blob: e218dd7a43f96e153761f56bdf94aed46f554170 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
reed@android.com8a1c16f2008-12-17 15:59:43 +00008
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "include/utils/SkBase64.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010
11#define DecodePad -2
12#define EncodePad 64
13
rmistry@google.comd6176b02012-08-23 18:14:13 +000014static const char default_encode[] =
reed@android.com8a1c16f2008-12-17 15:59:43 +000015 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
16 "abcdefghijklmnopqrstuvwxyz"
17 "0123456789+/=";
18
19static const signed char decodeData[] = {
20 62, -1, -1, -1, 63,
21 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, DecodePad, -1, -1,
22 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
23 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
24 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
25 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
26};
27
bungemand7dc76f2016-03-10 11:14:40 -080028#if defined _WIN32 // disable 'two', etc. may be used without having been initialized
reed@android.com8a1c16f2008-12-17 15:59:43 +000029#pragma warning ( push )
30#pragma warning ( disable : 4701 )
31#endif
32
Ben Wagnerb06ebee2021-01-07 12:16:22 -050033SkBase64::Error SkBase64::Decode(const void* srcv, size_t srcLength, void* dstv, size_t* dstLength){
34 const unsigned char* src = static_cast<const unsigned char*>(srcv);
35 unsigned char* dst = static_cast<unsigned char*>(dstv);
Mike Kleinc0c05222020-01-31 11:07:51 -060036
Ben Wagnerb06ebee2021-01-07 12:16:22 -050037 int i = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 bool padTwo = false;
39 bool padThree = false;
Ben Wagnerb06ebee2021-01-07 12:16:22 -050040 char unsigned const * const end = src + srcLength;
reed@android.com8a1c16f2008-12-17 15:59:43 +000041 while (src < end) {
42 unsigned char bytes[4];
43 int byte = 0;
44 do {
45 unsigned char srcByte = *src++;
46 if (srcByte == 0)
47 goto goHome;
48 if (srcByte <= ' ')
49 continue; // treat as white space
50 if (srcByte < '+' || srcByte > 'z')
51 return kBadCharError;
52 signed char decoded = decodeData[srcByte - '+'];
53 bytes[byte] = decoded;
54 if (decoded < 0) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000055 if (decoded == DecodePad)
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 goto handlePad;
57 return kBadCharError;
58 } else
59 byte++;
60 if (*src)
61 continue;
62 if (byte == 0)
63 goto goHome;
64 if (byte == 4)
65 break;
66handlePad:
67 if (byte < 2)
68 return kPadError;
69 padThree = true;
70 if (byte == 2)
71 padTwo = true;
72 break;
73 } while (byte < 4);
tomhudson@google.coma7ed3cc2011-07-29 13:20:06 +000074 int two = 0;
75 int three = 0;
Ben Wagnerb06ebee2021-01-07 12:16:22 -050076 if (dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000077 int one = (uint8_t) (bytes[0] << 2);
78 two = bytes[1];
79 one |= two >> 4;
Brian Osman50ea3c02019-02-04 10:01:53 -050080 two = (uint8_t) ((two << 4) & 0xFF);
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 three = bytes[2];
82 two |= three >> 2;
Brian Osman50ea3c02019-02-04 10:01:53 -050083 three = (uint8_t) ((three << 6) & 0xFF);
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 three |= bytes[3];
85 SkASSERT(one < 256 && two < 256 && three < 256);
Mike Kleinc0c05222020-01-31 11:07:51 -060086 dst[i] = (unsigned char) one;
reed@android.com8a1c16f2008-12-17 15:59:43 +000087 }
Mike Kleinc0c05222020-01-31 11:07:51 -060088 i++;
rmistry@google.comd6176b02012-08-23 18:14:13 +000089 if (padTwo)
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 break;
Ben Wagnerb06ebee2021-01-07 12:16:22 -050091 if (dst)
Mike Kleinc0c05222020-01-31 11:07:51 -060092 dst[i] = (unsigned char) two;
93 i++;
reed@android.com8a1c16f2008-12-17 15:59:43 +000094 if (padThree)
95 break;
Ben Wagnerb06ebee2021-01-07 12:16:22 -050096 if (dst)
Mike Kleinc0c05222020-01-31 11:07:51 -060097 dst[i] = (unsigned char) three;
98 i++;
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 }
100goHome:
Ben Wagnerb06ebee2021-01-07 12:16:22 -0500101 *dstLength = i;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102 return kNoError;
103}
104
bungemand7dc76f2016-03-10 11:14:40 -0800105#if defined _WIN32
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106#pragma warning ( pop )
107#endif
108
Ben Wagnerb06ebee2021-01-07 12:16:22 -0500109size_t SkBase64::Encode(const void* srcv, size_t length, void* dstv, const char* encodeMap) {
110 const unsigned char* src = static_cast<const unsigned char*>(srcv);
111 unsigned char* dst = static_cast<unsigned char*>(dstv);
112
bungeman@google.comaf5bbf22012-02-07 20:47:38 +0000113 const char* encode;
halcanary96fcdcc2015-08-27 07:41:13 -0700114 if (nullptr == encodeMap) {
bungeman@google.comaf5bbf22012-02-07 20:47:38 +0000115 encode = default_encode;
116 } else {
117 encode = encodeMap;
118 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119 if (dst) {
120 size_t remainder = length % 3;
Ben Wagnerb06ebee2021-01-07 12:16:22 -0500121 char unsigned const * const end = &src[length - remainder];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 while (src < end) {
123 unsigned a = *src++;
124 unsigned b = *src++;
125 unsigned c = *src++;
126 int d = c & 0x3F;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000127 c = (c >> 6 | b << 2) & 0x3F;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 b = (b >> 4 | a << 4) & 0x3F;
129 a = a >> 2;
130 *dst++ = encode[a];
131 *dst++ = encode[b];
132 *dst++ = encode[c];
133 *dst++ = encode[d];
134 }
135 if (remainder > 0) {
136 int k1 = 0;
137 int k2 = EncodePad;
138 int a = (uint8_t) *src++;
139 if (remainder == 2)
140 {
141 int b = *src++;
142 k1 = b >> 4;
143 k2 = (b << 2) & 0x3F;
144 }
145 *dst++ = encode[a >> 2];
146 *dst++ = encode[(k1 | a << 4) & 0x3F];
147 *dst++ = encode[k2];
148 *dst++ = encode[EncodePad];
149 }
150 }
151 return (length + 2) / 3 * 4;
152}