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