• 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/common/BC_CommonByteMatrix.h"
24 #include "xfa/fxbarcode/qrcode/BC_QRCoder.h"
25 #include "xfa/fxbarcode/qrcode/BC_QRCoderBitVector.h"
26 #include "xfa/fxbarcode/qrcode/BC_QRCoderErrorCorrectionLevel.h"
27 #include "xfa/fxbarcode/qrcode/BC_QRCoderMaskUtil.h"
28 #include "xfa/fxbarcode/qrcode/BC_QRCoderMatrixUtil.h"
29 #include "xfa/fxbarcode/utils.h"
30 
31 const int32_t CBC_QRCoderMatrixUtil::POSITION_DETECTION_PATTERN[7][7] = {
32     {1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 1}, {1, 0, 1, 1, 1, 0, 1},
33     {1, 0, 1, 1, 1, 0, 1}, {1, 0, 1, 1, 1, 0, 1}, {1, 0, 0, 0, 0, 0, 1},
34     {1, 1, 1, 1, 1, 1, 1}};
35 const int32_t CBC_QRCoderMatrixUtil::HORIZONTAL_SEPARATION_PATTERN[1][8] = {
36     {0, 0, 0, 0, 0, 0, 0, 0}};
37 const int32_t CBC_QRCoderMatrixUtil::VERTICAL_SEPARATION_PATTERN[7][1] = {
38     {0}, {0}, {0}, {0}, {0}, {0}, {0}};
39 const int32_t CBC_QRCoderMatrixUtil::POSITION_ADJUSTMENT_PATTERN[5][5] = {
40     {1, 1, 1, 1, 1},
41     {1, 0, 0, 0, 1},
42     {1, 0, 1, 0, 1},
43     {1, 0, 0, 0, 1},
44     {1, 1, 1, 1, 1}};
45 const int32_t
46     CBC_QRCoderMatrixUtil::POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[40][7] =
47         // NOLINTNEXTLINE
48     {
49         {-1, -1, -1, -1, -1, -1, -1},   {6, 18, -1, -1, -1, -1, -1},
50         {6, 22, -1, -1, -1, -1, -1},    {6, 26, -1, -1, -1, -1, -1},
51         {6, 30, -1, -1, -1, -1, -1},    {6, 34, -1, -1, -1, -1, -1},
52         {6, 22, 38, -1, -1, -1, -1},    {6, 24, 42, -1, -1, -1, -1},
53         {6, 26, 46, -1, -1, -1, -1},    {6, 28, 50, -1, -1, -1, -1},
54         {6, 30, 54, -1, -1, -1, -1},    {6, 32, 58, -1, -1, -1, -1},
55         {6, 34, 62, -1, -1, -1, -1},    {6, 26, 46, 66, -1, -1, -1},
56         {6, 26, 48, 70, -1, -1, -1},    {6, 26, 50, 74, -1, -1, -1},
57         {6, 30, 54, 78, -1, -1, -1},    {6, 30, 56, 82, -1, -1, -1},
58         {6, 30, 58, 86, -1, -1, -1},    {6, 34, 62, 90, -1, -1, -1},
59         {6, 28, 50, 72, 94, -1, -1},    {6, 26, 50, 74, 98, -1, -1},
60         {6, 30, 54, 78, 102, -1, -1},   {6, 28, 54, 80, 106, -1, -1},
61         {6, 32, 58, 84, 110, -1, -1},   {6, 30, 58, 86, 114, -1, -1},
62         {6, 34, 62, 90, 118, -1, -1},   {6, 26, 50, 74, 98, 122, -1},
63         {6, 30, 54, 78, 102, 126, -1},  {6, 26, 52, 78, 104, 130, -1},
64         {6, 30, 56, 82, 108, 134, -1},  {6, 34, 60, 86, 112, 138, -1},
65         {6, 30, 58, 86, 114, 142, -1},  {6, 34, 62, 90, 118, 146, -1},
66         {6, 30, 54, 78, 102, 126, 150}, {6, 24, 50, 76, 102, 128, 154},
67         {6, 28, 54, 80, 106, 132, 158}, {6, 32, 58, 84, 110, 136, 162},
68         {6, 26, 54, 82, 110, 138, 166}, {6, 30, 58, 86, 114, 142, 170},
69 };
70 const int32_t CBC_QRCoderMatrixUtil::TYPE_INFO_COORDINATES[15][2] = {
71     {8, 0}, {8, 1}, {8, 2}, {8, 3}, {8, 4}, {8, 5}, {8, 7}, {8, 8},
72     {7, 8}, {5, 8}, {4, 8}, {3, 8}, {2, 8}, {1, 8}, {0, 8},
73 };
74 const int32_t CBC_QRCoderMatrixUtil::VERSION_INFO_POLY = 0x1f25;
75 const int32_t CBC_QRCoderMatrixUtil::TYPE_INFO_POLY = 0x0537;
76 const int32_t CBC_QRCoderMatrixUtil::TYPE_INFO_MASK_PATTERN = 0x5412;
77 
ClearMatrix(CBC_CommonByteMatrix * matrix,int32_t & e)78 void CBC_QRCoderMatrixUtil::ClearMatrix(CBC_CommonByteMatrix* matrix,
79                                         int32_t& e) {
80   if (!matrix) {
81     e = BCExceptionNullPointer;
82     return;
83   }
84   matrix->clear((uint8_t)-1);
85 }
BuildMatrix(CBC_QRCoderBitVector * dataBits,CBC_QRCoderErrorCorrectionLevel * ecLevel,int32_t version,int32_t maskPattern,CBC_CommonByteMatrix * matrix,int32_t & e)86 void CBC_QRCoderMatrixUtil::BuildMatrix(
87     CBC_QRCoderBitVector* dataBits,
88     CBC_QRCoderErrorCorrectionLevel* ecLevel,
89     int32_t version,
90     int32_t maskPattern,
91     CBC_CommonByteMatrix* matrix,
92     int32_t& e) {
93   if (!matrix) {
94     e = BCExceptionNullPointer;
95     return;
96   }
97   ClearMatrix(matrix, e);
98   if (e != BCExceptionNO)
99     return;
100   EmbedBasicPatterns(version, matrix, e);
101   if (e != BCExceptionNO)
102     return;
103   EmbedTypeInfo(ecLevel, maskPattern, matrix, e);
104   if (e != BCExceptionNO)
105     return;
106   MaybeEmbedVersionInfo(version, matrix, e);
107   if (e != BCExceptionNO)
108     return;
109   EmbedDataBits(dataBits, maskPattern, matrix, e);
110   if (e != BCExceptionNO)
111     return;
112 }
EmbedBasicPatterns(int32_t version,CBC_CommonByteMatrix * matrix,int32_t & e)113 void CBC_QRCoderMatrixUtil::EmbedBasicPatterns(int32_t version,
114                                                CBC_CommonByteMatrix* matrix,
115                                                int32_t& e) {
116   if (!matrix) {
117     e = BCExceptionNullPointer;
118     return;
119   }
120   EmbedPositionDetectionPatternsAndSeparators(matrix, e);
121   if (e != BCExceptionNO)
122     return;
123   EmbedDarkDotAtLeftBottomCorner(matrix, e);
124   if (e != BCExceptionNO)
125     return;
126   MaybeEmbedPositionAdjustmentPatterns(version, matrix, e);
127   if (e != BCExceptionNO)
128     return;
129   EmbedTimingPatterns(matrix, e);
130   if (e != BCExceptionNO)
131     return;
132 }
EmbedTypeInfo(CBC_QRCoderErrorCorrectionLevel * ecLevel,int32_t maskPattern,CBC_CommonByteMatrix * matrix,int32_t & e)133 void CBC_QRCoderMatrixUtil::EmbedTypeInfo(
134     CBC_QRCoderErrorCorrectionLevel* ecLevel,
135     int32_t maskPattern,
136     CBC_CommonByteMatrix* matrix,
137     int32_t& e) {
138   if (!matrix) {
139     e = BCExceptionNullPointer;
140     return;
141   }
142   CBC_QRCoderBitVector typeInfoBits;
143   typeInfoBits.Init();
144   MakeTypeInfoBits(ecLevel, maskPattern, &typeInfoBits, e);
145   if (e != BCExceptionNO)
146     return;
147   for (int32_t i = 0; i < typeInfoBits.Size(); i++) {
148     int32_t bit = typeInfoBits.At(typeInfoBits.Size() - 1 - i, e);
149     if (e != BCExceptionNO)
150       return;
151     int32_t x1 = TYPE_INFO_COORDINATES[i][0];
152     int32_t y1 = TYPE_INFO_COORDINATES[i][1];
153     matrix->Set(x1, y1, bit);
154     if (i < 8) {
155       int32_t x2 = matrix->GetWidth() - i - 1;
156       int32_t y2 = 8;
157       matrix->Set(x2, y2, bit);
158     } else {
159       int32_t x2 = 8;
160       int32_t y2 = matrix->GetHeight() - 7 + (i - 8);
161       matrix->Set(x2, y2, bit);
162     }
163   }
164 }
MaybeEmbedVersionInfo(int32_t version,CBC_CommonByteMatrix * matrix,int32_t & e)165 void CBC_QRCoderMatrixUtil::MaybeEmbedVersionInfo(int32_t version,
166                                                   CBC_CommonByteMatrix* matrix,
167                                                   int32_t& e) {
168   if (!matrix) {
169     e = BCExceptionNullPointer;
170     return;
171   }
172   if (version < 7) {
173     return;
174   }
175   CBC_QRCoderBitVector versionInfoBits;
176   versionInfoBits.Init();
177   MakeVersionInfoBits(version, &versionInfoBits, e);
178   if (e != BCExceptionNO)
179     return;
180   int32_t bitIndex = 6 * 3 - 1;
181   for (int32_t i = 0; i < 6; i++) {
182     for (int32_t j = 0; j < 3; j++) {
183       int32_t bit = versionInfoBits.At(bitIndex, e);
184       if (e != BCExceptionNO)
185         return;
186       bitIndex--;
187       matrix->Set(i, matrix->GetHeight() - 11 + j, bit);
188       matrix->Set(matrix->GetHeight() - 11 + j, i, bit);
189     }
190   }
191 }
EmbedDataBits(CBC_QRCoderBitVector * dataBits,int32_t maskPattern,CBC_CommonByteMatrix * matrix,int32_t & e)192 void CBC_QRCoderMatrixUtil::EmbedDataBits(CBC_QRCoderBitVector* dataBits,
193                                           int32_t maskPattern,
194                                           CBC_CommonByteMatrix* matrix,
195                                           int32_t& e) {
196   if (!matrix || !dataBits) {
197     e = BCExceptionNullPointer;
198     return;
199   }
200   int32_t bitIndex = 0;
201   int32_t direction = -1;
202   int32_t x = matrix->GetWidth() - 1;
203   int32_t y = matrix->GetHeight() - 1;
204   while (x > 0) {
205     if (x == 6) {
206       x -= 1;
207     }
208     while (y >= 0 && y < matrix->GetHeight()) {
209       if (y == 6) {
210         y += direction;
211         continue;
212       }
213       for (int32_t i = 0; i < 2; i++) {
214         int32_t xx = x - i;
215         if (!IsEmpty(matrix->Get(xx, y))) {
216           continue;
217         }
218         int32_t bit;
219         if (bitIndex < dataBits->Size()) {
220           bit = dataBits->At(bitIndex, e);
221           if (e != BCExceptionNO)
222             return;
223           bitIndex++;
224         } else {
225           bit = 0;
226         }
227         if (maskPattern != -1) {
228           bool bol = CBC_QRCoderMaskUtil::GetDataMaskBit(maskPattern, xx, y, e);
229           if (e != BCExceptionNO)
230             return;
231           if (bol) {
232             bit ^= 0x01;
233           }
234         }
235         matrix->Set(xx, y, bit);
236       }
237       y += direction;
238     }
239     direction = -direction;
240     y += direction;
241     x -= 2;
242   }
243   if (bitIndex != dataBits->Size()) {
244     return;
245   }
246 }
CalculateBCHCode(int32_t value,int32_t poly)247 int32_t CBC_QRCoderMatrixUtil::CalculateBCHCode(int32_t value, int32_t poly) {
248   int32_t msbSetInPoly = FindMSBSet(poly);
249   value <<= msbSetInPoly - 1;
250   while (FindMSBSet(value) >= msbSetInPoly) {
251     value ^= poly << (FindMSBSet(value) - msbSetInPoly);
252   }
253   return value;
254 }
MakeTypeInfoBits(CBC_QRCoderErrorCorrectionLevel * ecLevel,int32_t maskPattern,CBC_QRCoderBitVector * bits,int32_t & e)255 void CBC_QRCoderMatrixUtil::MakeTypeInfoBits(
256     CBC_QRCoderErrorCorrectionLevel* ecLevel,
257     int32_t maskPattern,
258     CBC_QRCoderBitVector* bits,
259     int32_t& e) {
260   if (!bits) {
261     e = BCExceptionNullPointer;
262     return;
263   }
264   if (!CBC_QRCoder::IsValidMaskPattern(maskPattern)) {
265     e = BCExceptionBadMask;
266     return;
267   }
268   int32_t typeInfo = (ecLevel->GetBits() << 3) | maskPattern;
269   if (e != BCExceptionNO)
270     return;
271   bits->AppendBits(typeInfo, 5, e);
272   int32_t bchCode = CalculateBCHCode(typeInfo, TYPE_INFO_POLY);
273   if (e != BCExceptionNO)
274     return;
275   bits->AppendBits(bchCode, 10, e);
276   CBC_QRCoderBitVector maskBits;
277   maskBits.Init();
278   maskBits.AppendBits(TYPE_INFO_MASK_PATTERN, 15, e);
279   if (e != BCExceptionNO)
280     return;
281   bits->XOR(&maskBits, e);
282   if (e != BCExceptionNO)
283     return;
284   if (bits->Size() != 15)
285     e = BCExceptionBitSizeNot15;
286 }
287 
MakeVersionInfoBits(int32_t version,CBC_QRCoderBitVector * bits,int32_t & e)288 void CBC_QRCoderMatrixUtil::MakeVersionInfoBits(int32_t version,
289                                                 CBC_QRCoderBitVector* bits,
290                                                 int32_t& e) {
291   if (!bits) {
292     e = BCExceptionNullPointer;
293     return;
294   }
295   bits->AppendBits(version, 6, e);
296   if (e != BCExceptionNO)
297     return;
298 
299   int32_t bchCode = CalculateBCHCode(version, VERSION_INFO_POLY);
300   bits->AppendBits(bchCode, 12, e);
301   if (e != BCExceptionNO)
302     return;
303 
304   if (bits->Size() != 18)
305     e = BCExceptionBitSizeNot18;
306 }
307 
IsEmpty(int32_t value)308 bool CBC_QRCoderMatrixUtil::IsEmpty(int32_t value) {
309   return (uint8_t)value == 0xff;
310 }
IsValidValue(int32_t value)311 bool CBC_QRCoderMatrixUtil::IsValidValue(int32_t value) {
312   return ((uint8_t)value == 0xff || (uint8_t)value == 0x00 ||
313           (uint8_t)value == 0x01);
314 }
315 
EmbedTimingPatterns(CBC_CommonByteMatrix * matrix,int32_t & e)316 void CBC_QRCoderMatrixUtil::EmbedTimingPatterns(CBC_CommonByteMatrix* matrix,
317                                                 int32_t& e) {
318   if (!matrix) {
319     e = BCExceptionNullPointer;
320     return;
321   }
322   for (int32_t i = 8; i < matrix->GetWidth() - 8; i++) {
323     int32_t bit = (i + 1) % 2;
324     if (!IsValidValue(matrix->Get(i, 6))) {
325       e = BCExceptionInvalidateImageData;
326       return;
327     }
328     if (IsEmpty(matrix->Get(i, 6))) {
329       matrix->Set(i, 6, bit);
330     }
331     if (!IsValidValue(matrix->Get(6, i))) {
332       e = BCExceptionInvalidateImageData;
333       return;
334     }
335     if (IsEmpty(matrix->Get(6, i))) {
336       matrix->Set(6, i, bit);
337     }
338   }
339 }
EmbedDarkDotAtLeftBottomCorner(CBC_CommonByteMatrix * matrix,int32_t & e)340 void CBC_QRCoderMatrixUtil::EmbedDarkDotAtLeftBottomCorner(
341     CBC_CommonByteMatrix* matrix,
342     int32_t& e) {
343   if (!matrix) {
344     e = BCExceptionNullPointer;
345     return;
346   }
347   if (matrix->Get(8, matrix->GetHeight() - 8) == 0) {
348     e = BCExceptionHeight_8BeZero;
349     return;
350   }
351   matrix->Set(8, matrix->GetHeight() - 8, 1);
352 }
EmbedHorizontalSeparationPattern(int32_t xStart,int32_t yStart,CBC_CommonByteMatrix * matrix,int32_t & e)353 void CBC_QRCoderMatrixUtil::EmbedHorizontalSeparationPattern(
354     int32_t xStart,
355     int32_t yStart,
356     CBC_CommonByteMatrix* matrix,
357     int32_t& e) {
358   if (!matrix) {
359     e = BCExceptionNullPointer;
360     return;
361   }
362   for (int32_t x = 0; x < 8; x++) {
363     if (!IsEmpty(matrix->Get(xStart + x, yStart))) {
364       e = BCExceptionInvalidateData;
365       return;
366     }
367     matrix->Set(xStart + x, yStart, HORIZONTAL_SEPARATION_PATTERN[0][x]);
368   }
369 }
EmbedVerticalSeparationPattern(int32_t xStart,int32_t yStart,CBC_CommonByteMatrix * matrix,int32_t & e)370 void CBC_QRCoderMatrixUtil::EmbedVerticalSeparationPattern(
371     int32_t xStart,
372     int32_t yStart,
373     CBC_CommonByteMatrix* matrix,
374     int32_t& e) {
375   if (!matrix) {
376     e = BCExceptionNullPointer;
377     return;
378   }
379   for (int32_t y = 0; y < 7; y++) {
380     if (!IsEmpty(matrix->Get(xStart, yStart + y))) {
381       e = BCExceptionInvalidateData;
382       return;
383     }
384     matrix->Set(xStart, yStart + y, VERTICAL_SEPARATION_PATTERN[y][0]);
385   }
386 }
EmbedPositionAdjustmentPattern(int32_t xStart,int32_t yStart,CBC_CommonByteMatrix * matrix,int32_t & e)387 void CBC_QRCoderMatrixUtil::EmbedPositionAdjustmentPattern(
388     int32_t xStart,
389     int32_t yStart,
390     CBC_CommonByteMatrix* matrix,
391     int32_t& e) {
392   if (!matrix) {
393     e = BCExceptionNullPointer;
394     if (e != BCExceptionNO)
395       return;
396   }
397   for (int32_t y = 0; y < 5; y++) {
398     for (int32_t x = 0; x < 5; x++) {
399       if (!IsEmpty(matrix->Get(xStart + x, y + yStart))) {
400         e = BCExceptionInvalidateData;
401         return;
402       }
403       matrix->Set(xStart + x, yStart + y, POSITION_ADJUSTMENT_PATTERN[y][x]);
404     }
405   }
406 }
EmbedPositionDetectionPattern(int32_t xStart,int32_t yStart,CBC_CommonByteMatrix * matrix,int32_t & e)407 void CBC_QRCoderMatrixUtil::EmbedPositionDetectionPattern(
408     int32_t xStart,
409     int32_t yStart,
410     CBC_CommonByteMatrix* matrix,
411     int32_t& e) {
412   if (!matrix) {
413     e = BCExceptionNullPointer;
414     return;
415   }
416   for (int32_t y = 0; y < 7; y++) {
417     for (int32_t x = 0; x < 7; x++) {
418       if (!IsEmpty(matrix->Get(xStart + x, yStart + y))) {
419         e = BCExceptionInvalidateData;
420         return;
421       }
422       matrix->Set(xStart + x, yStart + y, POSITION_DETECTION_PATTERN[y][x]);
423     }
424   }
425 }
EmbedPositionDetectionPatternsAndSeparators(CBC_CommonByteMatrix * matrix,int32_t & e)426 void CBC_QRCoderMatrixUtil::EmbedPositionDetectionPatternsAndSeparators(
427     CBC_CommonByteMatrix* matrix,
428     int32_t& e) {
429   if (!matrix) {
430     e = BCExceptionNullPointer;
431     return;
432   }
433   int32_t pdpWidth = 7;
434   EmbedPositionDetectionPattern(0, 0, matrix, e);
435   if (e != BCExceptionNO)
436     return;
437   EmbedPositionDetectionPattern(matrix->GetWidth() - pdpWidth, 0, matrix, e);
438   if (e != BCExceptionNO)
439     return;
440   EmbedPositionDetectionPattern(0, matrix->GetWidth() - pdpWidth, matrix, e);
441   if (e != BCExceptionNO)
442     return;
443   int32_t hspWidth = 8;
444   EmbedHorizontalSeparationPattern(0, hspWidth - 1, matrix, e);
445   if (e != BCExceptionNO)
446     return;
447   EmbedHorizontalSeparationPattern(matrix->GetWidth() - hspWidth, hspWidth - 1,
448                                    matrix, e);
449   if (e != BCExceptionNO)
450     return;
451   EmbedHorizontalSeparationPattern(0, matrix->GetWidth() - hspWidth, matrix, e);
452   if (e != BCExceptionNO)
453     return;
454   int32_t vspSize = 7;
455   EmbedVerticalSeparationPattern(vspSize, 0, matrix, e);
456   if (e != BCExceptionNO)
457     return;
458   EmbedVerticalSeparationPattern(matrix->GetHeight() - vspSize - 1, 0, matrix,
459                                  e);
460   if (e != BCExceptionNO)
461     return;
462   EmbedVerticalSeparationPattern(vspSize, matrix->GetHeight() - vspSize, matrix,
463                                  e);
464   if (e != BCExceptionNO)
465     return;
466 }
MaybeEmbedPositionAdjustmentPatterns(int32_t version,CBC_CommonByteMatrix * matrix,int32_t & e)467 void CBC_QRCoderMatrixUtil::MaybeEmbedPositionAdjustmentPatterns(
468     int32_t version,
469     CBC_CommonByteMatrix* matrix,
470     int32_t& e) {
471   if (!matrix) {
472     e = BCExceptionNullPointer;
473     return;
474   }
475   if (version < 2) {
476     return;
477   }
478   int32_t index = version - 1;
479   int32_t const* coordinates =
480       &(POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index][0]);
481   int32_t numCoordinate = 7;
482   for (int32_t i = 0; i < numCoordinate; i++) {
483     for (int32_t j = 0; j < numCoordinate; j++) {
484       int32_t y = coordinates[i];
485       int32_t x = coordinates[j];
486       if (x == -1 || y == -1) {
487         continue;
488       }
489       if (IsEmpty(matrix->Get(x, y))) {
490         EmbedPositionAdjustmentPattern(x - 2, y - 2, matrix, e);
491         if (e != BCExceptionNO)
492           return;
493       }
494     }
495   }
496 }
FindMSBSet(int32_t value)497 int32_t CBC_QRCoderMatrixUtil::FindMSBSet(int32_t value) {
498   int32_t numDigits = 0;
499   while (value != 0) {
500     value >>= 1;
501     ++numDigits;
502   }
503   return numDigits;
504 }
CBC_QRCoderMatrixUtil()505 CBC_QRCoderMatrixUtil::CBC_QRCoderMatrixUtil() {}
~CBC_QRCoderMatrixUtil()506 CBC_QRCoderMatrixUtil::~CBC_QRCoderMatrixUtil() {}
507