blob: a44dfc39f6d8b02500bab81197fb5dc557c08f3a [file] [log] [blame]
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -07001// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6// Original code is licensed as follows:
7/*
8 * Copyright 2008 ZXing authors
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23#include "fxbarcode/qrcode/BC_QRCoderEncoder.h"
24
25#include <algorithm>
26#include <memory>
27#include <utility>
28
29#include "fxbarcode/BC_UtilCodingConvert.h"
30#include "fxbarcode/common/BC_CommonByteArray.h"
31#include "fxbarcode/common/BC_CommonByteMatrix.h"
32#include "fxbarcode/common/reedsolomon/BC_ReedSolomon.h"
33#include "fxbarcode/common/reedsolomon/BC_ReedSolomonGF256.h"
34#include "fxbarcode/qrcode/BC_QRCoder.h"
35#include "fxbarcode/qrcode/BC_QRCoderBitVector.h"
36#include "fxbarcode/qrcode/BC_QRCoderBlockPair.h"
37#include "fxbarcode/qrcode/BC_QRCoderECBlocks.h"
38#include "fxbarcode/qrcode/BC_QRCoderMaskUtil.h"
39#include "fxbarcode/qrcode/BC_QRCoderMatrixUtil.h"
40#include "fxbarcode/qrcode/BC_QRCoderMode.h"
41#include "fxbarcode/qrcode/BC_QRCoderVersion.h"
42#include "third_party/base/ptr_util.h"
43
44using ModeStringPair = std::pair<CBC_QRCoderMode*, ByteString>;
45
46namespace {
47
48// This is a mapping for an ASCII table, starting at an index of 32.
49const int8_t g_alphaNumericTable[] = {
50 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 32-47
51 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 48-63
52 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 64-79
53 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35};
54
55int32_t GetAlphaNumericCode(int32_t code) {
56 if (code < 32)
57 return -1;
58 size_t code_index = static_cast<size_t>(code - 32);
59 if (code_index >= FX_ArraySize(g_alphaNumericTable))
60 return -1;
61 return g_alphaNumericTable[code_index];
62}
63
64void AppendNumericBytes(const ByteString& content,
65 CBC_QRCoderBitVector* bits,
66 int32_t& e) {
67 int32_t length = content.GetLength();
68 int32_t i = 0;
69 while (i < length) {
70 int32_t num1 = content[i] - '0';
71 if (i + 2 < length) {
72 int32_t num2 = content[i + 1] - '0';
73 int32_t num3 = content[i + 2] - '0';
74 bits->AppendBits(num1 * 100 + num2 * 10 + num3, 10);
75 i += 3;
76 } else if (i + 1 < length) {
77 int32_t num2 = content[i + 1] - '0';
78 bits->AppendBits(num1 * 10 + num2, 7);
79 i += 2;
80 } else {
81 bits->AppendBits(num1, 4);
82 i++;
83 }
84 }
85}
86
87void AppendAlphaNumericBytes(const ByteString& content,
88 CBC_QRCoderBitVector* bits,
89 int32_t& e) {
90 int32_t length = content.GetLength();
91 int32_t i = 0;
92 while (i < length) {
93 int32_t code1 = GetAlphaNumericCode(content[i]);
94 if (code1 == -1) {
95 e = BCExceptionInvalidateCharacter;
96 return;
97 }
98 if (i + 1 < length) {
99 int32_t code2 = GetAlphaNumericCode(content[i + 1]);
100 if (code2 == -1) {
101 e = BCExceptionInvalidateCharacter;
102 return;
103 }
104 bits->AppendBits(code1 * 45 + code2, 11);
105 i += 2;
106 } else {
107 bits->AppendBits(code1, 6);
108 i++;
109 }
110 }
111}
112
113void AppendGBKBytes(const ByteString& content,
114 CBC_QRCoderBitVector* bits,
115 int32_t& e) {
116 int32_t length = content.GetLength();
117 uint32_t value = 0;
118 for (int32_t i = 0; i < length; i += 2) {
119 value = (uint32_t)(content[i] << 8 | content[i + 1]);
120 if (value <= 0xAAFE && value >= 0xA1A1) {
121 value -= 0xA1A1;
122 } else if (value <= 0xFAFE && value >= 0xB0A1) {
123 value -= 0xA6A1;
124 } else {
125 e = BCExceptionInvalidateCharacter;
126 return;
127 }
128 value = (uint32_t)((value >> 8) * 0x60) + (uint32_t)(value & 0xff);
129 bits->AppendBits(value, 13);
130 }
131}
132
133void Append8BitBytes(const ByteString& content,
134 CBC_QRCoderBitVector* bits,
135 ByteString encoding,
136 int32_t& e) {
137 for (size_t i = 0; i < content.GetLength(); i++)
138 bits->AppendBits(content[i], 8);
139}
140
141void AppendKanjiBytes(const ByteString& content,
142 CBC_QRCoderBitVector* bits,
143 int32_t& e) {
144 std::vector<uint8_t> bytes;
145 uint32_t value = 0;
146 for (size_t i = 0; i < bytes.size(); i += 2) {
147 value = (uint32_t)((content[i] << 8) | content[i + 1]);
148 if (value <= 0x9ffc && value >= 0x8140) {
149 value -= 0x8140;
150 } else if (value <= 0xebbf && value >= 0xe040) {
151 value -= 0xc140;
152 } else {
153 e = BCExceptionInvalidateCharacter;
154 return;
155 }
156 value = (uint32_t)((value >> 8) * 0xc0) + (uint32_t)(value & 0xff);
157 bits->AppendBits(value, 13);
158 }
159}
160
161void AppendModeInfo(CBC_QRCoderMode* mode, CBC_QRCoderBitVector* bits) {
162 bits->AppendBits(mode->GetBits(), 4);
163 if (mode == CBC_QRCoderMode::sGBK)
164 bits->AppendBits(1, 4);
165}
166
167bool AppendLengthInfo(int32_t numLetters,
168 int32_t version,
169 CBC_QRCoderMode* mode,
170 CBC_QRCoderBitVector* bits) {
171 int32_t e = BCExceptionNO;
172 const auto* qcv = CBC_QRCoderVersion::GetVersionForNumber(version);
173 if (!qcv)
174 return false;
175 int32_t numBits = mode->GetCharacterCountBits(qcv->GetVersionNumber(), e);
176 if (e != BCExceptionNO)
177 return false;
178 if (numBits > ((1 << numBits) - 1))
179 return true;
180
181 if (mode == CBC_QRCoderMode::sGBK)
182 bits->AppendBits(numLetters / 2, numBits);
183 bits->AppendBits(numLetters, numBits);
184 return true;
185}
186
187void AppendBytes(const ByteString& content,
188 CBC_QRCoderMode* mode,
189 CBC_QRCoderBitVector* bits,
190 ByteString encoding,
191 int32_t& e) {
192 if (mode == CBC_QRCoderMode::sNUMERIC)
193 AppendNumericBytes(content, bits, e);
194 else if (mode == CBC_QRCoderMode::sALPHANUMERIC)
195 AppendAlphaNumericBytes(content, bits, e);
196 else if (mode == CBC_QRCoderMode::sBYTE)
197 Append8BitBytes(content, bits, encoding, e);
198 else if (mode == CBC_QRCoderMode::sKANJI)
199 AppendKanjiBytes(content, bits, e);
200 else if (mode == CBC_QRCoderMode::sGBK)
201 AppendGBKBytes(content, bits, e);
202 else
203 e = BCExceptionUnsupportedMode;
204}
205
206bool InitQRCode(int32_t numInputBytes,
207 const CBC_QRCoderErrorCorrectionLevel* ecLevel,
208 CBC_QRCoderMode* mode,
209 CBC_QRCoder* qrCode) {
210 qrCode->SetECLevel(ecLevel);
211 qrCode->SetMode(mode);
212 for (int32_t i = 1; i <= CBC_QRCoderVersion::kMaxVersion; ++i) {
213 const auto* version = CBC_QRCoderVersion::GetVersionForNumber(i);
214 int32_t numBytes = version->GetTotalCodeWords();
215 const auto* ecBlocks = version->GetECBlocksForLevel(*ecLevel);
216 int32_t numEcBytes = ecBlocks->GetTotalECCodeWords();
217 int32_t numRSBlocks = ecBlocks->GetNumBlocks();
218 int32_t numDataBytes = numBytes - numEcBytes;
219 if (numDataBytes >= numInputBytes + 3) {
220 qrCode->SetVersion(i);
221 qrCode->SetNumTotalBytes(numBytes);
222 qrCode->SetNumDataBytes(numDataBytes);
223 qrCode->SetNumRSBlocks(numRSBlocks);
224 qrCode->SetNumECBytes(numEcBytes);
225 qrCode->SetMatrixWidth(version->GetDimensionForVersion());
226 return true;
227 }
228 }
229 return false;
230}
231
232std::unique_ptr<CBC_CommonByteArray> GenerateECBytes(
233 CBC_CommonByteArray* dataBytes,
234 int32_t numEcBytesInBlock) {
235 int32_t numDataBytes = dataBytes->Size();
236 std::vector<int32_t> toEncode(numDataBytes + numEcBytesInBlock);
237 for (int32_t i = 0; i < numDataBytes; ++i)
238 toEncode[i] = dataBytes->At(i);
239 CBC_ReedSolomonEncoder encode(CBC_ReedSolomonGF256::QRCodeField);
240 encode.Init();
241 if (!encode.Encode(&toEncode, numEcBytesInBlock))
242 return nullptr;
243 auto ecBytes = pdfium::MakeUnique<CBC_CommonByteArray>(numEcBytesInBlock);
244 for (int32_t i = 0; i < numEcBytesInBlock; ++i)
245 ecBytes->Set(i, toEncode[numDataBytes + i]);
246 return ecBytes;
247}
248
249int32_t GetSpanByVersion(CBC_QRCoderMode* modeFirst,
250 CBC_QRCoderMode* modeSecond,
251 int32_t versionNum,
252 int32_t& e) {
253 if (versionNum == 0)
254 return 0;
255
256 if (modeFirst == CBC_QRCoderMode::sALPHANUMERIC &&
257 modeSecond == CBC_QRCoderMode::sBYTE) {
258 if (versionNum >= 1 && versionNum <= 9)
259 return 11;
260 if (versionNum >= 10 && versionNum <= 26)
261 return 15;
262 if (versionNum >= 27 && versionNum <= CBC_QRCoderVersion::kMaxVersion)
263 return 16;
264 e = BCExceptionNoSuchVersion;
265 return 0;
266 }
267 if (modeSecond == CBC_QRCoderMode::sALPHANUMERIC &&
268 modeFirst == CBC_QRCoderMode::sNUMERIC) {
269 if (versionNum >= 1 && versionNum <= 9)
270 return 13;
271 if (versionNum >= 10 && versionNum <= 26)
272 return 15;
273 if (versionNum >= 27 && versionNum <= CBC_QRCoderVersion::kMaxVersion)
274 return 17;
275 e = BCExceptionNoSuchVersion;
276 return 0;
277 }
278 if (modeSecond == CBC_QRCoderMode::sBYTE &&
279 modeFirst == CBC_QRCoderMode::sNUMERIC) {
280 if (versionNum >= 1 && versionNum <= 9)
281 return 6;
282 if (versionNum >= 10 && versionNum <= 26)
283 return 8;
284 if (versionNum >= 27 && versionNum <= CBC_QRCoderVersion::kMaxVersion)
285 return 9;
286 e = BCExceptionNoSuchVersion;
287 return 0;
288 }
289 return -1;
290}
291
292int32_t CalculateMaskPenalty(CBC_CommonByteMatrix* matrix) {
293 return CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule1(matrix) +
294 CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule2(matrix) +
295 CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule3(matrix) +
296 CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule4(matrix);
297}
298
299int32_t ChooseMaskPattern(CBC_QRCoderBitVector* bits,
300 const CBC_QRCoderErrorCorrectionLevel* ecLevel,
301 int32_t version,
302 CBC_CommonByteMatrix* matrix,
303 int32_t& e) {
304 int32_t minPenalty = 65535;
305 int32_t bestMaskPattern = -1;
306 for (int32_t maskPattern = 0; maskPattern < CBC_QRCoder::kNumMaskPatterns;
307 maskPattern++) {
308 CBC_QRCoderMatrixUtil::BuildMatrix(bits, ecLevel, version, maskPattern,
309 matrix, e);
310 if (e != BCExceptionNO)
311 return 0;
312 int32_t penalty = CalculateMaskPenalty(matrix);
313 if (penalty < minPenalty) {
314 minPenalty = penalty;
315 bestMaskPattern = maskPattern;
316 }
317 }
318 return bestMaskPattern;
319}
320
321void GetNumDataBytesAndNumECBytesForBlockID(int32_t numTotalBytes,
322 int32_t numDataBytes,
323 int32_t numRSBlocks,
324 int32_t blockID,
325 int32_t& numDataBytesInBlock,
326 int32_t& numECBytesInBlock) {
327 if (blockID >= numRSBlocks)
328 return;
329
330 int32_t numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
331 int32_t numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
332 int32_t numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
333 int32_t numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
334 int32_t numDataBytesInGroup1 = numDataBytes / numRSBlocks;
335 int32_t numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
336 int32_t numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
337 int32_t numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
338 if (blockID < numRsBlocksInGroup1) {
339 numDataBytesInBlock = numDataBytesInGroup1;
340 numECBytesInBlock = numEcBytesInGroup1;
341 } else {
342 numDataBytesInBlock = numDataBytesInGroup2;
343 numECBytesInBlock = numEcBytesInGroup2;
344 }
345}
346
347bool TerminateBits(int32_t numDataBytes, CBC_QRCoderBitVector* bits) {
348 size_t capacity = numDataBytes << 3;
349 if (bits->Size() > capacity)
350 return false;
351
352 for (int32_t i = 0; i < 4 && bits->Size() < capacity; ++i)
353 bits->AppendBit(0);
354
355 int32_t numBitsInLastByte = bits->Size() % 8;
356 if (numBitsInLastByte > 0) {
357 int32_t numPaddingBits = 8 - numBitsInLastByte;
358 for (int32_t j = 0; j < numPaddingBits; ++j)
359 bits->AppendBit(0);
360 }
361
362 if (bits->Size() % 8 != 0)
363 return false;
364
365 int32_t numPaddingBytes = numDataBytes - bits->sizeInBytes();
366 for (int32_t k = 0; k < numPaddingBytes; ++k)
367 bits->AppendBits(k % 2 ? 0x11 : 0xec, 8);
368 return bits->Size() == capacity;
369}
370
371void MergeString(std::vector<ModeStringPair>* result,
372 int32_t versionNum,
373 int32_t& e) {
374 size_t mergeNum = 0;
375 for (size_t i = 0; i + 1 < result->size(); i++) {
376 auto& element1 = (*result)[i];
377 auto& element2 = (*result)[i + 1];
378 if (element1.first == CBC_QRCoderMode::sALPHANUMERIC) {
379 int32_t tmp = GetSpanByVersion(CBC_QRCoderMode::sALPHANUMERIC,
380 CBC_QRCoderMode::sBYTE, versionNum, e);
381 if (e != BCExceptionNO)
382 return;
383 if (element2.first == CBC_QRCoderMode::sBYTE && tmp >= 0 &&
384 element1.second.GetLength() < static_cast<size_t>(tmp)) {
385 element2.second = element1.second + element2.second;
386 result->erase(result->begin() + i);
387 i--;
388 mergeNum++;
389 }
390 } else if (element1.first == CBC_QRCoderMode::sBYTE) {
391 if (element2.first == CBC_QRCoderMode::sBYTE) {
392 element1.second += element2.second;
393 result->erase(result->begin() + i + 1);
394 i--;
395 mergeNum++;
396 }
397 } else if (element1.first == CBC_QRCoderMode::sNUMERIC) {
398 int32_t tmp = GetSpanByVersion(CBC_QRCoderMode::sNUMERIC,
399 CBC_QRCoderMode::sBYTE, versionNum, e);
400 if (e != BCExceptionNO)
401 return;
402 if (element2.first == CBC_QRCoderMode::sBYTE && tmp >= 0 &&
403 element1.second.GetLength() < static_cast<size_t>(tmp)) {
404 element2.second = element1.second + element2.second;
405 result->erase(result->begin() + i);
406 i--;
407 mergeNum++;
408 }
409 tmp = GetSpanByVersion(CBC_QRCoderMode::sNUMERIC,
410 CBC_QRCoderMode::sALPHANUMERIC, versionNum, e);
411 if (e != BCExceptionNO)
412 return;
413 if (element2.first == CBC_QRCoderMode::sALPHANUMERIC && tmp >= 0 &&
414 element1.second.GetLength() < static_cast<size_t>(tmp)) {
415 element2.second = element1.second + element2.second;
416 result->erase(result->begin() + i);
417 i--;
418 mergeNum++;
419 }
420 }
421 }
422 if (mergeNum != 0)
423 MergeString(result, versionNum, e);
424}
425
426void SplitString(const ByteString& content,
427 std::vector<ModeStringPair>* result) {
428 size_t index = 0;
429 while (index < content.GetLength()) {
430 uint8_t c = static_cast<uint8_t>(content[index]);
431 if (!((c >= 0xA1 && c <= 0xAA) || (c >= 0xB0 && c <= 0xFA)))
432 break;
433 index += 2;
434 }
435 if (index)
436 result->push_back({CBC_QRCoderMode::sGBK, content.Left(index)});
437 if (index >= content.GetLength())
438 return;
439
440 size_t flag = index;
441 while (GetAlphaNumericCode(content[index]) == -1 &&
442 index < content.GetLength()) {
443 uint8_t c = static_cast<uint8_t>(content[index]);
444 if (((c >= 0xA1 && c <= 0xAA) || (c >= 0xB0 && c <= 0xFA)))
445 break;
446#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
447 bool high = !!IsDBCSLeadByte(content[index]);
448#else
449 bool high = content[index] > 127;
450#endif
451 ++index;
452 if (high)
453 ++index;
454 }
455 if (index != flag) {
456 result->push_back(
457 {CBC_QRCoderMode::sBYTE, content.Mid(flag, index - flag)});
458 }
459 flag = index;
460 if (index >= content.GetLength())
461 return;
462
463 while (index < content.GetLength() && isdigit(content[index]))
464 ++index;
465
466 if (index != flag) {
467 result->push_back(
468 {CBC_QRCoderMode::sNUMERIC, content.Mid(flag, index - flag)});
469 }
470 flag = index;
471 if (index >= content.GetLength())
472 return;
473
474 while (index < content.GetLength() &&
475 GetAlphaNumericCode(content[index]) != -1) {
476 ++index;
477 }
478 if (index != flag) {
479 result->push_back(
480 {CBC_QRCoderMode::sALPHANUMERIC, content.Mid(flag, index - flag)});
481 }
482 flag = index;
483 if (index < content.GetLength())
484 SplitString(content.Right(content.GetLength() - index), result);
485}
486
487CBC_QRCoderMode* ChooseMode(const ByteString& content, ByteString encoding) {
488 if (encoding.Compare("SHIFT_JIS") == 0)
489 return CBC_QRCoderMode::sKANJI;
490
491 bool hasNumeric = false;
492 bool hasAlphaNumeric = false;
493 for (size_t i = 0; i < content.GetLength(); i++) {
494 if (isdigit(content[i])) {
495 hasNumeric = true;
496 } else if (GetAlphaNumericCode(content[i]) != -1) {
497 hasAlphaNumeric = true;
498 } else {
499 return CBC_QRCoderMode::sBYTE;
500 }
501 }
502 if (hasAlphaNumeric)
503 return CBC_QRCoderMode::sALPHANUMERIC;
504 if (hasNumeric)
505 return CBC_QRCoderMode::sNUMERIC;
506 return CBC_QRCoderMode::sBYTE;
507}
508
509bool InterleaveWithECBytes(CBC_QRCoderBitVector* bits,
510 int32_t numTotalBytes,
511 int32_t numDataBytes,
512 int32_t numRSBlocks,
513 CBC_QRCoderBitVector* result) {
514 ASSERT(numTotalBytes >= 0);
515 ASSERT(numDataBytes >= 0);
516 if (bits->sizeInBytes() != static_cast<size_t>(numDataBytes))
517 return false;
518
519 int32_t dataBytesOffset = 0;
520 int32_t maxNumDataBytes = 0;
521 int32_t maxNumEcBytes = 0;
522 std::vector<CBC_QRCoderBlockPair> blocks(numRSBlocks);
523 for (int32_t i = 0; i < numRSBlocks; i++) {
524 int32_t numDataBytesInBlock;
525 int32_t numEcBytesInBlosk;
526 GetNumDataBytesAndNumECBytesForBlockID(numTotalBytes, numDataBytes,
527 numRSBlocks, i, numDataBytesInBlock,
528 numEcBytesInBlosk);
529 auto dataBytes = pdfium::MakeUnique<CBC_CommonByteArray>();
530 dataBytes->Set(bits->GetArray(), dataBytesOffset, numDataBytesInBlock);
531 std::unique_ptr<CBC_CommonByteArray> ecBytes =
532 GenerateECBytes(dataBytes.get(), numEcBytesInBlosk);
533 if (!ecBytes)
534 return false;
535
536 maxNumDataBytes = std::max(maxNumDataBytes, dataBytes->Size());
537 maxNumEcBytes = std::max(maxNumEcBytes, ecBytes->Size());
538 blocks[i].SetData(std::move(dataBytes), std::move(ecBytes));
539 dataBytesOffset += numDataBytesInBlock;
540 }
541 if (numDataBytes != dataBytesOffset)
542 return false;
543
544 for (int32_t x = 0; x < maxNumDataBytes; x++) {
545 for (size_t j = 0; j < blocks.size(); j++) {
546 const CBC_CommonByteArray* dataBytes = blocks[j].GetDataBytes();
547 if (x < dataBytes->Size())
548 result->AppendBits(dataBytes->At(x), 8);
549 }
550 }
551 for (int32_t y = 0; y < maxNumEcBytes; y++) {
552 for (size_t l = 0; l < blocks.size(); l++) {
553 const CBC_CommonByteArray* ecBytes = blocks[l].GetErrorCorrectionBytes();
554 if (y < ecBytes->Size())
555 result->AppendBits(ecBytes->At(y), 8);
556 }
557 }
558 return static_cast<size_t>(numTotalBytes) == result->sizeInBytes();
559}
560
561} // namespace
562
563CBC_QRCoderEncoder::CBC_QRCoderEncoder() {}
564
565CBC_QRCoderEncoder::~CBC_QRCoderEncoder() {}
566
567// static
568bool CBC_QRCoderEncoder::Encode(const WideString& content,
569 const CBC_QRCoderErrorCorrectionLevel* ecLevel,
570 CBC_QRCoder* qrCode) {
571 ByteString encoding = "utf8";
572 ByteString utf8Data;
573 CBC_UtilCodingConvert::UnicodeToUTF8(content, utf8Data);
574 CBC_QRCoderMode* mode = ChooseMode(utf8Data, encoding);
575 CBC_QRCoderBitVector dataBits;
576 int32_t e = BCExceptionNO;
577 AppendBytes(utf8Data, mode, &dataBits, encoding, e);
578 if (e != BCExceptionNO)
579 return false;
580 int32_t numInputBytes = dataBits.sizeInBytes();
581 if (!InitQRCode(numInputBytes, ecLevel, mode, qrCode))
582 return false;
583 CBC_QRCoderBitVector headerAndDataBits;
584 AppendModeInfo(mode, &headerAndDataBits);
585 int32_t numLetters = mode == CBC_QRCoderMode::sBYTE ? dataBits.sizeInBytes()
586 : content.GetLength();
587 if (!AppendLengthInfo(numLetters, qrCode->GetVersion(), mode,
588 &headerAndDataBits)) {
589 return false;
590 }
591 headerAndDataBits.AppendBitVector(&dataBits);
592 if (!TerminateBits(qrCode->GetNumDataBytes(), &headerAndDataBits))
593 return false;
594 CBC_QRCoderBitVector finalBits;
595 if (!InterleaveWithECBytes(&headerAndDataBits, qrCode->GetNumTotalBytes(),
596 qrCode->GetNumDataBytes(),
597 qrCode->GetNumRSBlocks(), &finalBits)) {
598 return false;
599 }
600
601 auto matrix = pdfium::MakeUnique<CBC_CommonByteMatrix>(
602 qrCode->GetMatrixWidth(), qrCode->GetMatrixWidth());
603 matrix->Init();
604 int32_t maskPattern = ChooseMaskPattern(
605 &finalBits, qrCode->GetECLevel(), qrCode->GetVersion(), matrix.get(), e);
606 if (e != BCExceptionNO)
607 return false;
608
609 qrCode->SetMaskPattern(maskPattern);
610 CBC_QRCoderMatrixUtil::BuildMatrix(&finalBits, qrCode->GetECLevel(),
611 qrCode->GetVersion(),
612 qrCode->GetMaskPattern(), matrix.get(), e);
613 if (e != BCExceptionNO)
614 return false;
615
616 qrCode->SetMatrix(std::move(matrix));
617 return qrCode->IsValid();
618}