VCS_File.bas 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. Option Compare Database
  2. Option Private Module
  3. Option Explicit
  4. #If VBA7 Then
  5. Private Declare PtrSafe _
  6. Function getTempPath Lib "kernel32" _
  7. Alias "GetTempPathA" (ByVal nBufferLength As Long, _
  8. ByVal lpBuffer As String) As Long
  9. Private Declare PtrSafe _
  10. Function getTempFileName Lib "kernel32" _
  11. Alias "GetTempFileNameA" (ByVal lpszPath As String, _
  12. ByVal lpPrefixString As String, _
  13. ByVal wUnique As Long, _
  14. ByVal lpTempFileName As String) As Long
  15. #Else
  16. Private Declare _
  17. Function getTempPath Lib "kernel32" _
  18. Alias "GetTempPathA" (ByVal nBufferLength As Long, _
  19. ByVal lpBuffer As String) As Long
  20. Private Declare _
  21. Function getTempFileName Lib "kernel32" _
  22. Alias "GetTempFileNameA" (ByVal lpszPath As String, _
  23. ByVal lpPrefixString As String, _
  24. ByVal wUnique As Long, _
  25. ByVal lpTempFileName As String) As Long
  26. #End If
  27. ' --------------------------------
  28. ' Structures
  29. ' --------------------------------
  30. ' Structure to track buffered reading or writing of binary files
  31. Private Type BinFile
  32. file_num As Integer
  33. file_len As Long
  34. file_pos As Long
  35. buffer As String
  36. buffer_len As Integer
  37. buffer_pos As Integer
  38. at_eof As Boolean
  39. mode As String
  40. End Type
  41. ' --------------------------------
  42. ' Basic functions missing from VB 6: buffered file read/write, string builder, encoding check & conversion
  43. ' --------------------------------
  44. ' Open a binary file for reading (mode = 'r') or writing (mode = 'w').
  45. Private Function BinOpen(ByVal file_path As String, ByVal mode As String) As BinFile
  46. Dim f As BinFile
  47. f.file_num = FreeFile
  48. f.mode = LCase$(mode)
  49. If f.mode = "r" Then
  50. Open file_path For Binary Access Read As f.file_num
  51. f.file_len = LOF(f.file_num)
  52. f.file_pos = 0
  53. If f.file_len > &H4000 Then
  54. f.buffer = String$(&H4000, " ")
  55. f.buffer_len = &H4000
  56. Else
  57. f.buffer = String$(f.file_len, " ")
  58. f.buffer_len = f.file_len
  59. End If
  60. f.buffer_pos = 0
  61. Get f.file_num, f.file_pos + 1, f.buffer
  62. Else
  63. DelIfExist file_path
  64. Open file_path For Binary Access Write As f.file_num
  65. f.file_len = 0
  66. f.file_pos = 0
  67. f.buffer = String$(&H4000, " ")
  68. f.buffer_len = 0
  69. f.buffer_pos = 0
  70. End If
  71. BinOpen = f
  72. End Function
  73. ' Buffered read one byte at a time from a binary file.
  74. Private Function BinRead(ByRef f As BinFile) As Integer
  75. If f.at_eof = True Then
  76. BinRead = 0
  77. Exit Function
  78. End If
  79. BinRead = Asc(Mid$(f.buffer, f.buffer_pos + 1, 1))
  80. f.buffer_pos = f.buffer_pos + 1
  81. If f.buffer_pos >= f.buffer_len Then
  82. f.file_pos = f.file_pos + &H4000
  83. If f.file_pos >= f.file_len Then
  84. f.at_eof = True
  85. Exit Function
  86. End If
  87. If f.file_len - f.file_pos > &H4000 Then
  88. f.buffer_len = &H4000
  89. Else
  90. f.buffer_len = f.file_len - f.file_pos
  91. f.buffer = String$(f.buffer_len, " ")
  92. End If
  93. f.buffer_pos = 0
  94. Get f.file_num, f.file_pos + 1, f.buffer
  95. End If
  96. End Function
  97. ' Buffered write one byte at a time from a binary file.
  98. Private Sub BinWrite(ByRef f As BinFile, B As Integer)
  99. Mid(f.buffer, f.buffer_pos + 1, 1) = Chr$(B)
  100. f.buffer_pos = f.buffer_pos + 1
  101. If f.buffer_pos >= &H4000 Then
  102. Put f.file_num, , f.buffer
  103. f.buffer_pos = 0
  104. End If
  105. End Sub
  106. ' Close binary file.
  107. Private Sub BinClose(ByRef f As BinFile)
  108. If f.mode = "w" And f.buffer_pos > 0 Then
  109. f.buffer = Left$(f.buffer, f.buffer_pos)
  110. Put f.file_num, , f.buffer
  111. End If
  112. Close f.file_num
  113. End Sub
  114. ' Binary convert a UCS2-little-endian encoded file to UTF-8.
  115. Public Sub ConvertUcs2Utf8(ByVal Source As String, ByVal dest As String)
  116. Dim f_in As BinFile
  117. Dim f_out As BinFile
  118. Dim in_low As Integer
  119. Dim in_high As Integer
  120. f_in = BinOpen(Source, "r")
  121. f_out = BinOpen(dest, "w")
  122. Do While Not f_in.at_eof
  123. in_low = BinRead(f_in)
  124. in_high = BinRead(f_in)
  125. If in_high = 0 And in_low < &H80 Then
  126. ' U+0000 - U+007F 0LLLLLLL
  127. BinWrite f_out, in_low
  128. ElseIf in_high < &H8 Then
  129. ' U+0080 - U+07FF 110HHHLL 10LLLLLL
  130. BinWrite f_out, &HC0 + ((in_high And &H7) * &H4) + ((in_low And &HC0) / &H40)
  131. BinWrite f_out, &H80 + (in_low And &H3F)
  132. Else
  133. ' U+0800 - U+FFFF 1110HHHH 10HHHHLL 10LLLLLL
  134. BinWrite f_out, &HE0 + ((in_high And &HF0) / &H10)
  135. BinWrite f_out, &H80 + ((in_high And &HF) * &H4) + ((in_low And &HC0) / &H40)
  136. BinWrite f_out, &H80 + (in_low And &H3F)
  137. End If
  138. Loop
  139. BinClose f_in
  140. BinClose f_out
  141. End Sub
  142. ' Binary convert a UTF-8 encoded file to UCS2-little-endian.
  143. Public Sub ConvertUtf8Ucs2(ByVal Source As String, ByVal dest As String)
  144. Dim f_in As BinFile
  145. Dim f_out As BinFile
  146. Dim in_1 As Integer
  147. Dim in_2 As Integer
  148. Dim in_3 As Integer
  149. logger "ConvertUtf8Ucs2", "DEBUG", "Convert Utf8 file " & Source & " to UCS File " & dest
  150. f_in = BinOpen(Source, "r")
  151. f_out = BinOpen(dest, "w")
  152. Do While Not f_in.at_eof
  153. in_1 = BinRead(f_in)
  154. If (in_1 And &H80) = 0 Then
  155. ' U+0000 - U+007F 0LLLLLLL
  156. BinWrite f_out, in_1
  157. BinWrite f_out, 0
  158. ElseIf (in_1 And &HE0) = &HC0 Then
  159. ' U+0080 - U+07FF 110HHHLL 10LLLLLL
  160. in_2 = BinRead(f_in)
  161. BinWrite f_out, ((in_1 And &H3) * &H40) + (in_2 And &H3F)
  162. BinWrite f_out, (in_1 And &H1C) / &H4
  163. Else
  164. ' U+0800 - U+FFFF 1110HHHH 10HHHHLL 10LLLLLL
  165. in_2 = BinRead(f_in)
  166. in_3 = BinRead(f_in)
  167. BinWrite f_out, ((in_2 And &H3) * &H40) + (in_3 And &H3F)
  168. BinWrite f_out, ((in_1 And &HF) * &H10) + ((in_2 And &H3C) / &H4)
  169. End If
  170. Loop
  171. BinClose f_in
  172. BinClose f_out
  173. End Sub
  174. ' Determine if this database imports/exports code as UCS-2-LE. (Older file
  175. ' formats cause exported objects to use a Windows 8-bit character set.)
  176. Public Function UsingUcs2() As Boolean
  177. Dim obj_name As String
  178. Dim obj_type As Variant
  179. Dim fn As Integer
  180. Dim bytes As String
  181. Dim obj_type_split() As String
  182. Dim obj_type_name As String
  183. Dim obj_type_num As Integer
  184. If CurrentDb.QueryDefs.count > 0 Then
  185. obj_type_num = acQuery
  186. obj_name = CurrentDb.QueryDefs(0).name
  187. Else
  188. For Each obj_type In Split( _
  189. "Forms|" & acForm & "," & _
  190. "Reports|" & acReport & "," & _
  191. "Scripts|" & acMacro & "," & _
  192. "Modules|" & acModule _
  193. )
  194. DoEvents
  195. obj_type_split = Split(obj_type, "|")
  196. obj_type_name = obj_type_split(0)
  197. obj_type_num = val(obj_type_split(1))
  198. If CurrentDb.Containers(obj_type_name).Documents.count > 0 Then
  199. obj_name = CurrentDb.Containers(obj_type_name).Documents(0).name
  200. Exit For
  201. End If
  202. Next
  203. End If
  204. If obj_name = vbNullString Then
  205. ' No objects found that can be used to test UCS2 versus UTF-8
  206. UsingUcs2 = True
  207. Exit Function
  208. End If
  209. Dim tempFileName As String
  210. tempFileName = VCS_File.TempFile()
  211. Application.SaveAsText obj_type_num, obj_name, tempFileName
  212. fn = FreeFile
  213. Open tempFileName For Binary Access Read As fn
  214. bytes = " "
  215. Get fn, 1, bytes
  216. If Asc(Mid$(bytes, 1, 1)) = &HFF And Asc(Mid$(bytes, 2, 1)) = &HFE Then
  217. UsingUcs2 = True
  218. Else
  219. UsingUcs2 = False
  220. End If
  221. Close fn
  222. On Error Resume Next
  223. Kill tempFileName
  224. End Function
  225. Public Function ReadFile(filepath As String, Optional encoding As String = "utf-8") As String
  226. Dim objStream As ADODB.Stream
  227. Set objStream = New ADODB.Stream
  228. objStream.Charset = encoding
  229. objStream.Open
  230. objStream.LoadFromFile (filepath)
  231. ReadFile = objStream.ReadText()
  232. objStream.Close
  233. Set objStream = Nothing
  234. End Function
  235. Public Sub MakeFile(filepath As String, content As String, Optional encoding As String = "utf-8")
  236. Dim objStream As ADODB.Stream
  237. Set objStream = CreateObject("ADODB.Stream")
  238. objStream.Open
  239. objStream.Type = 2 'Text
  240. objStream.Charset = encoding
  241. objStream.WriteText content
  242. objStream.SaveToFile (filepath)
  243. objStream.Close
  244. End Sub
  245. ' Generate Random / Unique tempprary file name.
  246. Public Function TempFile(Optional ByVal sPrefix As String = "oa") As String
  247. Dim sTmpPath As String * 512
  248. Dim sTmpName As String * 576
  249. Dim nRet As Long
  250. Dim sFileName As String
  251. nRet = getTempPath(512, sTmpPath)
  252. nRet = getTempFileName(sTmpPath, sPrefix, 0, sTmpName)
  253. If nRet <> 0 Then sFileName = Left$(sTmpName, InStr(sTmpName, vbNullChar) - 1)
  254. TempFile = sFileName
  255. End Function
  256. Public Function IsValidFileName(ByVal sName As String) As Boolean
  257. IsValidFileName = (InStr(sName, "\") = 0 And InStr(sName, "/") = 0 And InStr(sName, "*") = 0 And InStr(sName, "?") = 0 And InStr(sName, Chr(34)) = 0 And InStr(sName, "|") = 0 And InStr(sName, ":") = 0 And InStr(sName, ">") = 0 And InStr(sName, "<") = 0)
  258. End Function