• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 "xfa/fxbarcode/qrcode/BC_QRCoderEncoder.h"
24 
25 #include <algorithm>
26 #include <memory>
27 #include <utility>
28 
29 #include "xfa/fxbarcode/BC_UtilCodingConvert.h"
30 #include "xfa/fxbarcode/common/BC_CommonByteArray.h"
31 #include "xfa/fxbarcode/common/BC_CommonByteMatrix.h"
32 #include "xfa/fxbarcode/common/reedsolomon/BC_ReedSolomon.h"
33 #include "xfa/fxbarcode/common/reedsolomon/BC_ReedSolomonGF256.h"
34 #include "xfa/fxbarcode/qrcode/BC_QRCoder.h"
35 #include "xfa/fxbarcode/qrcode/BC_QRCoderBitVector.h"
36 #include "xfa/fxbarcode/qrcode/BC_QRCoderBlockPair.h"
37 #include "xfa/fxbarcode/qrcode/BC_QRCoderECBlocks.h"
38 #include "xfa/fxbarcode/qrcode/BC_QRCoderMaskUtil.h"
39 #include "xfa/fxbarcode/qrcode/BC_QRCoderMatrixUtil.h"
40 #include "xfa/fxbarcode/qrcode/BC_QRCoderMode.h"
41 #include "xfa/fxbarcode/qrcode/BC_QRCoderVersion.h"
42 
43 namespace {
44 
45 const int8_t g_alphaNumericTable[] = {
46     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
47     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48     36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
49     0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  44, -1, -1, -1, -1, -1,
50     -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
51     25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1};
52 
53 }  // namespace
54 
CBC_QRCoderEncoder()55 CBC_QRCoderEncoder::CBC_QRCoderEncoder() {}
56 
~CBC_QRCoderEncoder()57 CBC_QRCoderEncoder::~CBC_QRCoderEncoder() {}
58 
Encode(const CFX_ByteString & content,CBC_QRCoderErrorCorrectionLevel * ecLevel,CBC_QRCoder * qrCode,int32_t & e,int32_t versionSpecify)59 void CBC_QRCoderEncoder::Encode(const CFX_ByteString& content,
60                                 CBC_QRCoderErrorCorrectionLevel* ecLevel,
61                                 CBC_QRCoder* qrCode,
62                                 int32_t& e,
63                                 int32_t versionSpecify) {
64   if (versionSpecify == 0) {
65     EncodeWithAutoVersion(content, ecLevel, qrCode, e);
66     if (e != BCExceptionNO)
67       return;
68   } else if (versionSpecify > 0 && versionSpecify <= 40) {
69     EncodeWithSpecifyVersion(content, ecLevel, qrCode, versionSpecify, e);
70     if (e != BCExceptionNO)
71       return;
72   } else {
73     e = BCExceptionVersionMust1_40;
74     if (e != BCExceptionNO)
75       return;
76   }
77 }
78 
AppendECI(CBC_QRCoderBitVector * bits)79 void CBC_QRCoderEncoder::AppendECI(CBC_QRCoderBitVector* bits) {}
80 
AppendDataModeLenghInfo(const std::vector<std::pair<CBC_QRCoderMode *,CFX_ByteString>> & splitResults,CBC_QRCoderBitVector & headerAndDataBits,CBC_QRCoderMode * tempMode,CBC_QRCoder * qrCode,CFX_ByteString & encoding,int32_t & e)81 void CBC_QRCoderEncoder::AppendDataModeLenghInfo(
82     const std::vector<std::pair<CBC_QRCoderMode*, CFX_ByteString>>&
83         splitResults,
84     CBC_QRCoderBitVector& headerAndDataBits,
85     CBC_QRCoderMode* tempMode,
86     CBC_QRCoder* qrCode,
87     CFX_ByteString& encoding,
88     int32_t& e) {
89   for (const auto& splitResult : splitResults) {
90     tempMode = splitResult.first;
91     if (tempMode == CBC_QRCoderMode::sGBK) {
92       AppendModeInfo(tempMode, &headerAndDataBits, e);
93       if (e != BCExceptionNO)
94         return;
95       AppendLengthInfo(splitResult.second.GetLength(), qrCode->GetVersion(),
96                        tempMode, &headerAndDataBits, e);
97       if (e != BCExceptionNO)
98         return;
99       AppendBytes(splitResult.second, tempMode, &headerAndDataBits, encoding,
100                   e);
101       if (e != BCExceptionNO)
102         return;
103     } else if (tempMode == CBC_QRCoderMode::sBYTE) {
104       CFX_ArrayTemplate<uint8_t> bytes;
105       CBC_UtilCodingConvert::LocaleToUtf8(splitResult.second, bytes);
106       AppendModeInfo(tempMode, &headerAndDataBits, e);
107       if (e != BCExceptionNO)
108         return;
109       AppendLengthInfo(bytes.GetSize(), qrCode->GetVersion(), tempMode,
110                        &headerAndDataBits, e);
111       if (e != BCExceptionNO)
112         return;
113       Append8BitBytes(bytes, &headerAndDataBits, e);
114       if (e != BCExceptionNO)
115         return;
116     } else if (tempMode == CBC_QRCoderMode::sALPHANUMERIC) {
117       AppendModeInfo(tempMode, &headerAndDataBits, e);
118       if (e != BCExceptionNO)
119         return;
120       AppendLengthInfo(splitResult.second.GetLength(), qrCode->GetVersion(),
121                        tempMode, &headerAndDataBits, e);
122       if (e != BCExceptionNO)
123         return;
124       AppendBytes(splitResult.second, tempMode, &headerAndDataBits, encoding,
125                   e);
126       if (e != BCExceptionNO)
127         return;
128     } else if (tempMode == CBC_QRCoderMode::sNUMERIC) {
129       AppendModeInfo(tempMode, &headerAndDataBits, e);
130       if (e != BCExceptionNO)
131         return;
132       AppendLengthInfo(splitResult.second.GetLength(), qrCode->GetVersion(),
133                        tempMode, &headerAndDataBits, e);
134       if (e != BCExceptionNO)
135         return;
136       AppendBytes(splitResult.second, tempMode, &headerAndDataBits, encoding,
137                   e);
138       if (e != BCExceptionNO)
139         return;
140     } else {
141       e = BCExceptionUnknown;
142       return;
143     }
144   }
145 }
146 
SplitString(const CFX_ByteString & content,std::vector<std::pair<CBC_QRCoderMode *,CFX_ByteString>> * result)147 void CBC_QRCoderEncoder::SplitString(
148     const CFX_ByteString& content,
149     std::vector<std::pair<CBC_QRCoderMode*, CFX_ByteString>>* result) {
150   int32_t index = 0, flag = 0;
151   while (
152       (((uint8_t)content[index] >= 0xA1 && (uint8_t)content[index] <= 0xAA) ||
153        ((uint8_t)content[index] >= 0xB0 && (uint8_t)content[index] <= 0xFA)) &&
154       (index < content.GetLength())) {
155     index += 2;
156   }
157   if (index != flag) {
158     result->push_back({CBC_QRCoderMode::sGBK, content.Mid(flag, index - flag)});
159   }
160   flag = index;
161   if (index >= content.GetLength()) {
162     return;
163   }
164   while (
165       GetAlphaNumericCode((uint8_t)content[index]) == -1 &&
166       !(((uint8_t)content[index] >= 0xA1 && (uint8_t)content[index] <= 0xAA) ||
167         ((uint8_t)content[index] >= 0xB0 && (uint8_t)content[index] <= 0xFA)) &&
168       (index < content.GetLength())) {
169 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
170     if (IsDBCSLeadByte((uint8_t)content[index]))
171 #else
172     if ((uint8_t)content[index] > 127)
173 #endif
174     {
175       index += 2;
176     } else {
177       index++;
178     }
179   }
180   if (index != flag) {
181     result->push_back(
182         {CBC_QRCoderMode::sBYTE, content.Mid(flag, index - flag)});
183   }
184   flag = index;
185   if (index >= content.GetLength()) {
186     return;
187   }
188   while (FXSYS_Isdigit((uint8_t)content[index]) &&
189          (index < content.GetLength())) {
190     index++;
191   }
192   if (index != flag) {
193     result->push_back(
194         {CBC_QRCoderMode::sNUMERIC, content.Mid(flag, index - flag)});
195   }
196   flag = index;
197   if (index >= content.GetLength()) {
198     return;
199   }
200   while (GetAlphaNumericCode((uint8_t)content[index]) != -1 &&
201          (index < content.GetLength())) {
202     index++;
203   }
204   if (index != flag) {
205     result->push_back(
206         {CBC_QRCoderMode::sALPHANUMERIC, content.Mid(flag, index - flag)});
207   }
208   flag = index;
209   if (index < content.GetLength())
210     SplitString(content.Mid(index, content.GetLength() - index), result);
211 }
212 
GetSpanByVersion(CBC_QRCoderMode * modeFirst,CBC_QRCoderMode * modeSecond,int32_t versionNum,int32_t & e)213 int32_t CBC_QRCoderEncoder::GetSpanByVersion(CBC_QRCoderMode* modeFirst,
214                                              CBC_QRCoderMode* modeSecond,
215                                              int32_t versionNum,
216                                              int32_t& e) {
217   if (versionNum == 0)
218     return 0;
219 
220   if (modeFirst == CBC_QRCoderMode::sALPHANUMERIC &&
221       modeSecond == CBC_QRCoderMode::sBYTE) {
222     if (versionNum >= 1 && versionNum <= 9)
223       return 11;
224     if (versionNum >= 10 && versionNum <= 26)
225       return 15;
226     if (versionNum >= 27 && versionNum <= 40)
227       return 16;
228     e = BCExceptionNoSuchVersion;
229     return 0;
230   }
231   if (modeSecond == CBC_QRCoderMode::sALPHANUMERIC &&
232       modeFirst == CBC_QRCoderMode::sNUMERIC) {
233     if (versionNum >= 1 && versionNum <= 9)
234       return 13;
235     if (versionNum >= 10 && versionNum <= 26)
236       return 15;
237     if (versionNum >= 27 && versionNum <= 40)
238       return 17;
239     e = BCExceptionNoSuchVersion;
240     return 0;
241   }
242   if (modeSecond == CBC_QRCoderMode::sBYTE &&
243       modeFirst == CBC_QRCoderMode::sNUMERIC) {
244     if (versionNum >= 1 && versionNum <= 9)
245       return 6;
246     if (versionNum >= 10 && versionNum <= 26)
247       return 8;
248     if (versionNum >= 27 && versionNum <= 40)
249       return 9;
250     e = BCExceptionNoSuchVersion;
251     return 0;
252   }
253   return -1;
254 }
255 
MergeString(std::vector<std::pair<CBC_QRCoderMode *,CFX_ByteString>> * result,int32_t versionNum,int32_t & e)256 void CBC_QRCoderEncoder::MergeString(
257     std::vector<std::pair<CBC_QRCoderMode*, CFX_ByteString>>* result,
258     int32_t versionNum,
259     int32_t& e) {
260   size_t mergeNum = 0;
261   for (size_t i = 0; i + 1 < result->size(); i++) {
262     auto element1 = &(*result)[i];
263     auto element2 = &(*result)[i + 1];
264     if (element1->first == CBC_QRCoderMode::sALPHANUMERIC) {
265       int32_t tmp = GetSpanByVersion(CBC_QRCoderMode::sALPHANUMERIC,
266                                      CBC_QRCoderMode::sBYTE, versionNum, e);
267       if (e != BCExceptionNO)
268         return;
269       if (element2->first == CBC_QRCoderMode::sBYTE &&
270           element1->second.GetLength() < tmp) {
271         element2->second = element1->second + element2->second;
272         result->erase(result->begin() + i);
273         i--;
274         mergeNum++;
275       }
276     } else if (element1->first == CBC_QRCoderMode::sBYTE) {
277       if (element2->first == CBC_QRCoderMode::sBYTE) {
278         element1->second += element2->second;
279         result->erase(result->begin() + i + 1);
280         i--;
281         mergeNum++;
282       }
283     } else if (element1->first == CBC_QRCoderMode::sNUMERIC) {
284       int32_t tmp = GetSpanByVersion(CBC_QRCoderMode::sNUMERIC,
285                                      CBC_QRCoderMode::sBYTE, versionNum, e);
286       if (e != BCExceptionNO)
287         return;
288       if (element2->first == CBC_QRCoderMode::sBYTE &&
289           element1->second.GetLength() < tmp) {
290         element2->second = element1->second + element2->second;
291         result->erase(result->begin() + i);
292         i--;
293         mergeNum++;
294       }
295       tmp = GetSpanByVersion(CBC_QRCoderMode::sNUMERIC,
296                              CBC_QRCoderMode::sALPHANUMERIC, versionNum, e);
297       if (e != BCExceptionNO)
298         return;
299       if (element2->first == CBC_QRCoderMode::sALPHANUMERIC &&
300           element1->second.GetLength() < tmp) {
301         element2->second = element1->second + element2->second;
302         result->erase(result->begin() + i);
303         i--;
304         mergeNum++;
305       }
306     }
307   }
308   if (mergeNum == 0) {
309     return;
310   }
311   MergeString(result, versionNum, e);
312   if (e != BCExceptionNO)
313     return;
314 }
315 
InitQRCode(int32_t numInputBytes,int32_t versionNumber,CBC_QRCoderErrorCorrectionLevel * ecLevel,CBC_QRCoderMode * mode,CBC_QRCoder * qrCode,int32_t & e)316 void CBC_QRCoderEncoder::InitQRCode(int32_t numInputBytes,
317                                     int32_t versionNumber,
318                                     CBC_QRCoderErrorCorrectionLevel* ecLevel,
319                                     CBC_QRCoderMode* mode,
320                                     CBC_QRCoder* qrCode,
321                                     int32_t& e) {
322   qrCode->SetECLevel(ecLevel);
323   qrCode->SetMode(mode);
324   CBC_QRCoderVersion* version =
325       CBC_QRCoderVersion::GetVersionForNumber(versionNumber, e);
326   if (e != BCExceptionNO)
327     return;
328   int32_t numBytes = version->GetTotalCodeWords();
329   CBC_QRCoderECBlocks* ecBlocks = version->GetECBlocksForLevel(ecLevel);
330   int32_t numEcBytes = ecBlocks->GetTotalECCodeWords();
331   int32_t numRSBlocks = ecBlocks->GetNumBlocks();
332   int32_t numDataBytes = numBytes - numEcBytes;
333   if (numDataBytes < numInputBytes + 3) {
334     e = BCExceptionCannotFindBlockInfo;
335     return;
336   }
337   qrCode->SetVersion(versionNumber);
338   qrCode->SetNumTotalBytes(numBytes);
339   qrCode->SetNumDataBytes(numDataBytes);
340   qrCode->SetNumRSBlocks(numRSBlocks);
341   qrCode->SetNumECBytes(numEcBytes);
342   qrCode->SetMatrixWidth(version->GetDimensionForVersion());
343 }
344 
EncodeWithSpecifyVersion(const CFX_ByteString & content,CBC_QRCoderErrorCorrectionLevel * ecLevel,CBC_QRCoder * qrCode,int32_t versionSpecify,int32_t & e)345 void CBC_QRCoderEncoder::EncodeWithSpecifyVersion(
346     const CFX_ByteString& content,
347     CBC_QRCoderErrorCorrectionLevel* ecLevel,
348     CBC_QRCoder* qrCode,
349     int32_t versionSpecify,
350     int32_t& e) {
351   CFX_ByteString encoding = "utf8";
352   CBC_QRCoderMode* mode = CBC_QRCoderMode::sBYTE;
353   std::vector<std::pair<CBC_QRCoderMode*, CFX_ByteString>> splitResult;
354   CBC_QRCoderBitVector dataBits;
355   dataBits.Init();
356   SplitString(content, &splitResult);
357   MergeString(&splitResult, versionSpecify, e);
358   if (e != BCExceptionNO)
359     return;
360   CBC_QRCoderMode* tempMode = nullptr;
361   for (const auto& result : splitResult) {
362     AppendBytes(result.second, result.first, &dataBits, encoding, e);
363     if (e != BCExceptionNO)
364       return;
365   }
366   int32_t numInputBytes = dataBits.sizeInBytes();
367   CBC_QRCoderBitVector headerAndDataBits;
368   headerAndDataBits.Init();
369   InitQRCode(numInputBytes, versionSpecify, ecLevel, mode, qrCode, e);
370   if (e != BCExceptionNO)
371     return;
372 
373   AppendDataModeLenghInfo(splitResult, headerAndDataBits, tempMode, qrCode,
374                           encoding, e);
375   if (e != BCExceptionNO)
376     return;
377 
378   numInputBytes = headerAndDataBits.sizeInBytes();
379   TerminateBits(qrCode->GetNumDataBytes(), &headerAndDataBits, e);
380   if (e != BCExceptionNO)
381     return;
382 
383   CBC_QRCoderBitVector finalBits;
384   finalBits.Init();
385   InterleaveWithECBytes(&headerAndDataBits, qrCode->GetNumTotalBytes(),
386                         qrCode->GetNumDataBytes(), qrCode->GetNumRSBlocks(),
387                         &finalBits, e);
388   if (e != BCExceptionNO)
389     return;
390 
391   std::unique_ptr<CBC_CommonByteMatrix> matrix(new CBC_CommonByteMatrix(
392       qrCode->GetMatrixWidth(), qrCode->GetMatrixWidth()));
393   matrix->Init();
394   int32_t maskPattern = ChooseMaskPattern(
395       &finalBits, qrCode->GetECLevel(), qrCode->GetVersion(), matrix.get(), e);
396   if (e != BCExceptionNO)
397     return;
398 
399   qrCode->SetMaskPattern(maskPattern);
400   CBC_QRCoderMatrixUtil::BuildMatrix(&finalBits, qrCode->GetECLevel(),
401                                      qrCode->GetVersion(),
402                                      qrCode->GetMaskPattern(), matrix.get(), e);
403   if (e != BCExceptionNO)
404     return;
405 
406   qrCode->SetMatrix(std::move(matrix));
407   if (!qrCode->IsValid())
408     e = BCExceptionInvalidQRCode;
409 }
410 
EncodeWithAutoVersion(const CFX_ByteString & content,CBC_QRCoderErrorCorrectionLevel * ecLevel,CBC_QRCoder * qrCode,int32_t & e)411 void CBC_QRCoderEncoder::EncodeWithAutoVersion(
412     const CFX_ByteString& content,
413     CBC_QRCoderErrorCorrectionLevel* ecLevel,
414     CBC_QRCoder* qrCode,
415     int32_t& e) {
416   CFX_ByteString encoding = "utf8";
417   CBC_QRCoderMode* mode = CBC_QRCoderMode::sBYTE;
418   std::vector<std::pair<CBC_QRCoderMode*, CFX_ByteString>> splitResult;
419   CBC_QRCoderBitVector dataBits;
420   dataBits.Init();
421   SplitString(content, &splitResult);
422   MergeString(&splitResult, 8, e);
423   if (e != BCExceptionNO)
424     return;
425   CBC_QRCoderMode* tempMode = nullptr;
426   for (const auto& result : splitResult) {
427     AppendBytes(result.second, result.first, &dataBits, encoding, e);
428     if (e != BCExceptionNO)
429       return;
430   }
431   int32_t numInputBytes = dataBits.sizeInBytes();
432   InitQRCode(numInputBytes, ecLevel, mode, qrCode, e);
433   if (e != BCExceptionNO)
434     return;
435   CBC_QRCoderBitVector headerAndDataBits;
436   headerAndDataBits.Init();
437   tempMode = nullptr;
438   int32_t versionNum = qrCode->GetVersion();
439 sign:
440   AppendDataModeLenghInfo(splitResult, headerAndDataBits, tempMode, qrCode,
441                           encoding, e);
442   if (e != BCExceptionNO) {
443     goto catchException;
444   }
445   numInputBytes = headerAndDataBits.sizeInBytes();
446   TerminateBits(qrCode->GetNumDataBytes(), &headerAndDataBits, e);
447   if (e != BCExceptionNO) {
448     goto catchException;
449   }
450 catchException:
451   if (e != BCExceptionNO) {
452     int32_t e1 = BCExceptionNO;
453     InitQRCode(numInputBytes, ecLevel, mode, qrCode, e1);
454     if (e1 != BCExceptionNO) {
455       e = e1;
456       return;
457     }
458     versionNum++;
459     if (versionNum <= 40) {
460       headerAndDataBits.Clear();
461       e = BCExceptionNO;
462       goto sign;
463     } else {
464       return;
465     }
466   }
467 
468   CBC_QRCoderBitVector finalBits;
469   finalBits.Init();
470   InterleaveWithECBytes(&headerAndDataBits, qrCode->GetNumTotalBytes(),
471                         qrCode->GetNumDataBytes(), qrCode->GetNumRSBlocks(),
472                         &finalBits, e);
473   if (e != BCExceptionNO)
474     return;
475 
476   std::unique_ptr<CBC_CommonByteMatrix> matrix(new CBC_CommonByteMatrix(
477       qrCode->GetMatrixWidth(), qrCode->GetMatrixWidth()));
478   matrix->Init();
479   int32_t maskPattern = ChooseMaskPattern(
480       &finalBits, qrCode->GetECLevel(), qrCode->GetVersion(), matrix.get(), e);
481   if (e != BCExceptionNO)
482     return;
483 
484   qrCode->SetMaskPattern(maskPattern);
485   CBC_QRCoderMatrixUtil::BuildMatrix(&finalBits, qrCode->GetECLevel(),
486                                      qrCode->GetVersion(),
487                                      qrCode->GetMaskPattern(), matrix.get(), e);
488   if (e != BCExceptionNO)
489     return qrCode->SetMatrix(std::move(matrix));
490 
491   if (!qrCode->IsValid())
492     e = BCExceptionInvalidQRCode;
493 }
494 
Encode(const CFX_WideString & content,CBC_QRCoderErrorCorrectionLevel * ecLevel,CBC_QRCoder * qrCode,int32_t & e)495 void CBC_QRCoderEncoder::Encode(const CFX_WideString& content,
496                                 CBC_QRCoderErrorCorrectionLevel* ecLevel,
497                                 CBC_QRCoder* qrCode,
498                                 int32_t& e) {
499   CFX_ByteString encoding = "utf8";
500   CFX_ByteString utf8Data;
501   CBC_UtilCodingConvert::UnicodeToUTF8(content, utf8Data);
502   CBC_QRCoderMode* mode = ChooseMode(utf8Data, encoding);
503   CBC_QRCoderBitVector dataBits;
504   dataBits.Init();
505   AppendBytes(utf8Data, mode, &dataBits, encoding, e);
506   if (e != BCExceptionNO)
507     return;
508   int32_t numInputBytes = dataBits.sizeInBytes();
509   InitQRCode(numInputBytes, ecLevel, mode, qrCode, e);
510   if (e != BCExceptionNO)
511     return;
512   CBC_QRCoderBitVector headerAndDataBits;
513   headerAndDataBits.Init();
514   AppendModeInfo(mode, &headerAndDataBits, e);
515   if (e != BCExceptionNO)
516     return;
517   int32_t numLetters = mode == CBC_QRCoderMode::sBYTE ? dataBits.sizeInBytes()
518                                                       : content.GetLength();
519   AppendLengthInfo(numLetters, qrCode->GetVersion(), mode, &headerAndDataBits,
520                    e);
521   if (e != BCExceptionNO)
522     return;
523   headerAndDataBits.AppendBitVector(&dataBits, e);
524   if (e != BCExceptionNO)
525     return TerminateBits(qrCode->GetNumDataBytes(), &headerAndDataBits, e);
526   if (e != BCExceptionNO)
527     return;
528   CBC_QRCoderBitVector finalBits;
529   finalBits.Init();
530   InterleaveWithECBytes(&headerAndDataBits, qrCode->GetNumTotalBytes(),
531                         qrCode->GetNumDataBytes(), qrCode->GetNumRSBlocks(),
532                         &finalBits, e);
533   if (e != BCExceptionNO)
534     return;
535 
536   std::unique_ptr<CBC_CommonByteMatrix> matrix(new CBC_CommonByteMatrix(
537       qrCode->GetMatrixWidth(), qrCode->GetMatrixWidth()));
538   matrix->Init();
539   int32_t maskPattern = ChooseMaskPattern(
540       &finalBits, qrCode->GetECLevel(), qrCode->GetVersion(), matrix.get(), e);
541   if (e != BCExceptionNO)
542     return;
543 
544   qrCode->SetMaskPattern(maskPattern);
545   CBC_QRCoderMatrixUtil::BuildMatrix(&finalBits, qrCode->GetECLevel(),
546                                      qrCode->GetVersion(),
547                                      qrCode->GetMaskPattern(), matrix.get(), e);
548   if (e != BCExceptionNO)
549     return qrCode->SetMatrix(std::move(matrix));
550 
551   if (!qrCode->IsValid())
552     e = BCExceptionInvalidQRCode;
553 }
554 
TerminateBits(int32_t numDataBytes,CBC_QRCoderBitVector * bits,int32_t & e)555 void CBC_QRCoderEncoder::TerminateBits(int32_t numDataBytes,
556                                        CBC_QRCoderBitVector* bits,
557                                        int32_t& e) {
558   int32_t capacity = numDataBytes << 3;
559   if (bits->Size() > capacity) {
560     e = BCExceptionDataTooMany;
561     return;
562   }
563   for (int32_t i = 0; i < 4 && bits->Size() < capacity; ++i) {
564     bits->AppendBit(0, e);
565     if (e != BCExceptionNO)
566       return;
567   }
568   int32_t numBitsInLastByte = bits->Size() % 8;
569   if (numBitsInLastByte > 0) {
570     int32_t numPaddingBits = 8 - numBitsInLastByte;
571     for (int32_t j = 0; j < numPaddingBits; ++j) {
572       bits->AppendBit(0, e);
573       if (e != BCExceptionNO)
574         return;
575     }
576   }
577   if (bits->Size() % 8 != 0) {
578     e = BCExceptionDigitLengthMustBe8;
579     return;
580   }
581   int32_t numPaddingBytes = numDataBytes - bits->sizeInBytes();
582   for (int32_t k = 0; k < numPaddingBytes; ++k) {
583     if (k % 2 == 0) {
584       bits->AppendBits(0xec, 8, e);
585       if (e != BCExceptionNO)
586         return;
587     } else {
588       bits->AppendBits(0x11, 8, e);
589       if (e != BCExceptionNO)
590         return;
591     }
592   }
593   if (bits->Size() != capacity)
594     e = BCExceptionBitsNotEqualCacity;
595 }
596 
ChooseMaskPattern(CBC_QRCoderBitVector * bits,CBC_QRCoderErrorCorrectionLevel * ecLevel,int32_t version,CBC_CommonByteMatrix * matrix,int32_t & e)597 int32_t CBC_QRCoderEncoder::ChooseMaskPattern(
598     CBC_QRCoderBitVector* bits,
599     CBC_QRCoderErrorCorrectionLevel* ecLevel,
600     int32_t version,
601     CBC_CommonByteMatrix* matrix,
602     int32_t& e) {
603   int32_t minPenalty = 65535;
604   int32_t bestMaskPattern = -1;
605   for (int32_t maskPattern = 0; maskPattern < CBC_QRCoder::kNumMaskPatterns;
606        maskPattern++) {
607     CBC_QRCoderMatrixUtil::BuildMatrix(bits, ecLevel, version, maskPattern,
608                                        matrix, e);
609     if (e != BCExceptionNO)
610       return 0;
611     int32_t penalty = CalculateMaskPenalty(matrix);
612     if (penalty < minPenalty) {
613       minPenalty = penalty;
614       bestMaskPattern = maskPattern;
615     }
616   }
617   return bestMaskPattern;
618 }
619 
CalculateMaskPenalty(CBC_CommonByteMatrix * matrix)620 int32_t CBC_QRCoderEncoder::CalculateMaskPenalty(CBC_CommonByteMatrix* matrix) {
621   int32_t penalty = 0;
622   penalty += CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule1(matrix);
623   penalty += CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule2(matrix);
624   penalty += CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule3(matrix);
625   penalty += CBC_QRCoderMaskUtil::ApplyMaskPenaltyRule4(matrix);
626   return penalty;
627 }
628 
ChooseMode(const CFX_ByteString & content,CFX_ByteString encoding)629 CBC_QRCoderMode* CBC_QRCoderEncoder::ChooseMode(const CFX_ByteString& content,
630                                                 CFX_ByteString encoding) {
631   if (encoding.Compare("SHIFT_JIS") == 0) {
632     return CBC_QRCoderMode::sKANJI;
633   }
634   bool hasNumeric = false;
635   bool hasAlphaNumeric = false;
636   for (int32_t i = 0; i < content.GetLength(); i++) {
637     if (isdigit((uint8_t)content[i])) {
638       hasNumeric = true;
639     } else if (GetAlphaNumericCode((uint8_t)content[i]) != -1) {
640       hasAlphaNumeric = true;
641     } else {
642       return CBC_QRCoderMode::sBYTE;
643     }
644   }
645   if (hasAlphaNumeric) {
646     return CBC_QRCoderMode::sALPHANUMERIC;
647   } else if (hasNumeric) {
648     return CBC_QRCoderMode::sNUMERIC;
649   }
650   return CBC_QRCoderMode::sBYTE;
651 }
652 
GetAlphaNumericCode(int32_t code)653 int32_t CBC_QRCoderEncoder::GetAlphaNumericCode(int32_t code) {
654   return (code >= 0 && code < 96) ? g_alphaNumericTable[code] : -1;
655 }
656 
AppendBytes(const CFX_ByteString & content,CBC_QRCoderMode * mode,CBC_QRCoderBitVector * bits,CFX_ByteString encoding,int32_t & e)657 void CBC_QRCoderEncoder::AppendBytes(const CFX_ByteString& content,
658                                      CBC_QRCoderMode* mode,
659                                      CBC_QRCoderBitVector* bits,
660                                      CFX_ByteString encoding,
661                                      int32_t& e) {
662   if (mode == CBC_QRCoderMode::sNUMERIC)
663     AppendNumericBytes(content, bits, e);
664   else if (mode == CBC_QRCoderMode::sALPHANUMERIC)
665     AppendAlphaNumericBytes(content, bits, e);
666   else if (mode == CBC_QRCoderMode::sBYTE)
667     Append8BitBytes(content, bits, encoding, e);
668   else if (mode == CBC_QRCoderMode::sKANJI)
669     AppendKanjiBytes(content, bits, e);
670   else if (mode == CBC_QRCoderMode::sGBK)
671     AppendGBKBytes(content, bits, e);
672   else
673     e = BCExceptionUnsupportedMode;
674 }
675 
AppendNumericBytes(const CFX_ByteString & content,CBC_QRCoderBitVector * bits,int32_t & e)676 void CBC_QRCoderEncoder::AppendNumericBytes(const CFX_ByteString& content,
677                                             CBC_QRCoderBitVector* bits,
678                                             int32_t& e) {
679   int32_t length = content.GetLength();
680   int32_t i = 0;
681   while (i < length) {
682     int32_t num1 = content[i] - '0';
683     if (i + 2 < length) {
684       int32_t num2 = content[i + 1] - '0';
685       int32_t num3 = content[i + 2] - '0';
686       bits->AppendBits(num1 * 100 + num2 * 10 + num3, 10, e);
687       if (e != BCExceptionNO)
688         return;
689       i += 3;
690     } else if (i + 1 < length) {
691       int32_t num2 = content[i + 1] - '0';
692       bits->AppendBits(num1 * 10 + num2, 7, e);
693       if (e != BCExceptionNO)
694         return;
695       i += 2;
696     } else {
697       bits->AppendBits(num1, 4, e);
698       if (e != BCExceptionNO)
699         return;
700       i++;
701     }
702   }
703 }
704 
AppendAlphaNumericBytes(const CFX_ByteString & content,CBC_QRCoderBitVector * bits,int32_t & e)705 void CBC_QRCoderEncoder::AppendAlphaNumericBytes(const CFX_ByteString& content,
706                                                  CBC_QRCoderBitVector* bits,
707                                                  int32_t& e) {
708   int32_t length = content.GetLength();
709   int32_t i = 0;
710   while (i < length) {
711     int32_t code1 = GetAlphaNumericCode(content[i]);
712     if (code1 == -1) {
713       e = BCExceptionInvalidateCharacter;
714       return;
715     }
716     if (i + 1 < length) {
717       int32_t code2 = GetAlphaNumericCode(content[i + 1]);
718       if (code2 == -1) {
719         e = BCExceptionInvalidateCharacter;
720         return;
721       }
722       bits->AppendBits(code1 * 45 + code2, 11, e);
723       if (e != BCExceptionNO)
724         return;
725       i += 2;
726     } else {
727       bits->AppendBits(code1, 6, e);
728       if (e != BCExceptionNO)
729         return;
730       i++;
731     }
732   }
733 }
734 
AppendGBKBytes(const CFX_ByteString & content,CBC_QRCoderBitVector * bits,int32_t & e)735 void CBC_QRCoderEncoder::AppendGBKBytes(const CFX_ByteString& content,
736                                         CBC_QRCoderBitVector* bits,
737                                         int32_t& e) {
738   int32_t length = content.GetLength();
739   uint32_t value = 0;
740   for (int32_t i = 0; i < length; i += 2) {
741     value = (uint32_t)((uint8_t)content[i] << 8 | (uint8_t)content[i + 1]);
742     if (value <= 0xAAFE && value >= 0xA1A1) {
743       value -= 0xA1A1;
744     } else if (value <= 0xFAFE && value >= 0xB0A1) {
745       value -= 0xA6A1;
746     } else {
747       e = BCExceptionInvalidateCharacter;
748       return;
749     }
750     value = (uint32_t)((value >> 8) * 0x60) + (uint32_t)(value & 0xff);
751     bits->AppendBits(value, 13, e);
752     if (e != BCExceptionNO)
753       return;
754   }
755 }
756 
Append8BitBytes(const CFX_ByteString & content,CBC_QRCoderBitVector * bits,CFX_ByteString encoding,int32_t & e)757 void CBC_QRCoderEncoder::Append8BitBytes(const CFX_ByteString& content,
758                                          CBC_QRCoderBitVector* bits,
759                                          CFX_ByteString encoding,
760                                          int32_t& e) {
761   for (int32_t i = 0; i < content.GetLength(); i++) {
762     bits->AppendBits(content[i], 8, e);
763     if (e != BCExceptionNO)
764       return;
765   }
766 }
767 
Append8BitBytes(CFX_ArrayTemplate<uint8_t> & bytes,CBC_QRCoderBitVector * bits,int32_t & e)768 void CBC_QRCoderEncoder::Append8BitBytes(CFX_ArrayTemplate<uint8_t>& bytes,
769                                          CBC_QRCoderBitVector* bits,
770                                          int32_t& e) {
771   for (int32_t i = 0; i < bytes.GetSize(); i++) {
772     bits->AppendBits(bytes[i], 8, e);
773     if (e != BCExceptionNO)
774       return;
775   }
776 }
777 
AppendKanjiBytes(const CFX_ByteString & content,CBC_QRCoderBitVector * bits,int32_t & e)778 void CBC_QRCoderEncoder::AppendKanjiBytes(const CFX_ByteString& content,
779                                           CBC_QRCoderBitVector* bits,
780                                           int32_t& e) {
781   CFX_ArrayTemplate<uint8_t> bytes;
782   uint32_t value = 0;
783   for (int32_t i = 0; i < bytes.GetSize(); i += 2) {
784     value = (uint32_t)((uint8_t)(content[i] << 8) | (uint8_t)content[i + 1]);
785     if (value <= 0x9ffc && value >= 0x8140) {
786       value -= 0x8140;
787     } else if (value <= 0xebbf && value >= 0xe040) {
788       value -= 0xc140;
789     } else {
790       e = BCExceptionInvalidateCharacter;
791       return;
792     }
793     value = (uint32_t)((value >> 8) * 0xc0) + (uint32_t)(value & 0xff);
794     bits->AppendBits(value, 13, e);
795     if (e != BCExceptionNO)
796       return;
797   }
798 }
799 
InitQRCode(int32_t numInputBytes,CBC_QRCoderErrorCorrectionLevel * ecLevel,CBC_QRCoderMode * mode,CBC_QRCoder * qrCode,int32_t & e)800 void CBC_QRCoderEncoder::InitQRCode(int32_t numInputBytes,
801                                     CBC_QRCoderErrorCorrectionLevel* ecLevel,
802                                     CBC_QRCoderMode* mode,
803                                     CBC_QRCoder* qrCode,
804                                     int32_t& e) {
805   qrCode->SetECLevel(ecLevel);
806   qrCode->SetMode(mode);
807   for (int32_t versionNum = 1; versionNum <= 40; versionNum++) {
808     CBC_QRCoderVersion* version =
809         CBC_QRCoderVersion::GetVersionForNumber(versionNum, e);
810     if (e != BCExceptionNO)
811       return;
812     int32_t numBytes = version->GetTotalCodeWords();
813     CBC_QRCoderECBlocks* ecBlocks = version->GetECBlocksForLevel(ecLevel);
814     int32_t numEcBytes = ecBlocks->GetTotalECCodeWords();
815     int32_t numRSBlocks = ecBlocks->GetNumBlocks();
816     int32_t numDataBytes = numBytes - numEcBytes;
817     if (numDataBytes >= numInputBytes + 3) {
818       qrCode->SetVersion(versionNum);
819       qrCode->SetNumTotalBytes(numBytes);
820       qrCode->SetNumDataBytes(numDataBytes);
821       qrCode->SetNumRSBlocks(numRSBlocks);
822       qrCode->SetNumECBytes(numEcBytes);
823       qrCode->SetMatrixWidth(version->GetDimensionForVersion());
824       return;
825     }
826   }
827   e = BCExceptionCannotFindBlockInfo;
828 }
829 
AppendModeInfo(CBC_QRCoderMode * mode,CBC_QRCoderBitVector * bits,int32_t & e)830 void CBC_QRCoderEncoder::AppendModeInfo(CBC_QRCoderMode* mode,
831                                         CBC_QRCoderBitVector* bits,
832                                         int32_t& e) {
833   bits->AppendBits(mode->GetBits(), 4, e);
834   if (mode == CBC_QRCoderMode::sGBK)
835     bits->AppendBits(1, 4, e);
836 }
837 
AppendLengthInfo(int32_t numLetters,int32_t version,CBC_QRCoderMode * mode,CBC_QRCoderBitVector * bits,int32_t & e)838 void CBC_QRCoderEncoder::AppendLengthInfo(int32_t numLetters,
839                                           int32_t version,
840                                           CBC_QRCoderMode* mode,
841                                           CBC_QRCoderBitVector* bits,
842                                           int32_t& e) {
843   CBC_QRCoderVersion* qcv = CBC_QRCoderVersion::GetVersionForNumber(version, e);
844   if (e != BCExceptionNO)
845     return;
846   int32_t numBits = mode->GetCharacterCountBits(qcv, e);
847   if (e != BCExceptionNO)
848     return;
849   if (numBits > ((1 << numBits) - 1)) {
850     return;
851   }
852   if (mode == CBC_QRCoderMode::sGBK) {
853     bits->AppendBits(numLetters / 2, numBits, e);
854     if (e != BCExceptionNO)
855       return;
856   }
857   bits->AppendBits(numLetters, numBits, e);
858 }
859 
InterleaveWithECBytes(CBC_QRCoderBitVector * bits,int32_t numTotalBytes,int32_t numDataBytes,int32_t numRSBlocks,CBC_QRCoderBitVector * result,int32_t & e)860 void CBC_QRCoderEncoder::InterleaveWithECBytes(CBC_QRCoderBitVector* bits,
861                                                int32_t numTotalBytes,
862                                                int32_t numDataBytes,
863                                                int32_t numRSBlocks,
864                                                CBC_QRCoderBitVector* result,
865                                                int32_t& e) {
866   if (bits->sizeInBytes() != numDataBytes) {
867     e = BCExceptionBitsBytesNotMatch;
868     return;
869   }
870   int32_t dataBytesOffset = 0;
871   int32_t maxNumDataBytes = 0;
872   int32_t maxNumEcBytes = 0;
873   CFX_ArrayTemplate<CBC_QRCoderBlockPair*> blocks;
874   int32_t i;
875   for (i = 0; i < numRSBlocks; i++) {
876     int32_t numDataBytesInBlock;
877     int32_t numEcBytesInBlosk;
878     GetNumDataBytesAndNumECBytesForBlockID(numTotalBytes, numDataBytes,
879                                            numRSBlocks, i, numDataBytesInBlock,
880                                            numEcBytesInBlosk);
881     std::unique_ptr<CBC_CommonByteArray> dataBytes(new CBC_CommonByteArray);
882     dataBytes->Set(bits->GetArray(), dataBytesOffset, numDataBytesInBlock);
883     std::unique_ptr<CBC_CommonByteArray> ecBytes(
884         GenerateECBytes(dataBytes.get(), numEcBytesInBlosk, e));
885     if (e != BCExceptionNO)
886       return;
887     maxNumDataBytes = std::max(maxNumDataBytes, dataBytes->Size());
888     maxNumEcBytes = std::max(maxNumEcBytes, ecBytes->Size());
889     blocks.Add(
890         new CBC_QRCoderBlockPair(std::move(dataBytes), std::move(ecBytes)));
891     dataBytesOffset += numDataBytesInBlock;
892   }
893   if (numDataBytes != dataBytesOffset) {
894     e = BCExceptionBytesNotMatchOffset;
895     return;
896   }
897   for (int32_t x = 0; x < maxNumDataBytes; x++) {
898     for (int32_t j = 0; j < blocks.GetSize(); j++) {
899       const CBC_CommonByteArray* dataBytes = blocks[j]->GetDataBytes();
900       if (x < dataBytes->Size()) {
901         result->AppendBits(dataBytes->At(x), 8, e);
902         if (e != BCExceptionNO)
903           return;
904       }
905     }
906   }
907   for (int32_t y = 0; y < maxNumEcBytes; y++) {
908     for (int32_t l = 0; l < blocks.GetSize(); l++) {
909       const CBC_CommonByteArray* ecBytes = blocks[l]->GetErrorCorrectionBytes();
910       if (y < ecBytes->Size()) {
911         result->AppendBits(ecBytes->At(y), 8, e);
912         if (e != BCExceptionNO)
913           return;
914       }
915     }
916   }
917   for (int32_t k = 0; k < blocks.GetSize(); k++) {
918     delete blocks[k];
919   }
920   if (numTotalBytes != result->sizeInBytes())
921     e = BCExceptionSizeInBytesDiffer;
922 }
923 
GetNumDataBytesAndNumECBytesForBlockID(int32_t numTotalBytes,int32_t numDataBytes,int32_t numRSBlocks,int32_t blockID,int32_t & numDataBytesInBlock,int32_t & numECBytesInBlock)924 void CBC_QRCoderEncoder::GetNumDataBytesAndNumECBytesForBlockID(
925     int32_t numTotalBytes,
926     int32_t numDataBytes,
927     int32_t numRSBlocks,
928     int32_t blockID,
929     int32_t& numDataBytesInBlock,
930     int32_t& numECBytesInBlock) {
931   if (blockID >= numRSBlocks) {
932     return;
933   }
934   int32_t numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
935   int32_t numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
936   int32_t numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
937   int32_t numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
938   int32_t numDataBytesInGroup1 = numDataBytes / numRSBlocks;
939   int32_t numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
940   int32_t numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
941   int32_t numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
942   if (blockID < numRsBlocksInGroup1) {
943     numDataBytesInBlock = numDataBytesInGroup1;
944     numECBytesInBlock = numEcBytesInGroup1;
945   } else {
946     numDataBytesInBlock = numDataBytesInGroup2;
947     numECBytesInBlock = numEcBytesInGroup2;
948   }
949 }
950 
GenerateECBytes(CBC_CommonByteArray * dataBytes,int32_t numEcBytesInBlock,int32_t & e)951 CBC_CommonByteArray* CBC_QRCoderEncoder::GenerateECBytes(
952     CBC_CommonByteArray* dataBytes,
953     int32_t numEcBytesInBlock,
954     int32_t& e) {
955   int32_t numDataBytes = dataBytes->Size();
956   CFX_ArrayTemplate<int32_t> toEncode;
957   toEncode.SetSize(numDataBytes + numEcBytesInBlock);
958   for (int32_t i = 0; i < numDataBytes; i++) {
959     toEncode[i] = (dataBytes->At(i));
960   }
961   CBC_ReedSolomonEncoder encode(CBC_ReedSolomonGF256::QRCodeField);
962   encode.Init();
963   encode.Encode(&toEncode, numEcBytesInBlock, e);
964   if (e != BCExceptionNO)
965     return nullptr;
966   CBC_CommonByteArray* ecBytes = new CBC_CommonByteArray(numEcBytesInBlock);
967   for (int32_t j = 0; j < numEcBytesInBlock; j++) {
968     ecBytes->Set(j, toEncode[numDataBytes + j]);
969   }
970   return ecBytes;
971 }
972