base64.bmx 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. ' Copyright (c) 2008-2023 Bruce A Henderson
  2. '
  3. ' Permission is hereby granted, free of charge, to any person obtaining a copy
  4. ' of this software and associated documentation files (the "Software"), to deal
  5. ' in the Software without restriction, including without limitation the rights
  6. ' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. ' copies of the Software, and to permit persons to whom the Software is
  8. ' furnished to do so, subject to the following conditions:
  9. '
  10. ' The above copyright notice and this permission notice shall be included in
  11. ' all copies or substantial portions of the Software.
  12. '
  13. ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. ' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. ' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. ' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. ' THE SOFTWARE.
  20. '
  21. SuperStrict
  22. Rem
  23. bbdoc: Base64 Encoding
  24. End Rem
  25. Module BRL.Base64
  26. ModuleInfo "Version: 1.02"
  27. ModuleInfo "License: MIT"
  28. ModuleInfo "Copyright: Original - Robert Harder (http://iharder.sourceforge.net/current/java/base64/)"
  29. ModuleInfo "Copyright: BlitzMax port - 2008-2023 Bruce A Henderson"
  30. ModuleInfo "History: 1.02"
  31. ModuleInfo "History: Added Encode for Strings."
  32. ModuleInfo "History: Changed to not use Shl 24."
  33. ModuleInfo "History: 1.01"
  34. ModuleInfo "History: Fixed Encode() sometimes returning an extra null character."
  35. ModuleInfo "History: 1.00 Initial Release"
  36. Rem
  37. bbdoc: Encode/Decode Base64 data.
  38. about:
  39. End Rem
  40. Type TBase64
  41. ' Maximum line length (76) of Base64 output.
  42. Const MAX_LINE_LENGTH:Int = 76
  43. ' The equals sign (=) as int.
  44. Const EQUALS_SIGN:Int = Asc("=")
  45. ' The new line character (\n) as int.
  46. Const NEW_LINE:Int = Asc("~n")
  47. Const WHITE_SPACE_ENC:Int = -5 ' Indicates white space in encoding
  48. Const EQUALS_SIGN_ENC:Int = -1 ' Indicates equals sign in encoding
  49. Private
  50. Const _STANDARD_ALPHABET:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  51. Global _STANDARD_DECODABET:Int[] = [-9,-9,-9,-9,-9,-9,-9,-9,-9, ..
  52. -5,-5, ..
  53. -9,-9, ..
  54. -5, ..
  55. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, ..
  56. -9,-9,-9,-9,-9, ..
  57. -5, ..
  58. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, ..
  59. 62, ..
  60. -9,-9,-9, ..
  61. 63, ..
  62. 52,53,54,55,56,57,58,59,60,61, ..
  63. -9,-9,-9, ..
  64. -1, ..
  65. -9,-9,-9, ..
  66. 0,1,2,3,4,5,6,7,8,9,10,11,12,13, ..
  67. 14,15,16,17,18,19,20,21,22,23,24,25, ..
  68. -9,-9,-9,-9,-9,-9, ..
  69. 26,27,28,29,30,31,32,33,34,35,36,37,38, ..
  70. 39,40,41,42,43,44,45,46,47,48,49,50,51, ..
  71. -9,-9,-9,-9]
  72. Public
  73. Rem
  74. bbdoc: Encode byte data to a Base64 encoded String, starting at @offset of @length bytes.
  75. End Rem
  76. Function Encode:String( source:String, options:EBase64Options = EBase64Options.None)
  77. Local s:Byte Ptr = source.ToUTF8String()
  78. Local length:Int = strlen_(s)
  79. Local result:String = Encode(s, length, 0, options)
  80. MemFree(s)
  81. Return result
  82. End Function
  83. Rem
  84. bbdoc: Encodes byte array data @source to a Base64 encoded String, starting at @offset.
  85. End Rem
  86. Function Encode:String(source:Byte[], offset:Int = 0, options:EBase64Options = EBase64Options.None)
  87. Return Encode(source, source.length, offset, options)
  88. End Function
  89. Rem
  90. bbdoc: Encodes byte data @source to a Base64 encoded String, starting at @offset and of @length bytes.
  91. End Rem
  92. Function Encode:String(source:Byte Ptr, length:Int, offset:Int = 0, options:EBase64Options = EBase64Options.None)
  93. ' Convert option To boolean in way that code likes it.
  94. Local breakLines:Int = True
  95. If options & EBase64Options.DontBreakLines Then
  96. breakLines = False
  97. End If
  98. Local len43:Int = length * 4 / 3
  99. Local nl:Int = len43 / MAX_LINE_LENGTH
  100. Local pad:Int = 0
  101. If length Mod 3 > 0 Then
  102. pad = 4
  103. End If
  104. If Not breakLines Then
  105. nl = 0
  106. End If
  107. Local outBuff:Byte[] = New Byte[ len43 + pad + nl ]
  108. Local d:Int = 0
  109. Local e:Int = 0
  110. Local len2:Int = length - 2
  111. Local lineLength:Int = 0
  112. While d < len2
  113. encode3to4( source, d + offset, 3, outBuff, e )
  114. lineLength :+ 4
  115. If breakLines And (lineLength = MAX_LINE_LENGTH) Then
  116. outBuff[e+4] = NEW_LINE
  117. e:+1
  118. lineLength = 0
  119. End If
  120. d:+3
  121. e:+4
  122. Wend
  123. ' pad?
  124. If d < Length Then
  125. encode3to4( source, d + offset, Length - d, outBuff, e )
  126. e :+ 4
  127. End If
  128. Return String.FromBytes(outBuff, e)
  129. End Function
  130. Rem
  131. bbdoc: Decodes Base64 encoded String @source to an array of Bytes, starting at @offset.
  132. End Rem
  133. Function Decode:Byte[]( source:String, offset:Int = 0 )
  134. Local length:Int = source.length
  135. Local len34:Int = Length * 3 / 4
  136. Local outBuff:Byte[] = New Byte[ len34 ]
  137. Local outBuffPosn:Int = 0
  138. Local b4:Byte[] = New Byte[4]
  139. Local b4Posn:Int = 0
  140. Local sbiCrop:Int = 0
  141. Local sbiDecode:Int = 0
  142. For Local i:Int = offset Until offset + length
  143. sbiCrop = source[i] & $7f
  144. sbiDecode = _STANDARD_DECODABET[ sbiCrop ]
  145. If sbiDecode >= WHITE_SPACE_ENC Then
  146. If sbiDecode >= EQUALS_SIGN_ENC Then
  147. b4[ b4Posn ] = sbiCrop
  148. b4Posn:+1
  149. If b4Posn > 3 Then
  150. outBuffPosn :+ decode4to3( b4, 0, outBuff, outBuffPosn )
  151. b4Posn = 0
  152. ' If that was the equals sign, break out of 'for' loop
  153. If sbiCrop = EQUALS_SIGN Then
  154. Exit
  155. End If
  156. End If
  157. End If
  158. Else
  159. Throw "Bad Base64 input character at " + i + ": " + source[i]
  160. End If
  161. Next
  162. Return outBuff[0..outBuffPosn]
  163. End Function
  164. Private
  165. Function encode3to4(source:Byte Ptr, srcOffset:Int, numSigBytes:Int, destination:Byte Ptr, destOffset:Int)
  166. Local inBuff:Int
  167. If numSigBytes > 0 Then
  168. inBuff = (source[ srcOffset ] & $FF) Shl 16
  169. If numSigBytes > 1 Then
  170. inBuff :| ((source[ srcOffset + 1 ] & $FF) Shl 8)
  171. If numSigBytes > 2 Then
  172. inBuff :| (source[ srcOffset + 2 ] & $FF)
  173. End If
  174. End If
  175. End If
  176. Select numSigBytes
  177. Case 3
  178. destination[ destOffset ] = _STANDARD_ALPHABET[ (inBuff Shr 18) ]
  179. destination[ destOffset + 1 ] = _STANDARD_ALPHABET[ (inBuff Shr 12) & $3f ]
  180. destination[ destOffset + 2 ] = _STANDARD_ALPHABET[ (inBuff Shr 6) & $3f ]
  181. destination[ destOffset + 3 ] = _STANDARD_ALPHABET[ (inBuff ) & $3f ]
  182. Return
  183. Case 2
  184. destination[ destOffset ] = _STANDARD_ALPHABET[ (inBuff Shr 18) ]
  185. destination[ destOffset + 1 ] = _STANDARD_ALPHABET[ (inBuff Shr 12) & $3f ]
  186. destination[ destOffset + 2 ] = _STANDARD_ALPHABET[ (inBuff Shr 6) & $3f ]
  187. destination[ destOffset + 3 ] = EQUALS_SIGN
  188. Return
  189. Case 1
  190. destination[ destOffset ] = _STANDARD_ALPHABET[ (inBuff Shr 18) ]
  191. destination[ destOffset + 1 ] = _STANDARD_ALPHABET[ (inBuff Shr 12) & $3f ]
  192. destination[ destOffset + 2 ] = EQUALS_SIGN
  193. destination[ destOffset + 3 ] = EQUALS_SIGN
  194. Return
  195. End Select
  196. End Function
  197. Function decode4to3:Int( source:Byte Ptr, srcOffset:Int, destination:Byte Ptr , destOffset:Int)
  198. ' Example: Dk==
  199. If source[ srcOffset + 2] = EQUALS_SIGN Then
  200. Local outBuff:Int = ( ( _STANDARD_DECODABET[ source[ srcOffset ] ] & $FF ) Shl 18 ) ..
  201. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 1] ] & $FF ) Shl 12 )
  202. destination[ destOffset ] = outBuff Shr 16
  203. Return 1
  204. ' Example: DkL=
  205. Else If source[ srcOffset + 3 ] = EQUALS_SIGN Then
  206. Local outBuff:Int = ( ( _STANDARD_DECODABET[ source[ srcOffset ] ] & $FF ) Shl 18 ) ..
  207. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 1 ] ] & $FF ) Shl 12 ) ..
  208. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 2 ] ] & $FF ) Shl 6 )
  209. destination[ destOffset ] = outBuff Shr 16
  210. destination[ destOffset + 1 ] = outBuff Shr 8
  211. Return 2
  212. ' Example: DkLE
  213. Else
  214. Local outBuff:Int = ( ( _STANDARD_DECODABET[ source[ srcOffset ] ] & $FF ) Shl 18 ) ..
  215. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 1 ] ] & $FF ) Shl 12 ) ..
  216. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 2 ] ] & $FF ) Shl 6) ..
  217. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 3 ] ] & $FF ) )
  218. destination[ destOffset ] = outBuff Shr 16
  219. destination[ destOffset + 1 ] = outBuff Shr 8
  220. destination[ destOffset + 2 ] = outBuff
  221. Return 3
  222. End If
  223. End Function
  224. Public
  225. End Type
  226. Rem
  227. bbdoc: TBase64 options.
  228. End Rem
  229. Enum EBase64Options Flags
  230. None = 0
  231. Rem
  232. bbdoc: Encode to a single line, regardless of length.
  233. about: Otherwise, lines are typically wrapped at 76 characters.
  234. End Rem
  235. DontBreakLines = 8
  236. End Enum
  237. Private
  238. Extern
  239. Function strlen_:Size_T( str:Byte Ptr )="size_t strlen( const char *) !"
  240. End Extern