Home | History | Annotate | Download | only in qrcode
      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 
     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 }
     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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 
    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 
    308 bool CBC_QRCoderMatrixUtil::IsEmpty(int32_t value) {
    309   return (uint8_t)value == 0xff;
    310 }
    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 
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    505 CBC_QRCoderMatrixUtil::CBC_QRCoderMatrixUtil() {}
    506 CBC_QRCoderMatrixUtil::~CBC_QRCoderMatrixUtil() {}
    507