1//
2// Base64Decoder.cpp
3//
4// Library: Foundation
5// Package: Streams
6// Module: Base64
7//
8// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Base64Decoder.h"
16#include "Poco/Base64Encoder.h"
17#include "Poco/Exception.h"
18#include "Poco/Mutex.h"
19
20
21namespace Poco {
22
23
24unsigned char Base64DecoderBuf::IN_ENCODING[256];
25bool Base64DecoderBuf::IN_ENCODING_INIT = false;
26unsigned char Base64DecoderBuf::IN_ENCODING_URL[256];
27bool Base64DecoderBuf::IN_ENCODING_URL_INIT = false;
28
29
30namespace
31{
32 static FastMutex mutex;
33}
34
35
36Base64DecoderBuf::Base64DecoderBuf(std::istream& istr, int options):
37 _options(options),
38 _groupLength(0),
39 _groupIndex(0),
40 _buf(*istr.rdbuf()),
41 _pInEncoding((options & BASE64_URL_ENCODING) ? IN_ENCODING_URL : IN_ENCODING)
42{
43 FastMutex::ScopedLock lock(mutex);
44 if (options & BASE64_URL_ENCODING)
45 {
46 if (!IN_ENCODING_URL_INIT)
47 {
48 for (unsigned i = 0; i < sizeof(IN_ENCODING_URL); i++)
49 {
50 IN_ENCODING_URL[i] = 0xFF;
51 }
52 for (unsigned i = 0; i < sizeof(Base64EncoderBuf::OUT_ENCODING_URL); i++)
53 {
54 IN_ENCODING_URL[Base64EncoderBuf::OUT_ENCODING_URL[i]] = i;
55 }
56 IN_ENCODING_URL[static_cast<unsigned char>('=')] = '\0';
57 IN_ENCODING_URL_INIT = true;
58 }
59 }
60 else
61 {
62 if (!IN_ENCODING_INIT)
63 {
64 for (unsigned i = 0; i < sizeof(IN_ENCODING); i++)
65 {
66 IN_ENCODING[i] = 0xFF;
67 }
68 for (unsigned i = 0; i < sizeof(Base64EncoderBuf::OUT_ENCODING); i++)
69 {
70 IN_ENCODING[Base64EncoderBuf::OUT_ENCODING[i]] = i;
71 }
72 IN_ENCODING[static_cast<unsigned char>('=')] = '\0';
73 IN_ENCODING_INIT = true;
74 }
75 }
76}
77
78
79Base64DecoderBuf::~Base64DecoderBuf()
80{
81}
82
83
84int Base64DecoderBuf::readFromDevice()
85{
86 if (_groupIndex < _groupLength)
87 {
88 return _group[_groupIndex++];
89 }
90 else
91 {
92 unsigned char buffer[4];
93 int c;
94 if ((c = readOne()) == -1) return -1;
95 buffer[0] = (unsigned char) c;
96 if (_pInEncoding[buffer[0]] == 0xFF) throw DataFormatException();
97 if ((c = readOne()) == -1) return -1;
98 buffer[1] = (unsigned char) c;
99 if (_pInEncoding[buffer[1]] == 0xFF) throw DataFormatException();
100 if (_options & BASE64_NO_PADDING)
101 {
102 if ((c = readOne()) != -1)
103 buffer[2] = c;
104 else
105 buffer[2] = '=';
106 if (_pInEncoding[buffer[2]] == 0xFF) throw DataFormatException();
107 if ((c = readOne()) != -1)
108 buffer[3] = c;
109 else
110 buffer[3] = '=';
111 if (_pInEncoding[buffer[3]] == 0xFF) throw DataFormatException();
112 }
113 else
114 {
115 if ((c = readOne()) == -1) throw DataFormatException();
116 buffer[2] = c;
117 if (_pInEncoding[buffer[2]] == 0xFF) throw DataFormatException();
118 if ((c = readOne()) == -1) throw DataFormatException();
119 buffer[3] = c;
120 if (_pInEncoding[buffer[3]] == 0xFF) throw DataFormatException();
121 }
122
123 _group[0] = (_pInEncoding[buffer[0]] << 2) | (_pInEncoding[buffer[1]] >> 4);
124 _group[1] = ((_pInEncoding[buffer[1]] & 0x0F) << 4) | (_pInEncoding[buffer[2]] >> 2);
125 _group[2] = (_pInEncoding[buffer[2]] << 6) | _pInEncoding[buffer[3]];
126
127 if (buffer[2] == '=')
128 _groupLength = 1;
129 else if (buffer[3] == '=')
130 _groupLength = 2;
131 else
132 _groupLength = 3;
133 _groupIndex = 1;
134 return _group[0];
135 }
136}
137
138
139int Base64DecoderBuf::readOne()
140{
141 int ch = _buf.sbumpc();
142 if (!(_options & BASE64_URL_ENCODING))
143 {
144 while (ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n')
145 ch = _buf.sbumpc();
146 }
147 return ch;
148}
149
150
151Base64DecoderIOS::Base64DecoderIOS(std::istream& istr, int options): _buf(istr, options)
152{
153 poco_ios_init(&_buf);
154}
155
156
157Base64DecoderIOS::~Base64DecoderIOS()
158{
159}
160
161
162Base64DecoderBuf* Base64DecoderIOS::rdbuf()
163{
164 return &_buf;
165}
166
167
168Base64Decoder::Base64Decoder(std::istream& istr, int options): Base64DecoderIOS(istr, options), std::istream(&_buf)
169{
170}
171
172
173Base64Decoder::~Base64Decoder()
174{
175}
176
177
178} // namespace Poco
179