Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1class Base64Error(Error): 

2 message: string 

3 

4func _index_to_encoded(index: u8) -> u8: 

5 if 0 <= index and index <= 25: 

6 return u8(i32('A') + i32(index) - 0) 

7 elif 26 <= index and index <= 51: 

8 return u8(i32('a') + i32(index) - 26) 

9 elif 52 <= index and index <= 61: 

10 return u8(i32('0') + i32(index) - 52) 

11 elif index == 62: 

12 return u8(i32('+')) 

13 elif index == 63: 

14 return u8(i32('/')) 

15 else: 

16 return u8(i32('=')) 

17 

18func _encoded_to_index(encoded: u8) -> u8: 

19 if u8(i32('A')) <= encoded and encoded <= u8(i32('Z')): 

20 return encoded - u8(i32('A')) 

21 elif u8(i32('a')) <= encoded and encoded <= u8(i32('z')): 

22 return 26 + encoded - u8(i32('a')) 

23 elif u8(i32('0')) <= encoded and encoded <= u8(i32('9')): 

24 return 52 + encoded - u8(i32('0')) 

25 elif encoded == u8(i32('+')): 

26 return 62 

27 elif encoded == u8(i32('/')): 

28 return 63 

29 elif encoded == u8(i32('=')): 

30 return 64 

31 else: 

32 raise Base64Error(f"Invalid value {encoded}.") 

33 

34func encode(data: bytes) -> string: 

35 """Encode given data. 

36 

37 """ 

38 

39 return string(encode_bytes(data)) 

40 

41func decode(data: string) -> bytes: 

42 """Decode given base64 encoded data. 

43 

44 """ 

45 

46 return decode_bytes(data.to_utf8()) 

47 

48func encode_bytes(data: bytes) -> bytes: 

49 """Encode given data. 

50 

51 """ 

52 

53 encoded = b"" 

54 length = data.length() 

55 encoded.reserve(4 * ((length + 2) / 3)) 

56 

57 for i in range(0, length, 3): 

58 index = (data[i + 0] & 0xfc) >> 2 

59 encoded += _index_to_encoded(index) 

60 index = ((data[i + 0] & 0x03) << 4) 

61 

62 if i + 1 < length: 

63 index |= (data[i + 1] & 0xf0) >> 4 

64 encoded += _index_to_encoded(index) 

65 index = (data[i + 1] & 0x0f) << 2 

66 

67 if i + 2 < length: 

68 index |= (data[i + 2] & 0xc0) >> 6 

69 encoded += _index_to_encoded(index) 

70 index = data[i + 2] & 0x3f 

71 encoded += _index_to_encoded(index) 

72 else: 

73 encoded += _index_to_encoded(index) 

74 encoded += _index_to_encoded(64) 

75 else: 

76 encoded += _index_to_encoded(index) 

77 encoded += _index_to_encoded(64) 

78 encoded += _index_to_encoded(64) 

79 

80 return encoded 

81 

82func decode_bytes(data: bytes) -> bytes: 

83 """Decode given base64 encoded data. 

84 

85 """ 

86 

87 length = data.length() 

88 

89 if (length % 4) != 0: 

90 raise Base64Error(f"Length {length} not multiple of 4.") 

91 

92 decoded = b"" 

93 decoded.reserve(3 * length / 4) 

94 

95 for i in range(0, length, 4): 

96 v0 = _encoded_to_index(data[i + 0]) 

97 v1 = _encoded_to_index(data[i + 1]) 

98 v2 = _encoded_to_index(data[i + 2]) 

99 v3 = _encoded_to_index(data[i + 3]) 

100 

101 if v0 == 64 or v1 == 64: 

102 raise Base64Error(f"Bad value 64 at first of second index.") 

103 elif v2 == 64: 

104 decoded += (v0 << 2) | (v1 >> 4) 

105 elif v3 == 64: 

106 decoded += (v0 << 2) | (v1 >> 4) 

107 decoded += (v1 << 4) | (v2 >> 2) 

108 else: 

109 decoded += (v0 << 2) | (v1 >> 4) 

110 decoded += (v1 << 4) | (v2 >> 2) 

111 decoded += (v2 << 6) | (v3 >> 0) 

112 

113 return decoded 

114 

115test various(): 

116 datas = [ 

117 ("", b""), 

118 ("Zg==", b"f"), 

119 ("Zm8=", b"fo"), 

120 ("Zm9v", b"foo"), 

121 ("Zm9vYg==", b"foob"), 

122 ("Zm9vYmE=", b"fooba"), 

123 ("Zm9vYmFy", b"foobar"), 

124 ( 

125 "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCB" 

126 "ieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaC" 

127 "BpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZ" 

128 "GVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRp" 

129 "b24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW5" 

130 "5IGNhcm5hbCBwbGVhc3VyZS4=", 

131 b"Man is distinguished, not only by his reason, but by this singular" 

132 b" passion from other animals, which is a lust of the mind, that by " 

133 b"a perseverance of delight in the continued and indefatigable gener" 

134 b"ation of knowledge, exceeds the short vehemence of any carnal plea" 

135 b"sure." 

136 ), 

137 ("TQ==", b"M"), 

138 ("TWE=", b"Ma"), 

139 ("TWFu", b"Man") 

140 ] 

141 

142 for encoded, decoded in datas: 

143 assert encode(decoded) == encoded 

144 assert decode(encoded) == decoded 

145 

146test various_bytes(): 

147 datas = [ 

148 (b"", b""), 

149 (b"Zg==", b"f"), 

150 (b"Zm8=", b"fo"), 

151 (b"Zm9v", b"foo"), 

152 (b"Zm9vYg==", b"foob"), 

153 (b"Zm9vYmE=", b"fooba"), 

154 (b"Zm9vYmFy", b"foobar"), 

155 ( 

156 b"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCB" 

157 b"ieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaC" 

158 b"BpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZ" 

159 b"GVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRp" 

160 b"b24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW5" 

161 b"5IGNhcm5hbCBwbGVhc3VyZS4=", 

162 b"Man is distinguished, not only by his reason, but by this singular" 

163 b" passion from other animals, which is a lust of the mind, that by " 

164 b"a perseverance of delight in the continued and indefatigable gener" 

165 b"ation of knowledge, exceeds the short vehemence of any carnal plea" 

166 b"sure." 

167 ), 

168 (b"TQ==", b"M"), 

169 (b"TWE=", b"Ma"), 

170 (b"TWFu", b"Man") 

171 ] 

172 

173 for encoded, decoded in datas: 

174 assert encode_bytes(decoded) == encoded 

175 assert decode_bytes(encoded) == decoded 

176 

177test decode_bad_length(): 

178 try: 

179 decode("1") 

180 assert False 

181 except Base64Error as error: 

182 assert error.message == "Length 1 not multiple of 4." 

183 

184test decode_bad_value(): 

185 try: 

186 decode_bytes(b"-234") 

187 assert False 

188 except Base64Error as error: 

189 assert error.message == "Invalid value 45." 

190 

191 try: 

192 decode_bytes(b"====") 

193 assert False 

194 except Base64Error as error: 

195 assert error.message == "Bad value 64 at first of second index."