1 /*
2 * Copyright 2016 Huy Cuong Nguyen
3 * Copyright 2016 ZXing authors
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 
18 #include "QREncoder.h"
19 
20 #include "BitArray.h"
21 #include "CharacterSetECI.h"
22 #include "GenericGF.h"
23 #include "QREncodeResult.h"
24 #include "QRErrorCorrectionLevel.h"
25 #include "QRMaskUtil.h"
26 #include "QRMatrixUtil.h"
27 #include "ReedSolomonEncoder.h"
28 #include "TextEncoder.h"
29 #include "ZXTestSupport.h"
30 
31 #include <algorithm>
32 #include <array>
33 #include <limits>
34 #include <stdexcept>
35 
36 namespace ZXing::QRCode {
37 
38 static const CharacterSet DEFAULT_BYTE_MODE_ENCODING = CharacterSet::ISO8859_1;
39 
40 // The original table is defined in the table 5 of JISX0510:2004 (p.19).
41 static const std::array<int, 16*6> ALPHANUMERIC_TABLE = {
42 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // 0x00-0x0f
43 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // 0x10-0x1f
44 	36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,  // 0x20-0x2f
45 	0,   1,  2,  3,  4,  5,  6,  7,  8,  9, 44, -1, -1, -1, -1, -1,  // 0x30-0x3f
46 	-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,  // 0x40-0x4f
47 	25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,  // 0x50-0x5f
48 };
49 
IsOnlyDoubleByteKanji(const std::wstring & content)50 static bool IsOnlyDoubleByteKanji(const std::wstring& content)
51 {
52 	std::string bytes = TextEncoder::FromUnicode(content, CharacterSet::Shift_JIS);
53 	size_t length = bytes.length();
54 	if (length % 2 != 0) {
55 		return false;
56 	}
57 	for (size_t i = 0; i < length; i += 2) {
58 		int byte1 = bytes[i] & 0xff;
59 		if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) {
60 			return false;
61 		}
62 	}
63 	return true;
64 }
65 
66 /**
67 * @return the code point of the table used in alphanumeric mode or
68 *  -1 if there is no corresponding code in the table.
69 */
70 ZXING_EXPORT_TEST_ONLY
GetAlphanumericCode(int code)71 int GetAlphanumericCode(int code)
72 {
73 	if (code < Size(ALPHANUMERIC_TABLE)) {
74 		return ALPHANUMERIC_TABLE[code];
75 	}
76 	return -1;
77 }
78 
79 /**
80 * Choose the best mode by examining the content. Note that 'encoding' is used as a hint;
81 * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}.
82 */
83 ZXING_EXPORT_TEST_ONLY
ChooseMode(const std::wstring & content,CharacterSet encoding)84 CodecMode ChooseMode(const std::wstring& content, CharacterSet encoding)
85 {
86 	if (encoding == CharacterSet::Shift_JIS && IsOnlyDoubleByteKanji(content)) {
87 		// Choose Kanji mode if all input are double-byte characters
88 		return CodecMode::KANJI;
89 	}
90 	bool hasNumeric = false;
91 	bool hasAlphanumeric = false;
92 	for (wchar_t c : content) {
93 		if (c >= '0' && c <= '9') {
94 			hasNumeric = true;
95 		}
96 		else if (GetAlphanumericCode(c) != -1) {
97 			hasAlphanumeric = true;
98 		}
99 		else {
100 			return CodecMode::BYTE;
101 		}
102 	}
103 	if (hasAlphanumeric) {
104 		return CodecMode::ALPHANUMERIC;
105 	}
106 	if (hasNumeric) {
107 		return CodecMode::NUMERIC;
108 	}
109 	return CodecMode::BYTE;
110 }
111 
112 /*
113 * See ISO/IEC 18004:2015 Table 4
114 */
AppendECI(CharacterSet eci,BitArray & bits)115 static void AppendECI(CharacterSet eci, BitArray& bits)
116 {
117 	int eciValue = CharacterSetECI::ValueForCharset(eci);
118 	if (eciValue >= 0 && eciValue <= 999999) {
119 		bits.appendBits(static_cast<int>(CodecMode::ECI), 4);
120 		if (eciValue <= 127) {
121 			bits.appendBits(eciValue, 8);
122 		}
123 		else if (eciValue <= 16383) {
124 			bits.appendBits(0x8000 | eciValue, 16);
125 		}
126 		else {
127 			bits.appendBits(0xC00000 | eciValue, 24);
128 		}
129 	}
130 }
131 
132 /**
133 * Append mode info. On success, store the result in "bits".
134 */
135 ZXING_EXPORT_TEST_ONLY
AppendModeInfo(CodecMode mode,BitArray & bits)136 void AppendModeInfo(CodecMode mode, BitArray& bits)
137 {
138 	bits.appendBits(static_cast<int>(mode), 4);
139 }
140 
141 
142 /**
143 * Append length info. On success, store the result in "bits".
144 */
145 ZXING_EXPORT_TEST_ONLY
AppendLengthInfo(int numLetters,const Version & version,CodecMode mode,BitArray & bits)146 void AppendLengthInfo(int numLetters, const Version& version, CodecMode mode, BitArray& bits)
147 {
148 	int numBits = CharacterCountBits(mode, version);
149 	if (numLetters >= (1 << numBits)) {
150 		return throw std::invalid_argument(std::to_string(numLetters) + " is bigger than " + std::to_string((1 << numBits) - 1));
151 	}
152 	bits.appendBits(numLetters, numBits);
153 }
154 
155 ZXING_EXPORT_TEST_ONLY
AppendNumericBytes(const std::wstring & content,BitArray & bits)156 void AppendNumericBytes(const std::wstring& content, BitArray& bits)
157 {
158 	size_t length = content.length();
159 	size_t i = 0;
160 	while (i < length) {
161 		int num1 = content[i] - '0';
162 		if (i + 2 < length) {
163 			// Encode three numeric letters in ten bits.
164 			int num2 = content[i + 1] - '0';
165 			int num3 = content[i + 2] - '0';
166 			bits.appendBits(num1 * 100 + num2 * 10 + num3, 10);
167 			i += 3;
168 		}
169 		else if (i + 1 < length) {
170 			// Encode two numeric letters in seven bits.
171 			int num2 = content[i + 1] - '0';
172 			bits.appendBits(num1 * 10 + num2, 7);
173 			i += 2;
174 		}
175 		else {
176 			// Encode one numeric letter in four bits.
177 			bits.appendBits(num1, 4);
178 			i++;
179 		}
180 	}
181 }
182 
183 ZXING_EXPORT_TEST_ONLY
AppendAlphanumericBytes(const std::wstring & content,BitArray & bits)184 void AppendAlphanumericBytes(const std::wstring& content, BitArray& bits)
185 {
186 	size_t length = content.length();
187 	size_t i = 0;
188 	while (i < length) {
189 		int code1 = GetAlphanumericCode(content[i]);
190 		if (code1 == -1) {
191 			throw std::invalid_argument("Unexpected contents");
192 		}
193 		if (i + 1 < length) {
194 			int code2 = GetAlphanumericCode(content[i + 1]);
195 			if (code2 == -1) {
196 				throw std::invalid_argument("Unexpected contents");
197 			}
198 			// Encode two alphanumeric letters in 11 bits.
199 			bits.appendBits(code1 * 45 + code2, 11);
200 			i += 2;
201 		}
202 		else {
203 			// Encode one alphanumeric letter in six bits.
204 			bits.appendBits(code1, 6);
205 			i++;
206 		}
207 	}
208 }
209 
210 ZXING_EXPORT_TEST_ONLY
Append8BitBytes(const std::wstring & content,CharacterSet encoding,BitArray & bits)211 void Append8BitBytes(const std::wstring& content, CharacterSet encoding, BitArray& bits)
212 {
213 	for (char b : TextEncoder::FromUnicode(content, encoding)) {
214 		bits.appendBits(b, 8);
215 	}
216 }
217 
218 ZXING_EXPORT_TEST_ONLY
AppendKanjiBytes(const std::wstring & content,BitArray & bits)219 void AppendKanjiBytes(const std::wstring& content, BitArray& bits)
220 {
221 	std::string bytes = TextEncoder::FromUnicode(content, CharacterSet::Shift_JIS);
222 	int length = Size(bytes);
223 	if (length % 2 != 0) {
224 		throw std::invalid_argument("Kanji byte size not even");
225 	}
226 	--length;
227 	for (int i = 0; i < length; i += 2) {
228 		int byte1 = bytes[i] & 0xff;
229 		int byte2 = bytes[i + 1] & 0xff;
230 		int code = (byte1 << 8) | byte2;
231 		int subtracted = -1;
232 		if (code >= 0x8140 && code <= 0x9ffc) {
233 			subtracted = code - 0x8140;
234 		}
235 		else if (code >= 0xe040 && code <= 0xebbf) {
236 			subtracted = code - 0xc140;
237 		}
238 		if (subtracted == -1) {
239 			throw std::invalid_argument("Invalid byte sequence");
240 		}
241 		int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
242 		bits.appendBits(encoded, 13);
243 	}
244 }
245 
246 /**
247 * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
248 */
249 ZXING_EXPORT_TEST_ONLY
AppendBytes(const std::wstring & content,CodecMode mode,CharacterSet encoding,BitArray & bits)250 void AppendBytes(const std::wstring& content, CodecMode mode, CharacterSet encoding, BitArray& bits)
251 {
252 	switch (mode) {
253 		case CodecMode::NUMERIC:
254 			AppendNumericBytes(content, bits);
255 			break;
256 		case CodecMode::ALPHANUMERIC:
257 			AppendAlphanumericBytes(content, bits);
258 			break;
259 		case CodecMode::BYTE:
260 			Append8BitBytes(content, encoding, bits);
261 			break;
262 		case CodecMode::KANJI:
263 			AppendKanjiBytes(content, bits);
264 			break;
265 		default:
266 			throw std::invalid_argument("Invalid mode: " + std::to_string(static_cast<int>(mode)));
267 	}
268 }
269 
270 /**
271 * @return true if the number of input bits will fit in a code with the specified version and
272 * error correction level.
273 */
WillFit(int numInputBits,const Version & version,ErrorCorrectionLevel ecLevel)274 static bool WillFit(int numInputBits, const Version& version, ErrorCorrectionLevel ecLevel) {
275 	// In the following comments, we use numbers of Version 7-H.
276 	// numBytes = 196
277 	int numBytes = version.totalCodewords();
278 	// getNumECBytes = 130
279 	auto ecBlocks = version.ecBlocksForLevel(ecLevel);
280 	int numEcBytes = ecBlocks.totalCodewords();
281 	// getNumDataBytes = 196 - 130 = 66
282 	int numDataBytes = numBytes - numEcBytes;
283 	int totalInputBytes = (numInputBits + 7) / 8;
284 	return numDataBytes >= totalInputBytes;
285 }
286 
ChooseVersion(int numInputBits,ErrorCorrectionLevel ecLevel)287 static const Version& ChooseVersion(int numInputBits, ErrorCorrectionLevel ecLevel)
288 {
289 	for (int versionNum = 1; versionNum <= 40; versionNum++) {
290 		const Version* version = Version::VersionForNumber(versionNum);
291 		if (WillFit(numInputBits, *version, ecLevel)) {
292 			return *version;
293 		}
294 	}
295 	throw std::invalid_argument("Data too big");
296 }
297 
298 /**
299 * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
300 */
301 ZXING_EXPORT_TEST_ONLY
TerminateBits(int numDataBytes,BitArray & bits)302 void TerminateBits(int numDataBytes, BitArray& bits)
303 {
304 	int capacity = numDataBytes * 8;
305 	if (bits.size() > capacity) {
306 		throw std::invalid_argument("data bits cannot fit in the QR Code" + std::to_string(bits.size()) + " > " + std::to_string(capacity));
307 	}
308 	for (int i = 0; i < 4 && bits.size() < capacity; ++i) {
309 		bits.appendBit(false);
310 	}
311 	// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
312 	// If the last byte isn't 8-bit aligned, we'll add padding bits.
313 	int numBitsInLastByte = bits.size() & 0x07;
314 	if (numBitsInLastByte > 0) {
315 		for (int i = numBitsInLastByte; i < 8; i++) {
316 			bits.appendBit(false);
317 		}
318 	}
319 	// If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
320 	int numPaddingBytes = numDataBytes - bits.sizeInBytes();
321 	for (int i = 0; i < numPaddingBytes; ++i) {
322 		bits.appendBits((i & 0x01) == 0 ? 0xEC : 0x11, 8);
323 	}
324 	if (bits.size() != capacity) {
325 		throw std::invalid_argument("Bits size does not equal capacity");
326 	}
327 }
328 
329 struct BlockPair
330 {
331 	ByteArray dataBytes;
332 	ByteArray ecBytes;
333 };
334 
335 
336 /**
337 * Get number of data bytes and number of error correction bytes for block id "blockID". Store
338 * the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
339 * JISX0510:2004 (p.30)
340 */
341 ZXING_EXPORT_TEST_ONLY
GetNumDataBytesAndNumECBytesForBlockID(int numTotalBytes,int numDataBytes,int numRSBlocks,int blockID,int & numDataBytesInBlock,int & numECBytesInBlock)342 void GetNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, int numRSBlocks, int blockID,  int& numDataBytesInBlock, int& numECBytesInBlock)
343 {
344 	if (blockID >= numRSBlocks) {
345 		throw std::invalid_argument("Block ID too large");
346 	}
347 	// numRsBlocksInGroup2 = 196 % 5 = 1
348 	int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
349 	// numRsBlocksInGroup1 = 5 - 1 = 4
350 	int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
351 	// numTotalBytesInGroup1 = 196 / 5 = 39
352 	int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
353 	// numTotalBytesInGroup2 = 39 + 1 = 40
354 	int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
355 	// numDataBytesInGroup1 = 66 / 5 = 13
356 	int numDataBytesInGroup1 = numDataBytes / numRSBlocks;
357 	// numDataBytesInGroup2 = 13 + 1 = 14
358 	int numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
359 	// numEcBytesInGroup1 = 39 - 13 = 26
360 	int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
361 	// numEcBytesInGroup2 = 40 - 14 = 26
362 	int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
363 	// Sanity checks.
364 	// 26 = 26
365 	if (numEcBytesInGroup1 != numEcBytesInGroup2) {
366 		throw std::invalid_argument("EC bytes mismatch");
367 	}
368 	// 5 = 4 + 1.
369 	if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) {
370 		throw std::invalid_argument("RS blocks mismatch");
371 	}
372 	// 196 = (13 + 26) * 4 + (14 + 26) * 1
373 	if (numTotalBytes !=
374 		((numDataBytesInGroup1 + numEcBytesInGroup1) *
375 			numRsBlocksInGroup1) +
376 			((numDataBytesInGroup2 + numEcBytesInGroup2) *
377 				numRsBlocksInGroup2)) {
378 		throw std::invalid_argument("Total bytes mismatch");
379 	}
380 
381 	if (blockID < numRsBlocksInGroup1) {
382 		numDataBytesInBlock = numDataBytesInGroup1;
383 		numECBytesInBlock = numEcBytesInGroup1;
384 	}
385 	else {
386 		numDataBytesInBlock = numDataBytesInGroup2;
387 		numECBytesInBlock = numEcBytesInGroup2;
388 	}
389 }
390 
391 ZXING_EXPORT_TEST_ONLY
GenerateECBytes(const ByteArray & dataBytes,int numEcBytes,ByteArray & ecBytes)392 void GenerateECBytes(const ByteArray& dataBytes, int numEcBytes, ByteArray& ecBytes)
393 {
394 	std::vector<int> message(dataBytes.size() + numEcBytes, 0);
395 	std::copy(dataBytes.begin(), dataBytes.end(), message.begin());
396 	ReedSolomonEncode(GenericGF::QRCodeField256(), message, numEcBytes);
397 
398 	ecBytes.resize(numEcBytes);
399 	std::transform(message.end() - numEcBytes, message.end(), ecBytes.begin(),
400 				   [](auto c) { return static_cast<uint8_t>(c); });
401 }
402 
403 
404 /**
405 * Interleave "bits" with corresponding error correction bytes. On success, store the result in
406 * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
407 */
408 ZXING_EXPORT_TEST_ONLY
InterleaveWithECBytes(const BitArray & bits,int numTotalBytes,int numDataBytes,int numRSBlocks)409 BitArray InterleaveWithECBytes(const BitArray& bits, int numTotalBytes, int numDataBytes, int numRSBlocks)
410 {
411 	// "bits" must have "getNumDataBytes" bytes of data.
412 	if (bits.sizeInBytes() != numDataBytes) {
413 		throw std::invalid_argument("Number of bits and data bytes does not match");
414 	}
415 
416 	// Step 1.  Divide data bytes into blocks and generate error correction bytes for them. We'll
417 	// store the divided data bytes blocks and error correction bytes blocks into "blocks".
418 	int dataBytesOffset = 0;
419 	int maxNumDataBytes = 0;
420 	int maxNumEcBytes = 0;
421 
422 	// Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
423 	std::vector<BlockPair> blocks(numRSBlocks);
424 
425 	for (int i = 0; i < numRSBlocks; ++i) {
426 		int numDataBytesInBlock = 0;
427 		int numEcBytesInBlock = 0;
428 		GetNumDataBytesAndNumECBytesForBlockID(numTotalBytes, numDataBytes, numRSBlocks, i, numDataBytesInBlock, numEcBytesInBlock);
429 
430 		blocks[i].dataBytes = bits.toBytes(8 * dataBytesOffset, numDataBytesInBlock);
431 		GenerateECBytes(blocks[i].dataBytes, numEcBytesInBlock, blocks[i].ecBytes);
432 
433 		maxNumDataBytes = std::max(maxNumDataBytes, numDataBytesInBlock);
434 		maxNumEcBytes = std::max(maxNumEcBytes, Size(blocks[i].ecBytes));
435 		dataBytesOffset += numDataBytesInBlock;
436 	}
437 	if (numDataBytes != dataBytesOffset) {
438 		throw std::invalid_argument("Data bytes does not match offset");
439 	}
440 
441 	BitArray output;
442 	// First, place data blocks.
443 	for (int i = 0; i < maxNumDataBytes; ++i) {
444 		for (auto& block : blocks) {
445 			if (i < Size(block.dataBytes)) {
446 				output.appendBits(block.dataBytes[i], 8);
447 			}
448 		}
449 	}
450 	// Then, place error correction blocks.
451 	for (int i = 0; i < maxNumEcBytes; ++i) {
452 		for (auto& block : blocks) {
453 			if (i < Size(block.ecBytes)) {
454 				output.appendBits(block.ecBytes[i], 8);
455 			}
456 		}
457 	}
458 	if (numTotalBytes != output.sizeInBytes()) {  // Should be same.
459 		throw std::invalid_argument("Interleaving error: " + std::to_string(numTotalBytes) + " and " + std::to_string(output.sizeInBytes()) + " differ.");
460 	}
461 	return output;
462 }
463 
464 
ChooseMaskPattern(const BitArray & bits,ErrorCorrectionLevel ecLevel,const Version & version,TritMatrix & matrix)465 static int ChooseMaskPattern(const BitArray& bits, ErrorCorrectionLevel ecLevel, const Version& version, TritMatrix& matrix)
466 {
467 	int minPenalty = std::numeric_limits<int>::max();  // Lower penalty is better.
468 	int bestMaskPattern = -1;
469 	// We try all mask patterns to choose the best one.
470 	for (int maskPattern = 0; maskPattern < NUM_MASK_PATTERNS; maskPattern++) {
471 		BuildMatrix(bits, ecLevel, version, maskPattern, matrix);
472 		int penalty = MaskUtil::CalculateMaskPenalty(matrix);
473 		if (penalty < minPenalty) {
474 			minPenalty = penalty;
475 			bestMaskPattern = maskPattern;
476 		}
477 	}
478 	return bestMaskPattern;
479 }
480 
CalculateBitsNeeded(CodecMode mode,const BitArray & headerBits,const BitArray & dataBits,const Version & version)481 static int CalculateBitsNeeded(CodecMode mode, const BitArray& headerBits, const BitArray& dataBits, const Version& version)
482 {
483 	return headerBits.size() + CharacterCountBits(mode, version) + dataBits.size();
484 }
485 
486 /**
487 * Decides the smallest version of QR code that will contain all of the provided data.
488 * @throws WriterException if the data cannot fit in any version
489 */
RecommendVersion(ErrorCorrectionLevel ecLevel,CodecMode mode,const BitArray & headerBits,const BitArray & dataBits)490 static const Version& RecommendVersion(ErrorCorrectionLevel ecLevel, CodecMode mode, const BitArray& headerBits, const BitArray& dataBits)
491 {
492 	// Hard part: need to know version to know how many bits length takes. But need to know how many
493 	// bits it takes to know version. First we take a guess at version by assuming version will be
494 	// the minimum, 1:
495 	int provisionalBitsNeeded = CalculateBitsNeeded(mode, headerBits, dataBits, *Version::VersionForNumber(1));
496 	const Version& provisionalVersion = ChooseVersion(provisionalBitsNeeded, ecLevel);
497 
498 	// Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
499 	int bitsNeeded = CalculateBitsNeeded(mode, headerBits, dataBits, provisionalVersion);
500 	return ChooseVersion(bitsNeeded, ecLevel);
501 }
502 
Encode(const std::wstring & content,ErrorCorrectionLevel ecLevel,CharacterSet charset,int versionNumber,bool useGs1Format,int maskPattern)503 EncodeResult Encode(const std::wstring& content, ErrorCorrectionLevel ecLevel, CharacterSet charset, int versionNumber,
504 					bool useGs1Format, int maskPattern)
505 {
506 	bool charsetWasUnknown = charset == CharacterSet::Unknown;
507 	if (charsetWasUnknown) {
508 		charset = DEFAULT_BYTE_MODE_ENCODING;
509 	}
510 
511 	// Pick an encoding mode appropriate for the content. Note that this will not attempt to use
512 	// multiple modes / segments even if that were more efficient. Twould be nice.
513 	CodecMode mode = ChooseMode(content, charset);
514 
515 	// This will store the header information, like mode and
516 	// length, as well as "header" segments like an ECI segment.
517 	BitArray headerBits;
518 
519 	// Append ECI segment if applicable
520 	if (mode == CodecMode::BYTE && !charsetWasUnknown) {
521 		AppendECI(charset, headerBits);
522 	}
523 
524 	// Append the FNC1 mode header for GS1 formatted data if applicable
525 	if (useGs1Format) {
526 		// GS1 formatted codes are prefixed with a FNC1 in first position mode header
527 		AppendModeInfo(CodecMode::FNC1_FIRST_POSITION, headerBits);
528 	}
529 
530 	// (With ECI in place,) Write the mode marker
531 	AppendModeInfo(mode, headerBits);
532 
533 	// Collect data within the main segment, separately, to count its size if needed. Don't add it to
534 	// main payload yet.
535 	BitArray dataBits;
536 	AppendBytes(content, mode, charset, dataBits);
537 
538 	const Version* version;
539 	if (versionNumber > 0) {
540 		version = Version::VersionForNumber(versionNumber);
541 		if (version != nullptr) {
542 			int bitsNeeded = CalculateBitsNeeded(mode, headerBits, dataBits, *version);
543 			if (!WillFit(bitsNeeded, *version, ecLevel)) {
544 				throw std::invalid_argument("Data too big for requested version");
545 			}
546 		}
547 		else {
548 			version = &RecommendVersion(ecLevel, mode, headerBits, dataBits);
549 		}
550 	}
551 	else {
552 		version = &RecommendVersion(ecLevel, mode, headerBits, dataBits);
553 	}
554 
555 	BitArray headerAndDataBits;
556 	headerAndDataBits.appendBitArray(headerBits);
557 	// Find "length" of main segment and write it
558 	int numLetters = mode == CodecMode::BYTE ? dataBits.sizeInBytes() : Size(content);
559 	AppendLengthInfo(numLetters, *version, mode, headerAndDataBits);
560 	// Put data together into the overall payload
561 	headerAndDataBits.appendBitArray(dataBits);
562 
563 	auto& ecBlocks = version->ecBlocksForLevel(ecLevel);
564 	int numDataBytes = version->totalCodewords() - ecBlocks.totalCodewords();
565 
566 	// Terminate the bits properly.
567 	TerminateBits(numDataBytes, headerAndDataBits);
568 
569 	// Interleave data bits with error correction code.
570 	BitArray finalBits =
571 		InterleaveWithECBytes(headerAndDataBits, version->totalCodewords(), numDataBytes, ecBlocks.numBlocks());
572 
573 	EncodeResult output;
574 	output.ecLevel = ecLevel;
575 	output.mode = mode;
576 	output.version = version;
577 
578 	//  Choose the mask pattern and set to "qrCode".
579 	int dimension = version->dimensionForVersion();
580 	TritMatrix matrix(dimension, dimension);
581 	output.maskPattern = maskPattern != -1 ? maskPattern : ChooseMaskPattern(finalBits, ecLevel, *version, matrix);
582 
583 	// Build the matrix and set it to "qrCode".
584 	BuildMatrix(finalBits, ecLevel, *version, output.maskPattern, matrix);
585 
586 	output.matrix = ToBitMatrix(matrix);
587 
588 	return output;
589 }
590 
591 } // namespace ZXing::QRCode
592