1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//*********************************************************************
3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//* Base64 - a simple base64 encoder and decoder.
4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//*
5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//*     Copyright (c) 1999, Bob Withers - bwit@pobox.com
6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//*
7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//* This code may be freely used for any purpose, either personal
8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//* or commercial, provided the authors copyright notice remains
9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//* intact.
10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//*
11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//* Enhancements by Stanley Yamane:
12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//*     o reverse lookup table for the decode function
13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//*     o reserve string buffer space in advance
14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//*
15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//*********************************************************************
16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/base64.h"
18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/common.h"
19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochusing std::string;
21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochusing std::vector;
22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace talk_base {
24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const char kPad = '=';
26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const unsigned char pd = 0xFD;  // Padding
27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const unsigned char sp = 0xFE;  // Whitespace
28f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const unsigned char il = 0xFF;  // Illegal base64 character
29f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst string Base64::Base64Table(
31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// 0000000000111111111122222222223333333333444444444455555555556666
32f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// 0123456789012345678901234567890123456789012345678901234567890123
33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Decode Table gives the index of any valid base64 character in the
36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Base64 table
37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// 65 == A, 97 == a, 48 == 0, 43 == +, 47 == /
38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst unsigned char Base64::DecodeTable[] = {
40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// 0  1  2  3  4  5  6  7  8  9
41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,sp,  //   0 -   9
42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  sp,sp,sp,sp,il,il,il,il,il,il,  //  10 -  19
43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  //  20 -  29
44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,sp,il,il,il,il,il,il,il,  //  30 -  39
45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,62,il,il,il,63,52,53,  //  40 -  49
46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  54,55,56,57,58,59,60,61,il,il,  //  50 -  59
47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,pd,il,il,il, 0, 1, 2, 3, 4,  //  60 -  69
48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch   5, 6, 7, 8, 9,10,11,12,13,14,  //  70 -  79
49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  15,16,17,18,19,20,21,22,23,24,  //  80 -  89
50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  25,il,il,il,il,il,il,26,27,28,  //  90 -  99
51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  29,30,31,32,33,34,35,36,37,38,  // 100 - 109
52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  39,40,41,42,43,44,45,46,47,48,  // 110 - 119
53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  49,50,51,il,il,il,il,il,il,il,  // 120 - 129
54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 130 - 139
55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 140 - 149
56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 150 - 159
57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 160 - 169
58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 170 - 179
59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 180 - 189
60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 190 - 199
61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 200 - 209
62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 210 - 219
63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 220 - 229
64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 230 - 239
65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il,il,il,il,il,  // 240 - 249
66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  il,il,il,il,il,il               // 250 - 255
67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Base64::IsBase64Char(char ch) {
70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return (('A' <= ch) && (ch <= 'Z')) ||
71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch         (('a' <= ch) && (ch <= 'z')) ||
72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch         (('0' <= ch) && (ch <= '9')) ||
73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch         (ch == '+') || (ch == '/');
74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Base64::IsBase64Encoded(const std::string& str) {
77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i = 0; i < str.size(); ++i) {
78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!IsBase64Char(str.at(i)))
79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return false;
80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid Base64::EncodeFromArray(const void* data, size_t len, string* result) {
85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(NULL != result);
86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  result->clear();
87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  result->reserve(((len + 2) / 3) * 4);
88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const unsigned char* byte_data = static_cast<const unsigned char*>(data);
89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  unsigned char c;
91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t i = 0;
92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  while (i < len) {
93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    c = (byte_data[i] >> 2) & 0x3f;
94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    result->push_back(Base64Table[c]);
95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    c = (byte_data[i] << 4) & 0x3f;
97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (++i < len) {
98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      c |= (byte_data[i] >> 4) & 0x0f;
99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    result->push_back(Base64Table[c]);
101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (i < len) {
103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      c = (byte_data[i] << 2) & 0x3f;
104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (++i < len) {
105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        c |= (byte_data[i] >> 6) & 0x03;
106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      result->push_back(Base64Table[c]);
108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else {
109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      result->push_back(kPad);
110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (i < len) {
113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      c = byte_data[i] & 0x3f;
114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      result->push_back(Base64Table[c]);
115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ++i;
116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else {
117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      result->push_back(kPad);
118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochsize_t Base64::GetNextQuantum(DecodeFlags parse_flags, bool illegal_pads,
123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                              const char* data, size_t len, size_t* dpos,
124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                              unsigned char qbuf[4], bool* padded)
125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch{
126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t byte_len = 0, pad_len = 0, pad_start = 0;
127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (; (byte_len < 4) && (*dpos < len); ++*dpos) {
128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    qbuf[byte_len] = DecodeTable[static_cast<unsigned char>(data[*dpos])];
129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if ((il == qbuf[byte_len]) || (illegal_pads && (pd == qbuf[byte_len]))) {
130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (parse_flags != DO_PARSE_ANY)
131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        break;
132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      // Ignore illegal characters
133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else if (sp == qbuf[byte_len]) {
134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (parse_flags == DO_PARSE_STRICT)
135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        break;
136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      // Ignore spaces
137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else if (pd == qbuf[byte_len]) {
138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (byte_len < 2) {
139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (parse_flags != DO_PARSE_ANY)
140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          break;
141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // Ignore unexpected padding
142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      } else if (byte_len + pad_len >= 4) {
143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (parse_flags != DO_PARSE_ANY)
144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          break;
145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // Ignore extra pads
146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      } else {
147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (1 == ++pad_len) {
148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          pad_start = *dpos;
149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else {
152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (pad_len > 0) {
153f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (parse_flags != DO_PARSE_ANY)
154f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          break;
155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // Ignore pads which are followed by data
156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pad_len = 0;
157f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
158f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ++byte_len;
159f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i = byte_len; i < 4; ++i) {
162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    qbuf[i] = 0;
163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (4 == byte_len + pad_len) {
165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    *padded = true;
166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    *padded = false;
168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (pad_len) {
169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      // Roll back illegal padding
170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      *dpos = pad_start;
171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return byte_len;
174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Base64::DecodeFromArray(const char* data, size_t len, DecodeFlags flags,
177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                             string* result, size_t* data_used) {
178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return DecodeFromArrayTemplate<string>(data, len, flags, result, data_used);
179f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Base64::DecodeFromArray(const char* data, size_t len, DecodeFlags flags,
182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                             vector<char>* result, size_t* data_used) {
183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return DecodeFromArrayTemplate<vector<char> >(data, len, flags, result,
184f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                                data_used);
185f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
186f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
187f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochtemplate<typename T>
188f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Base64::DecodeFromArrayTemplate(const char* data, size_t len,
189f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                     DecodeFlags flags, T* result,
190f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                     size_t* data_used)
191f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch{
192f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(NULL != result);
193f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(flags <= (DO_PARSE_MASK | DO_PAD_MASK | DO_TERM_MASK));
194f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
195f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const DecodeFlags parse_flags = flags & DO_PARSE_MASK;
196f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const DecodeFlags pad_flags   = flags & DO_PAD_MASK;
197f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const DecodeFlags term_flags  = flags & DO_TERM_MASK;
198f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(0 != parse_flags);
199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(0 != pad_flags);
200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(0 != term_flags);
201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  result->clear();
203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  result->reserve(len);
204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t dpos = 0;
206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool success = true, padded;
207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  unsigned char c, qbuf[4];
208f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  while (dpos < len) {
209f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    size_t qlen = GetNextQuantum(parse_flags, (DO_PAD_NO == pad_flags),
210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                 data, len, &dpos, qbuf, &padded);
211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    c = (qbuf[0] << 2) | ((qbuf[1] >> 4) & 0x3);
212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (qlen >= 2) {
213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      result->push_back(c);
214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      c = ((qbuf[1] << 4) & 0xf0) | ((qbuf[2] >> 2) & 0xf);
215f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (qlen >= 3) {
216f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        result->push_back(c);
217f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        c = ((qbuf[2] << 6) & 0xc0) | qbuf[3];
218f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (qlen >= 4) {
219f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          result->push_back(c);
220f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          c = 0;
221f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
222f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
223f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
224f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (qlen < 4) {
225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if ((DO_TERM_ANY != term_flags) && (0 != c)) {
226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        success = false;  // unused bits
227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
228f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if ((DO_PAD_YES == pad_flags) && !padded) {
229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        success = false;  // expected padding
230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      break;
232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((DO_TERM_BUFFER == term_flags) && (dpos != len)) {
235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    success = false;  // unused chars
236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (data_used) {
238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    *data_used = dpos;
239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return success;
241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} // namespace talk_base
244