base64.bmx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. ' Copyright (c) 2008-2021 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: Encode/Decode Base64 data.
  24. about:
  25. To Encode :
  26. <pre>
  27. SuperStrict
  28. Import BaH.Base64
  29. Local someData:String = "Woo! BlitzMax Modules rock!"
  30. Local encoded:String = TBase64.Encode(someData, someData.length)
  31. Print "Encoded : " + encoded
  32. </pre>
  33. To Decode :
  34. <pre>
  35. SuperStrict
  36. Import BaH.Base64
  37. Local encodedData:String = "V29vISBCbGl0ek1heCBNb2R1bGVzIHJvY2sh"
  38. Local data:Byte[] = TBase64.Decode(encodedData)
  39. Local decoded:String = String.FromBytes(data, data.length)
  40. Print "Decoded : " + decoded
  41. </pre>
  42. End Rem
  43. Type TBase64
  44. Const DONT_BREAK_LINES:Int = 8
  45. ' Maximum line length (76) of Base64 output.
  46. Const MAX_LINE_LENGTH:Int = 76
  47. ' The equals sign (=) as int.
  48. Const EQUALS_SIGN:Int = Asc("=")
  49. ' The new line character (\n) as int.
  50. Const NEW_LINE:Int = Asc("~n")
  51. Const WHITE_SPACE_ENC:Int = -5 ' Indicates white space in encoding
  52. Const EQUALS_SIGN_ENC:Int = -1 ' Indicates equals sign in encoding
  53. Const _STANDARD_ALPHABET:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  54. Global _STANDARD_DECODABET:Int[] = [-9,-9,-9,-9,-9,-9,-9,-9,-9, ..
  55. -5,-5, ..
  56. -9,-9, ..
  57. -5, ..
  58. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, ..
  59. -9,-9,-9,-9,-9, ..
  60. -5, ..
  61. -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, ..
  62. 62, ..
  63. -9,-9,-9, ..
  64. 63, ..
  65. 52,53,54,55,56,57,58,59,60,61, ..
  66. -9,-9,-9, ..
  67. -1, ..
  68. -9,-9,-9, ..
  69. 0,1,2,3,4,5,6,7,8,9,10,11,12,13, ..
  70. 14,15,16,17,18,19,20,21,22,23,24,25, ..
  71. -9,-9,-9,-9,-9,-9, ..
  72. 26,27,28,29,30,31,32,33,34,35,36,37,38, ..
  73. 39,40,41,42,43,44,45,46,47,48,49,50,51, ..
  74. -9,-9,-9,-9]
  75. Rem
  76. bbdoc: Encode byte data to a Base64 encoded String, starting at @offset of @length bytes.
  77. End Rem
  78. Function Encode:String( source:Byte Ptr, length:Int, offset:Int = 0, options:Int = 0)
  79. ' Isolate options
  80. Local dontBreakLines:Int = options & DONT_BREAK_LINES
  81. ' Convert option To boolean in way that code likes it.
  82. Local breakLines:Int = True
  83. If dontBreakLines Then
  84. breakLines = False
  85. End If
  86. Local len43:Int = length * 4 / 3
  87. Local nl:Int = len43 / MAX_LINE_LENGTH
  88. Local pad:Int = 0
  89. If length Mod 3 > 0 Then
  90. pad = 4
  91. End If
  92. If Not breakLines Then
  93. nl = 0
  94. End If
  95. Local outBuff:Byte[] = New Byte[ len43 + pad + nl ]
  96. Local d:Int = 0
  97. Local e:Int = 0
  98. Local len2:Int = length - 2
  99. Local lineLength:Int = 0
  100. While d < len2
  101. encode3to4( source, d + offset, 3, outBuff, e, options )
  102. lineLength :+ 4
  103. If breakLines And (lineLength = MAX_LINE_LENGTH) Then
  104. outBuff[e+4] = NEW_LINE
  105. e:+1
  106. lineLength = 0
  107. End If
  108. d:+3
  109. e:+4
  110. Wend
  111. ' pad?
  112. If d < Length Then
  113. encode3to4( source, d + offset, Length - d, outBuff, e, options )
  114. e :+ 4
  115. End If
  116. Return String.FromBytes(outBuff, e)
  117. End Function
  118. Rem
  119. bbdoc: Decode Base64 encoded String to an array of Bytes, starting at @offset.
  120. End Rem
  121. Function Decode:Byte[]( source:String, offset:Int = 0, options:Int = 0 )
  122. Local length:Int = source.length
  123. Local len34:Int = Length * 3 / 4
  124. Local outBuff:Byte[] = New Byte[ len34 ]
  125. Local outBuffPosn:Int = 0
  126. Local b4:Byte[] = New Byte[4]
  127. Local b4Posn:Int = 0
  128. Local sbiCrop:Int = 0
  129. Local sbiDecode:Int = 0
  130. For Local i:Int = offset Until offset + length
  131. sbiCrop = source[i] & $7f
  132. sbiDecode = _STANDARD_DECODABET[ sbiCrop ]
  133. If sbiDecode >= WHITE_SPACE_ENC Then
  134. If sbiDecode >= EQUALS_SIGN_ENC Then
  135. b4[ b4Posn ] = sbiCrop
  136. b4Posn:+1
  137. If b4Posn > 3 Then
  138. outBuffPosn :+ decode4to3( b4, 0, outBuff, outBuffPosn, options )
  139. b4Posn = 0
  140. ' If that was the equals sign, break out of 'for' loop
  141. If sbiCrop = EQUALS_SIGN Then
  142. Exit
  143. End If
  144. End If
  145. End If
  146. Else
  147. DebugLog "Bad Base64 input character at " + i + ": " + source[i]
  148. Return Null
  149. End If
  150. Next
  151. Return outBuff[0..outBuffPosn]
  152. End Function
  153. Function encode3to4:Byte[](source:Byte Ptr, srcOffset:Int, numSigBytes:Int, destination:Byte[], destOffset:Int, options:Int )
  154. Local inBuff:Int
  155. If numSigBytes > 0 Then
  156. inBuff = (source[ srcOffset ] & $FF) Shl 16
  157. If numSigBytes > 1 Then
  158. inBuff :| ((source[ srcOffset + 1 ] & $FF) Shl 8)
  159. If numSigBytes > 2 Then
  160. inBuff :| (source[ srcOffset + 2 ] & $FF)
  161. End If
  162. End If
  163. End If
  164. Select numSigBytes
  165. Case 3
  166. destination[ destOffset ] = _STANDARD_ALPHABET[ (inBuff Shr 18) ]
  167. destination[ destOffset + 1 ] = _STANDARD_ALPHABET[ (inBuff Shr 12) & $3f ]
  168. destination[ destOffset + 2 ] = _STANDARD_ALPHABET[ (inBuff Shr 6) & $3f ]
  169. destination[ destOffset + 3 ] = _STANDARD_ALPHABET[ (inBuff ) & $3f ]
  170. Return destination
  171. Case 2
  172. destination[ destOffset ] = _STANDARD_ALPHABET[ (inBuff Shr 18) ]
  173. destination[ destOffset + 1 ] = _STANDARD_ALPHABET[ (inBuff Shr 12) & $3f ]
  174. destination[ destOffset + 2 ] = _STANDARD_ALPHABET[ (inBuff Shr 6) & $3f ]
  175. destination[ destOffset + 3 ] = EQUALS_SIGN
  176. Return destination
  177. Case 1
  178. destination[ destOffset ] = _STANDARD_ALPHABET[ (inBuff Shr 18) ]
  179. destination[ destOffset + 1 ] = _STANDARD_ALPHABET[ (inBuff Shr 12) & $3f ]
  180. destination[ destOffset + 2 ] = EQUALS_SIGN
  181. destination[ destOffset + 3 ] = EQUALS_SIGN
  182. Return destination
  183. Default
  184. Return destination
  185. End Select
  186. End Function
  187. Function decode4to3:Int( source:Byte[] , srcOffset:Int, destination:Byte[] , destOffset:Int, options:Int )
  188. ' Example: Dk==
  189. If source[ srcOffset + 2] = EQUALS_SIGN Then
  190. Local outBuff:Int = ( ( _STANDARD_DECODABET[ source[ srcOffset ] ] & $FF ) Shl 18 ) ..
  191. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 1] ] & $FF ) Shl 12 )
  192. destination[ destOffset ] = outBuff Shr 16
  193. Return 1
  194. ' Example: DkL=
  195. Else If source[ srcOffset + 3 ] = EQUALS_SIGN Then
  196. Local outBuff:Int = ( ( _STANDARD_DECODABET[ source[ srcOffset ] ] & $FF ) Shl 18 ) ..
  197. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 1 ] ] & $FF ) Shl 12 ) ..
  198. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 2 ] ] & $FF ) Shl 6 )
  199. destination[ destOffset ] = outBuff Shr 16
  200. destination[ destOffset + 1 ] = outBuff Shr 8
  201. Return 2
  202. ' Example: DkLE
  203. Else
  204. Local outBuff:Int = ( ( _STANDARD_DECODABET[ source[ srcOffset ] ] & $FF ) Shl 18 ) ..
  205. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 1 ] ] & $FF ) Shl 12 ) ..
  206. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 2 ] ] & $FF ) Shl 6) ..
  207. | ( ( _STANDARD_DECODABET[ source[ srcOffset + 3 ] ] & $FF ) )
  208. destination[ destOffset ] = outBuff Shr 16
  209. destination[ destOffset + 1 ] = outBuff Shr 8
  210. destination[ destOffset + 2 ] = outBuff
  211. Return 3
  212. End If
  213. End Function
  214. End Type