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