1// basecode.cpp - written and placed in the public domain by Wei Dai
2
3#include "pch.h"
4
5#ifndef CRYPTOPP_IMPORTS
6
7#include "basecode.h"
8#include "fltrimpl.h"
9#include <ctype.h>
10
11NAMESPACE_BEGIN(CryptoPP)
12
13void BaseN_Encoder::IsolatedInitialize(const NameValuePairs &parameters)
14{
15	parameters.GetRequiredParameter("BaseN_Encoder", Name::EncodingLookupArray(), m_alphabet);
16
17	parameters.GetRequiredIntParameter("BaseN_Encoder", Name::Log2Base(), m_bitsPerChar);
18	if (m_bitsPerChar <= 0 || m_bitsPerChar >= 8)
19		throw InvalidArgument("BaseN_Encoder: Log2Base must be between 1 and 7 inclusive");
20
21	byte padding;
22	bool pad;
23	if (parameters.GetValue(Name::PaddingByte(), padding))
24		pad = parameters.GetValueWithDefault(Name::Pad(), true);
25	else
26		pad = false;
27	m_padding = pad ? padding : -1;
28
29	m_bytePos = m_bitPos = 0;
30
31	int i = 8;
32	while (i%m_bitsPerChar != 0)
33		i += 8;
34	m_outputBlockSize = i/m_bitsPerChar;
35
36	m_outBuf.New(m_outputBlockSize);
37}
38
39size_t BaseN_Encoder::Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
40{
41	FILTER_BEGIN;
42	while (m_inputPosition < length)
43	{
44		if (m_bytePos == 0)
45			memset(m_outBuf, 0, m_outputBlockSize);
46
47		{
48		unsigned int b = begin[m_inputPosition++], bitsLeftInSource = 8;
49		while (true)
50		{
51			assert(m_bitPos < m_bitsPerChar);
52			unsigned int bitsLeftInTarget = m_bitsPerChar-m_bitPos;
53			m_outBuf[m_bytePos] |= b >> (8-bitsLeftInTarget);
54			if (bitsLeftInSource >= bitsLeftInTarget)
55			{
56				m_bitPos = 0;
57				++m_bytePos;
58				bitsLeftInSource -= bitsLeftInTarget;
59				if (bitsLeftInSource == 0)
60					break;
61				b <<= bitsLeftInTarget;
62				b &= 0xff;
63			}
64			else
65			{
66				m_bitPos += bitsLeftInSource;
67				break;
68			}
69		}
70		}
71
72		assert(m_bytePos <= m_outputBlockSize);
73		if (m_bytePos == m_outputBlockSize)
74		{
75			int i;
76			for (i=0; i<m_bytePos; i++)
77			{
78				assert(m_outBuf[i] < (1 << m_bitsPerChar));
79				m_outBuf[i] = m_alphabet[m_outBuf[i]];
80			}
81			FILTER_OUTPUT(1, m_outBuf, m_outputBlockSize, 0);
82
83			m_bytePos = m_bitPos = 0;
84		}
85	}
86	if (messageEnd)
87	{
88		if (m_bitPos > 0)
89			++m_bytePos;
90
91		int i;
92		for (i=0; i<m_bytePos; i++)
93			m_outBuf[i] = m_alphabet[m_outBuf[i]];
94
95		if (m_padding != -1 && m_bytePos > 0)
96		{
97			memset(m_outBuf+m_bytePos, m_padding, m_outputBlockSize-m_bytePos);
98			m_bytePos = m_outputBlockSize;
99		}
100		FILTER_OUTPUT(2, m_outBuf, m_bytePos, messageEnd);
101		m_bytePos = m_bitPos = 0;
102	}
103	FILTER_END_NO_MESSAGE_END;
104}
105
106void BaseN_Decoder::IsolatedInitialize(const NameValuePairs &parameters)
107{
108	parameters.GetRequiredParameter("BaseN_Decoder", Name::DecodingLookupArray(), m_lookup);
109
110	parameters.GetRequiredIntParameter("BaseN_Decoder", Name::Log2Base(), m_bitsPerChar);
111	if (m_bitsPerChar <= 0 || m_bitsPerChar >= 8)
112		throw InvalidArgument("BaseN_Decoder: Log2Base must be between 1 and 7 inclusive");
113
114	m_bytePos = m_bitPos = 0;
115
116	int i = m_bitsPerChar;
117	while (i%8 != 0)
118		i += m_bitsPerChar;
119	m_outputBlockSize = i/8;
120
121	m_outBuf.New(m_outputBlockSize);
122}
123
124size_t BaseN_Decoder::Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
125{
126	FILTER_BEGIN;
127	while (m_inputPosition < length)
128	{
129		unsigned int value;
130		value = m_lookup[begin[m_inputPosition++]];
131		if (value >= 256)
132			continue;
133
134		if (m_bytePos == 0 && m_bitPos == 0)
135			memset(m_outBuf, 0, m_outputBlockSize);
136
137		{
138			int newBitPos = m_bitPos + m_bitsPerChar;
139			if (newBitPos <= 8)
140				m_outBuf[m_bytePos] |= value << (8-newBitPos);
141			else
142			{
143				m_outBuf[m_bytePos] |= value >> (newBitPos-8);
144				m_outBuf[m_bytePos+1] |= value << (16-newBitPos);
145			}
146
147			m_bitPos = newBitPos;
148			while (m_bitPos >= 8)
149			{
150				m_bitPos -= 8;
151				++m_bytePos;
152			}
153		}
154
155		if (m_bytePos == m_outputBlockSize)
156		{
157			FILTER_OUTPUT(1, m_outBuf, m_outputBlockSize, 0);
158			m_bytePos = m_bitPos = 0;
159		}
160	}
161	if (messageEnd)
162	{
163		FILTER_OUTPUT(2, m_outBuf, m_bytePos, messageEnd);
164		m_bytePos = m_bitPos = 0;
165	}
166	FILTER_END_NO_MESSAGE_END;
167}
168
169void BaseN_Decoder::InitializeDecodingLookupArray(int *lookup, const byte *alphabet, unsigned int base, bool caseInsensitive)
170{
171	std::fill(lookup, lookup+256, -1);
172
173	for (unsigned int i=0; i<base; i++)
174	{
175		if (caseInsensitive && isalpha(alphabet[i]))
176		{
177			assert(lookup[toupper(alphabet[i])] == -1);
178			lookup[toupper(alphabet[i])] = i;
179			assert(lookup[tolower(alphabet[i])] == -1);
180			lookup[tolower(alphabet[i])] = i;
181		}
182		else
183		{
184			assert(lookup[alphabet[i]] == -1);
185			lookup[alphabet[i]] = i;
186		}
187	}
188}
189
190void Grouper::IsolatedInitialize(const NameValuePairs &parameters)
191{
192	m_groupSize = parameters.GetIntValueWithDefault(Name::GroupSize(), 0);
193	ConstByteArrayParameter separator, terminator;
194	if (m_groupSize)
195		parameters.GetRequiredParameter("Grouper", Name::Separator(), separator);
196	else
197		parameters.GetValue(Name::Separator(), separator);
198	parameters.GetValue(Name::Terminator(), terminator);
199
200	m_separator.Assign(separator.begin(), separator.size());
201	m_terminator.Assign(terminator.begin(), terminator.size());
202	m_counter = 0;
203}
204
205size_t Grouper::Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
206{
207	FILTER_BEGIN;
208	if (m_groupSize)
209	{
210		while (m_inputPosition < length)
211		{
212			if (m_counter == m_groupSize)
213			{
214				FILTER_OUTPUT(1, m_separator, m_separator.size(), 0);
215				m_counter = 0;
216			}
217
218			size_t len;
219			FILTER_OUTPUT2(2, len = STDMIN(length-m_inputPosition, m_groupSize-m_counter),
220				begin+m_inputPosition, len, 0);
221			m_inputPosition += len;
222			m_counter += len;
223		}
224	}
225	else
226		FILTER_OUTPUT(3, begin, length, 0);
227
228	if (messageEnd)
229	{
230		FILTER_OUTPUT(4, m_terminator, m_terminator.size(), messageEnd);
231		m_counter = 0;
232	}
233	FILTER_END_NO_MESSAGE_END
234}
235
236NAMESPACE_END
237
238#endif
239