diff --git a/src/lib.rs b/src/lib.rs index 04ff633..9540ae5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ pub mod client; pub mod common; mod exceptions; pub mod qrcode; +pub mod maxicode; pub use exceptions::Exceptions; diff --git a/src/maxicode/decoder/BitMatrixParser.java b/src/maxicode/decoder/BitMatrixParser.java deleted file mode 100644 index fe154b3..0000000 --- a/src/maxicode/decoder/BitMatrixParser.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2011 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.maxicode.decoder; - -import com.google.zxing.common.BitMatrix; - -/** - * @author mike32767 - * @author Manuel Kasten - */ -final class BitMatrixParser { - - @SuppressWarnings("checkstyle:lineLength") - private static final int[][] BITNR = { - {121,120,127,126,133,132,139,138,145,144,151,150,157,156,163,162,169,168,175,174,181,180,187,186,193,192,199,198, -2, -2}, - {123,122,129,128,135,134,141,140,147,146,153,152,159,158,165,164,171,170,177,176,183,182,189,188,195,194,201,200,816, -3}, - {125,124,131,130,137,136,143,142,149,148,155,154,161,160,167,166,173,172,179,178,185,184,191,190,197,196,203,202,818,817}, - {283,282,277,276,271,270,265,264,259,258,253,252,247,246,241,240,235,234,229,228,223,222,217,216,211,210,205,204,819, -3}, - {285,284,279,278,273,272,267,266,261,260,255,254,249,248,243,242,237,236,231,230,225,224,219,218,213,212,207,206,821,820}, - {287,286,281,280,275,274,269,268,263,262,257,256,251,250,245,244,239,238,233,232,227,226,221,220,215,214,209,208,822, -3}, - {289,288,295,294,301,300,307,306,313,312,319,318,325,324,331,330,337,336,343,342,349,348,355,354,361,360,367,366,824,823}, - {291,290,297,296,303,302,309,308,315,314,321,320,327,326,333,332,339,338,345,344,351,350,357,356,363,362,369,368,825, -3}, - {293,292,299,298,305,304,311,310,317,316,323,322,329,328,335,334,341,340,347,346,353,352,359,358,365,364,371,370,827,826}, - {409,408,403,402,397,396,391,390, 79, 78, -2, -2, 13, 12, 37, 36, 2, -1, 44, 43,109,108,385,384,379,378,373,372,828, -3}, - {411,410,405,404,399,398,393,392, 81, 80, 40, -2, 15, 14, 39, 38, 3, -1, -1, 45,111,110,387,386,381,380,375,374,830,829}, - {413,412,407,406,401,400,395,394, 83, 82, 41, -3, -3, -3, -3, -3, 5, 4, 47, 46,113,112,389,388,383,382,377,376,831, -3}, - {415,414,421,420,427,426,103,102, 55, 54, 16, -3, -3, -3, -3, -3, -3, -3, 20, 19, 85, 84,433,432,439,438,445,444,833,832}, - {417,416,423,422,429,428,105,104, 57, 56, -3, -3, -3, -3, -3, -3, -3, -3, 22, 21, 87, 86,435,434,441,440,447,446,834, -3}, - {419,418,425,424,431,430,107,106, 59, 58, -3, -3, -3, -3, -3, -3, -3, -3, -3, 23, 89, 88,437,436,443,442,449,448,836,835}, - {481,480,475,474,469,468, 48, -2, 30, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 0, 53, 52,463,462,457,456,451,450,837, -3}, - {483,482,477,476,471,470, 49, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -1,465,464,459,458,453,452,839,838}, - {485,484,479,478,473,472, 51, 50, 31, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 1, -2, 42,467,466,461,460,455,454,840, -3}, - {487,486,493,492,499,498, 97, 96, 61, 60, -3, -3, -3, -3, -3, -3, -3, -3, -3, 26, 91, 90,505,504,511,510,517,516,842,841}, - {489,488,495,494,501,500, 99, 98, 63, 62, -3, -3, -3, -3, -3, -3, -3, -3, 28, 27, 93, 92,507,506,513,512,519,518,843, -3}, - {491,490,497,496,503,502,101,100, 65, 64, 17, -3, -3, -3, -3, -3, -3, -3, 18, 29, 95, 94,509,508,515,514,521,520,845,844}, - {559,558,553,552,547,546,541,540, 73, 72, 32, -3, -3, -3, -3, -3, -3, 10, 67, 66,115,114,535,534,529,528,523,522,846, -3}, - {561,560,555,554,549,548,543,542, 75, 74, -2, -1, 7, 6, 35, 34, 11, -2, 69, 68,117,116,537,536,531,530,525,524,848,847}, - {563,562,557,556,551,550,545,544, 77, 76, -2, 33, 9, 8, 25, 24, -1, -2, 71, 70,119,118,539,538,533,532,527,526,849, -3}, - {565,564,571,570,577,576,583,582,589,588,595,594,601,600,607,606,613,612,619,618,625,624,631,630,637,636,643,642,851,850}, - {567,566,573,572,579,578,585,584,591,590,597,596,603,602,609,608,615,614,621,620,627,626,633,632,639,638,645,644,852, -3}, - {569,568,575,574,581,580,587,586,593,592,599,598,605,604,611,610,617,616,623,622,629,628,635,634,641,640,647,646,854,853}, - {727,726,721,720,715,714,709,708,703,702,697,696,691,690,685,684,679,678,673,672,667,666,661,660,655,654,649,648,855, -3}, - {729,728,723,722,717,716,711,710,705,704,699,698,693,692,687,686,681,680,675,674,669,668,663,662,657,656,651,650,857,856}, - {731,730,725,724,719,718,713,712,707,706,701,700,695,694,689,688,683,682,677,676,671,670,665,664,659,658,653,652,858, -3}, - {733,732,739,738,745,744,751,750,757,756,763,762,769,768,775,774,781,780,787,786,793,792,799,798,805,804,811,810,860,859}, - {735,734,741,740,747,746,753,752,759,758,765,764,771,770,777,776,783,782,789,788,795,794,801,800,807,806,813,812,861, -3}, - {737,736,743,742,749,748,755,754,761,760,767,766,773,772,779,778,785,784,791,790,797,796,803,802,809,808,815,814,863,862} - }; - - private final BitMatrix bitMatrix; - - /** - * @param bitMatrix {@link BitMatrix} to parse - */ - BitMatrixParser(BitMatrix bitMatrix) { - this.bitMatrix = bitMatrix; - } - - byte[] readCodewords() { - byte[] result = new byte[144]; - int height = bitMatrix.getHeight(); - int width = bitMatrix.getWidth(); - for (int y = 0; y < height; y++) { - int[] bitnrRow = BITNR[y]; - for (int x = 0; x < width; x++) { - int bit = bitnrRow[x]; - if (bit >= 0 && bitMatrix.get(x, y)) { - result[bit / 6] |= (byte) (1 << (5 - (bit % 6))); - } - } - } - return result; - } - -} diff --git a/src/maxicode/decoder/DecodedBitStreamParser.java b/src/maxicode/decoder/DecodedBitStreamParser.java deleted file mode 100644 index 486b838..0000000 --- a/src/maxicode/decoder/DecodedBitStreamParser.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2011 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.maxicode.decoder; - -import com.google.zxing.FormatException; -import com.google.zxing.common.DecoderRXingResult; -import java.text.DecimalFormat; -import java.text.NumberFormat; - -/** - *

MaxiCodes can encode text or structured information as bits in one of several modes, - * with multiple character sets in one code. This class decodes the bits back into text.

- * - * @author mike32767 - * @author Manuel Kasten - */ -final class DecodedBitStreamParser { - - private static final char SHIFTA = '\uFFF0'; - private static final char SHIFTB = '\uFFF1'; - private static final char SHIFTC = '\uFFF2'; - private static final char SHIFTD = '\uFFF3'; - private static final char SHIFTE = '\uFFF4'; - private static final char TWOSHIFTA = '\uFFF5'; - private static final char THREESHIFTA = '\uFFF6'; - private static final char LATCHA = '\uFFF7'; - private static final char LATCHB = '\uFFF8'; - private static final char LOCK = '\uFFF9'; - private static final char ECI = '\uFFFA'; - private static final char NS = '\uFFFB'; - private static final char PAD = '\uFFFC'; - private static final char FS = '\u001C'; - private static final char GS = '\u001D'; - private static final char RS = '\u001E'; - private static final byte[] COUNTRY_BYTES = { 53, 54, 43, 44, 45, 46, 47, 48, 37, 38 }; - private static final byte[] SERVICE_CLASS_BYTES = { 55, 56, 57, 58, 59, 60, 49, 50, 51, 52 }; - private static final byte[] POSTCODE_2_LENGTH_BYTES = { 39, 40, 41, 42, 31, 32 }; - private static final byte[] POSTCODE_2_BYTES = { 33, 34, 35, 36, 25, 26, 27, 28, 29, 30, 19, - 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 1, 2 }; - private static final byte[][] POSTCODE_3_BYTES = { - { 39, 40, 41, 42, 31, 32}, - { 33, 34, 35, 36, 25, 26}, - { 27, 28, 29, 30, 19, 20}, - { 21, 22, 23, 24, 13, 14}, - { 15, 16, 17, 18, 7, 8}, - { 9, 10, 11, 12, 1, 2} - }; - - @SuppressWarnings("checkstyle:lineLength") - private static final String[] SETS = { - "\rABCDEFGHIJKLMNOPQRSTUVWXYZ" + ECI + FS + GS + RS + NS + ' ' + PAD + - "\"#$%&'()*+,-./0123456789:" + SHIFTB + SHIFTC + SHIFTD + SHIFTE + LATCHB, - "`abcdefghijklmnopqrstuvwxyz" + ECI + FS + GS + RS + NS + '{' + PAD + - "}~\u007F;<=>?[\\]^_ ,./:@!|" + PAD + TWOSHIFTA + THREESHIFTA + PAD + - SHIFTA + SHIFTC + SHIFTD + SHIFTE + LATCHA, - "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7\u00D8\u00D9\u00DA" + - ECI + FS + GS + RS + NS + - "\u00DB\u00DC\u00DD\u00DE\u00DF\u00AA\u00AC\u00B1\u00B2\u00B3\u00B5\u00B9\u00BA\u00BC\u00BD\u00BE\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089" + - LATCHA + ' ' + LOCK + SHIFTD + SHIFTE + LATCHB, - "\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7\u00F8\u00F9\u00FA" + - ECI + FS + GS + RS + NS + - "\u00FB\u00FC\u00FD\u00FE\u00FF\u00A1\u00A8\u00AB\u00AF\u00B0\u00B4\u00B7\u00B8\u00BB\u00BF\u008A\u008B\u008C\u008D\u008E\u008F\u0090\u0091\u0092\u0093\u0094" + - LATCHA + ' ' + SHIFTC + LOCK + SHIFTE + LATCHB, - "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000B\u000C\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A" + - ECI + PAD + PAD + '\u001B' + NS + FS + GS + RS + - "\u001F\u009F\u00A0\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7\u00A9\u00AD\u00AE\u00B6\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009D\u009E" + - LATCHA + ' ' + SHIFTC + SHIFTD + LOCK + LATCHB, - }; - - private DecodedBitStreamParser() { - } - - static DecoderRXingResult decode(byte[] bytes, int mode) throws FormatException { - StringBuilder result = new StringBuilder(144); - switch (mode) { - case 2: - case 3: - String postcode; - if (mode == 2) { - int pc = getPostCode2(bytes); - int ps2Length = getPostCode2Length(bytes); - if (ps2Length > 10) { - throw FormatException.getFormatInstance(); - } - NumberFormat df = new DecimalFormat("0000000000".substring(0, ps2Length)); - postcode = df.format(pc); - } else { - postcode = getPostCode3(bytes); - } - NumberFormat threeDigits = new DecimalFormat("000"); - String country = threeDigits.format(getCountry(bytes)); - String service = threeDigits.format(getServiceClass(bytes)); - result.append(getMessage(bytes, 10, 84)); - if (result.toString().startsWith("[)>" + RS + "01" + GS)) { - result.insert(9, postcode + GS + country + GS + service + GS); - } else { - result.insert(0, postcode + GS + country + GS + service + GS); - } - break; - case 4: - result.append(getMessage(bytes, 1, 93)); - break; - case 5: - result.append(getMessage(bytes, 1, 77)); - break; - } - return new DecoderRXingResult(bytes, result.toString(), null, String.valueOf(mode)); - } - - private static int getBit(int bit, byte[] bytes) { - bit--; - return (bytes[bit / 6] & (1 << (5 - (bit % 6)))) == 0 ? 0 : 1; - } - - private static int getInt(byte[] bytes, byte[] x) { - int val = 0; - for (int i = 0; i < x.length; i++) { - val += getBit(x[i], bytes) << (x.length - i - 1); - } - return val; - } - - private static int getCountry(byte[] bytes) { - return getInt(bytes, COUNTRY_BYTES); - } - - private static int getServiceClass(byte[] bytes) { - return getInt(bytes, SERVICE_CLASS_BYTES); - } - - private static int getPostCode2Length(byte[] bytes) { - return getInt(bytes, POSTCODE_2_LENGTH_BYTES); - } - - private static int getPostCode2(byte[] bytes) { - return getInt(bytes, POSTCODE_2_BYTES); - } - - private static String getPostCode3(byte[] bytes) { - StringBuilder sb = new StringBuilder(POSTCODE_3_BYTES.length); - for (byte[] p3bytes : POSTCODE_3_BYTES) { - sb.append(SETS[0].charAt(getInt(bytes, p3bytes))); - } - return sb.toString(); - } - - private static String getMessage(byte[] bytes, int start, int len) { - StringBuilder sb = new StringBuilder(); - int shift = -1; - int set = 0; - int lastset = 0; - for (int i = start; i < start + len; i++) { - char c = SETS[set].charAt(bytes[i]); - switch (c) { - case LATCHA: - set = 0; - shift = -1; - break; - case LATCHB: - set = 1; - shift = -1; - break; - case SHIFTA: - case SHIFTB: - case SHIFTC: - case SHIFTD: - case SHIFTE: - lastset = set; - set = c - SHIFTA; - shift = 1; - break; - case TWOSHIFTA: - lastset = set; - set = 0; - shift = 2; - break; - case THREESHIFTA: - lastset = set; - set = 0; - shift = 3; - break; - case NS: - int nsval = (bytes[++i] << 24) + (bytes[++i] << 18) + (bytes[++i] << 12) + (bytes[++i] << 6) + bytes[++i]; - sb.append(new DecimalFormat("000000000").format(nsval)); - break; - case LOCK: - shift = -1; - break; - default: - sb.append(c); - } - if (shift-- == 0) { - set = lastset; - } - } - while (sb.length() > 0 && sb.charAt(sb.length() - 1) == PAD) { - sb.setLength(sb.length() - 1); - } - return sb.toString(); - } - -} diff --git a/src/maxicode/decoder/bit_matrix_parser.rs b/src/maxicode/decoder/bit_matrix_parser.rs new file mode 100644 index 0000000..757585a --- /dev/null +++ b/src/maxicode/decoder/bit_matrix_parser.rs @@ -0,0 +1,88 @@ +/* + * Copyright 2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::common::BitMatrix; + +const BITNR : [[i16;30];33] = [ + [121,120,127,126,133,132,139,138,145,144,151,150,157,156,163,162,169,168,175,174,181,180,187,186,193,192,199,198, -2, -2], + [123,122,129,128,135,134,141,140,147,146,153,152,159,158,165,164,171,170,177,176,183,182,189,188,195,194,201,200,816, -3], + [125,124,131,130,137,136,143,142,149,148,155,154,161,160,167,166,173,172,179,178,185,184,191,190,197,196,203,202,818,817], + [283,282,277,276,271,270,265,264,259,258,253,252,247,246,241,240,235,234,229,228,223,222,217,216,211,210,205,204,819, -3], + [285,284,279,278,273,272,267,266,261,260,255,254,249,248,243,242,237,236,231,230,225,224,219,218,213,212,207,206,821,820], + [287,286,281,280,275,274,269,268,263,262,257,256,251,250,245,244,239,238,233,232,227,226,221,220,215,214,209,208,822, -3], + [289,288,295,294,301,300,307,306,313,312,319,318,325,324,331,330,337,336,343,342,349,348,355,354,361,360,367,366,824,823], + [291,290,297,296,303,302,309,308,315,314,321,320,327,326,333,332,339,338,345,344,351,350,357,356,363,362,369,368,825, -3], + [293,292,299,298,305,304,311,310,317,316,323,322,329,328,335,334,341,340,347,346,353,352,359,358,365,364,371,370,827,826], + [409,408,403,402,397,396,391,390, 79, 78, -2, -2, 13, 12, 37, 36, 2, -1, 44, 43,109,108,385,384,379,378,373,372,828, -3], + [411,410,405,404,399,398,393,392, 81, 80, 40, -2, 15, 14, 39, 38, 3, -1, -1, 45,111,110,387,386,381,380,375,374,830,829], + [413,412,407,406,401,400,395,394, 83, 82, 41, -3, -3, -3, -3, -3, 5, 4, 47, 46,113,112,389,388,383,382,377,376,831, -3], + [415,414,421,420,427,426,103,102, 55, 54, 16, -3, -3, -3, -3, -3, -3, -3, 20, 19, 85, 84,433,432,439,438,445,444,833,832], + [417,416,423,422,429,428,105,104, 57, 56, -3, -3, -3, -3, -3, -3, -3, -3, 22, 21, 87, 86,435,434,441,440,447,446,834, -3], + [419,418,425,424,431,430,107,106, 59, 58, -3, -3, -3, -3, -3, -3, -3, -3, -3, 23, 89, 88,437,436,443,442,449,448,836,835], + [481,480,475,474,469,468, 48, -2, 30, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 0, 53, 52,463,462,457,456,451,450,837, -3], + [483,482,477,476,471,470, 49, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -1,465,464,459,458,453,452,839,838], + [485,484,479,478,473,472, 51, 50, 31, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 1, -2, 42,467,466,461,460,455,454,840, -3], + [487,486,493,492,499,498, 97, 96, 61, 60, -3, -3, -3, -3, -3, -3, -3, -3, -3, 26, 91, 90,505,504,511,510,517,516,842,841], + [489,488,495,494,501,500, 99, 98, 63, 62, -3, -3, -3, -3, -3, -3, -3, -3, 28, 27, 93, 92,507,506,513,512,519,518,843, -3], + [491,490,497,496,503,502,101,100, 65, 64, 17, -3, -3, -3, -3, -3, -3, -3, 18, 29, 95, 94,509,508,515,514,521,520,845,844], + [559,558,553,552,547,546,541,540, 73, 72, 32, -3, -3, -3, -3, -3, -3, 10, 67, 66,115,114,535,534,529,528,523,522,846, -3], + [561,560,555,554,549,548,543,542, 75, 74, -2, -1, 7, 6, 35, 34, 11, -2, 69, 68,117,116,537,536,531,530,525,524,848,847], + [563,562,557,556,551,550,545,544, 77, 76, -2, 33, 9, 8, 25, 24, -1, -2, 71, 70,119,118,539,538,533,532,527,526,849, -3], + [565,564,571,570,577,576,583,582,589,588,595,594,601,600,607,606,613,612,619,618,625,624,631,630,637,636,643,642,851,850], + [567,566,573,572,579,578,585,584,591,590,597,596,603,602,609,608,615,614,621,620,627,626,633,632,639,638,645,644,852, -3], + [569,568,575,574,581,580,587,586,593,592,599,598,605,604,611,610,617,616,623,622,629,628,635,634,641,640,647,646,854,853], + [727,726,721,720,715,714,709,708,703,702,697,696,691,690,685,684,679,678,673,672,667,666,661,660,655,654,649,648,855, -3], + [729,728,723,722,717,716,711,710,705,704,699,698,693,692,687,686,681,680,675,674,669,668,663,662,657,656,651,650,857,856], + [731,730,725,724,719,718,713,712,707,706,701,700,695,694,689,688,683,682,677,676,671,670,665,664,659,658,653,652,858, -3], + [733,732,739,738,745,744,751,750,757,756,763,762,769,768,775,774,781,780,787,786,793,792,799,798,805,804,811,810,860,859], + [735,734,741,740,747,746,753,752,759,758,765,764,771,770,777,776,783,782,789,788,795,794,801,800,807,806,813,812,861, -3], + [737,736,743,742,749,748,755,754,761,760,767,766,773,772,779,778,785,784,791,790,797,796,803,802,809,808,815,814,863,862] +]; + +/** + * @author mike32767 + * @author Manuel Kasten + */ +pub struct BitMatrixParser(BitMatrix); + +impl BitMatrixParser { + + /** + * @param bitMatrix {@link BitMatrix} to parse + */ + pub fn new( bitMatrix: BitMatrix) -> Self{ + Self(bitMatrix) + } + + pub fn readCodewords(&self) -> [u8;144] { + let mut result = [0u8;144]; + let height = self.0.getHeight() as usize; + let width = self.0.getWidth() as usize; + for y in 0..height { + // for (int y = 0; y < height; y++) { + let bitnrRow = BITNR[y]; + for x in 0..width { + // for (int x = 0; x < width; x++) { + let bit = bitnrRow[x]; + if bit >= 0 && self.0.get(x as u32, y as u32) { + result[bit as usize / 6] |= (1 << (5 - (bit % 6))); + } + } + } + result + } + +} diff --git a/src/maxicode/decoder/decoded_bit_stream_parser.rs b/src/maxicode/decoder/decoded_bit_stream_parser.rs new file mode 100644 index 0000000..d88e0ab --- /dev/null +++ b/src/maxicode/decoder/decoded_bit_stream_parser.rs @@ -0,0 +1,261 @@ +/* + * Copyright 2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use unicode_segmentation::UnicodeSegmentation; + +use crate::{common::DecoderRXingResult, Exceptions}; +use lazy_static::lazy_static; + +/** + *

MaxiCodes can encode text or structured information as bits in one of several modes, + * with multiple character sets in one code. This class decodes the bits back into text.

+ * + * @author mike32767 + * @author Manuel Kasten + */ + +const SHIFTA: &str = "\u{FFF0}"; +const SHIFTB: &str = "\u{FFF1}"; +const SHIFTC: &str = "\u{FFF2}"; +const SHIFTD: &str = "\u{FFF3}"; +const SHIFTE: &str = "\u{FFF4}"; +const TWOSHIFTA: &str = "\u{FFF5}"; +const THREESHIFTA: &str = "\u{FFF6}"; +const LATCHA: &str = "\u{FFF7}"; +const LATCHB: &str = "\u{FFF8}"; +const LOCK: &str = "\u{FFF9}"; +const ECI: &str = "\u{FFFA}"; +const NS: &str = "\u{FFFB}"; +const PAD: &str = "\u{FFFC}"; +const FS: &str = "\u{001C}"; +const GS: &str = "\u{001D}"; +const RS: &str = "\u{001E}"; +const COUNTRY_BYTES: [u8; 10] = [53, 54, 43, 44, 45, 46, 47, 48, 37, 38]; +const SERVICE_CLASS_BYTES: [u8; 10] = [55, 56, 57, 58, 59, 60, 49, 50, 51, 52]; +const POSTCODE_2_LENGTH_BYTES: [u8; 6] = [39, 40, 41, 42, 31, 32]; +const POSTCODE_2_BYTES: [u8; 30] = [ + 33, 34, 35, 36, 25, 26, 27, 28, 29, 30, 19, 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18, 7, 8, + 9, 10, 11, 12, 1, 2, +]; +const POSTCODE_3_BYTES: [[u8; 6]; 6] = [ + [39, 40, 41, 42, 31, 32], + [33, 34, 35, 36, 25, 26], + [27, 28, 29, 30, 19, 20], + [21, 22, 23, 24, 13, 14], + [15, 16, 17, 18, 7, 8], + [9, 10, 11, 12, 1, 2], +]; + +lazy_static! { +static ref SETS : [String;5]= [ + format!("\rABCDEFGHIJKLMNOPQRSTUVWXYZ{}{}{}{}{} {}\"#$%&'()*+,-./0123456789:{}{}{}{}{}" , ECI , FS , GS , RS , NS , PAD , + SHIFTB , SHIFTC , SHIFTD , SHIFTE , LATCHB), + format!("`abcdefghijklmnopqrstuvwxyz{}{}{}{}{}{{{}}}~\u{007F};<=>?[\\]^_ ,./:@!|{}{}{}{}{}{}{}{}{}" , ECI , FS , GS , RS , NS ,PAD , + PAD , TWOSHIFTA , THREESHIFTA , PAD , + SHIFTA , SHIFTC , SHIFTD , SHIFTE , LATCHA), + format!("\u{00C0}\u{00C1}\u{00C2}\u{00C3}\u{00C4}\u{00C5}\u{00C6}\u{00C7}\u{00C8}\u{00C9}\u{00CA}\u{00CB}\u{00CC}\u{00CD}\u{00CE}\u{00CF}\u{00D0}\u{00D1}\u{00D2}\u{00D3}\u{00D4}\u{00D5}\u{00D6}\u{00D7}\u{00D8}\u{00D9}\u{00DA}{}{}{}{}{}{}{}{}{}{}{}{}" , + ECI , FS , GS , RS , NS , + "\u{00DB}\u{00DC}\u{00DD}\u{00DE}\u{00DF}\u{00AA}\u{00AC}\u{00B1}\u{00B2}\u{00B3}\u{00B5}\u{00B9}\u{00BA}\u{00BC}\u{00BD}\u{00BE}\u{0080}\u{0081}\u{0082}\u{0083}\u{0084}\u{0085}\u{0086}\u{0087}\u{0088}\u{0089}" , + LATCHA , ' ' , LOCK , SHIFTD , SHIFTE , LATCHB), + format!("\u{00E0}\u{00E1}\u{00E2}\u{00E3}\u{00E4}\u{00E5}\u{00E6}\u{00E7}\u{00E8}\u{00E9}\u{00EA}\u{00EB}\u{00EC}\u{00ED}\u{00EE}\u{00EF}\u{00F0}\u{00F1}\u{00F2}\u{00F3}\u{00F4}\u{00F5}\u{00F6}\u{00F7}\u{00F8}\u{00F9}\u{00FA}{}{}{}{}{}{}{}{}{}{}{}{}" , + ECI , FS , GS , RS , NS , + "\u{00FB}\u{00FC}\u{00FD}\u{00FE}\u{00FF}\u{00A1}\u{00A8}\u{00AB}\u{00AF}\u{00B0}\u{00B4}\u{00B7}\u{00B8}\u{00BB}\u{00BF}\u{008A}\u{008B}\u{008C}\u{008D}\u{008E}\u{008F}\u{0090}\u{0091}\u{0092}\u{0093}\u{0094}" , + LATCHA , ' ' , SHIFTC , LOCK , SHIFTE , LATCHB), + format!("\u{0000}\u{0001}\u{0002}\u{0003}\u{0004}\u{0005}\u{0006}\u{0007}\u{0008}\u{0009}\n\u{000B}\u{000C}\r\u{000E}\u{000F}\u{0010}\u{0011}\u{0012}\u{0013}\u{0014}\u{0015}\u{0016}\u{0017}\u{0018}\u{0019}\u{001A}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}" , + ECI , PAD , PAD , '\u{001B}' , NS , FS , GS , RS , + "\u{001F}\u{009F}\u{00A0}\u{00A2}\u{00A3}\u{00A4}\u{00A5}\u{00A6}\u{00A7}\u{00A9}\u{00AD}\u{00AE}\u{00B6}\u{0095}\u{0096}\u{0097}\u{0098}\u{0099}\u{009A}\u{009B}\u{009C}\u{009D}\u{009E}" , + LATCHA , ' ' , SHIFTC , SHIFTD , LOCK , LATCHB), + ]; +} + +pub fn decode(bytes: &[u8], mode: u32) -> Result { + let mut result = String::with_capacity(144); + match mode { + 2 | 3 => { + let postcode; + if mode == 2 { + let pc = getPostCode2(bytes); + let ps2Length = getPostCode2Length(bytes) as usize; + if ps2Length > 10 { + return Err(Exceptions::FormatException("".to_owned())); + } + // NumberFormat df = new DecimalFormat("0000000000".substring(0, ps2Length)); + // postcode = df.format(pc); + postcode = format!("{:0>ps2Length$}", pc) + } else { + postcode = getPostCode3(bytes); + } + // NumberFormat threeDigits = new DecimalFormat("000"); + // let country = threeDigits.format(getCountry(bytes)); + // let service = threeDigits.format(getServiceClass(bytes)); + let country = format!("{:0>3}", getCountry(bytes)); //threeDigits.format(getCountry(bytes)); + let service = format!("{:0>3}", getServiceClass(bytes)); + result.push_str(&getMessage(bytes, 10, 84)); + if result.starts_with(&format!("[)>{}{}{}", RS, "01", GS)) { + result.insert_str( + 9, + &format!("{}{}{}{}{}{}", postcode, GS, country, GS, service, GS), + ); + } else { + result.insert_str( + 0, + &format!("{}{}{}{}{}{}", postcode, GS, country, GS, service, GS), + ); + } + } + 4 => { + result.push_str(&getMessage(bytes, 1, 93)); + } + 5 => { + result.push_str(&getMessage(bytes, 1, 77)); + } + _ => {} + } + Ok(DecoderRXingResult::new( + bytes.to_vec(), + result, + Vec::new(), + mode.to_string(), + )) +} + +fn getBit(bit: u8, bytes: &[u8]) -> u8 { + let bit = bit - 1; + if (bytes[bit as usize / 6] & (1 << (5 - (bit % 6)))) == 0 { + 0 + } else { + 1 + } +} + +fn getInt(bytes: &[u8], x: &[u8]) -> u32 { + let mut val = 0u32; + for i in 0..x.len() { + // for (int i = 0; i < x.length; i++) { + val += (getBit(x[i], bytes) as u32) << ((x.len() - i - 1) as u32); + } + val +} + +fn getCountry(bytes: &[u8]) -> u32 { + getInt(bytes, &COUNTRY_BYTES) +} + +fn getServiceClass(bytes: &[u8]) -> u32 { + getInt(bytes, &SERVICE_CLASS_BYTES) +} + +fn getPostCode2Length(bytes: &[u8]) -> u32 { + getInt(bytes, &POSTCODE_2_LENGTH_BYTES) +} + +fn getPostCode2(bytes: &[u8]) -> u32 { + getInt(bytes, &POSTCODE_2_BYTES) +} + +fn getPostCode3(bytes: &[u8]) -> String { + let mut sb = String::with_capacity(POSTCODE_3_BYTES.len()); + let mut graphemes = SETS[0].graphemes(true); + for p3bytes in &POSTCODE_3_BYTES { + // for (byte[] p3bytes : POSTCODE_3_BYTES) { + sb.push_str(graphemes.nth(getInt(bytes, p3bytes) as usize).unwrap()); + } + sb +} + +fn getMessage(bytes: &[u8], start: u32, len: u32) -> String { + let mut sb = String::new(); + let mut shift = -1; + let mut set = 0; + let mut lastset = 0; + + let mut i = start; + while i < start + len { + // for i in start..(start+len) { + // for (int i = start; i < start + len; i++) { + let mut set_graphemes = SETS[set].graphemes(true); + let c = set_graphemes.nth(bytes[i as usize] as usize).unwrap(); + match c { + LATCHA => { + set = 0; + shift = -1; + } + LATCHB => { + set = 1; + shift = -1; + } + SHIFTA | SHIFTB | SHIFTC | SHIFTD | SHIFTE => { + lastset = set; + // set = c - SHIFTA; + set = subtract_two_single_char_strings(c, SHIFTA); + shift = 1; + } + TWOSHIFTA => { + lastset = set; + set = 0; + shift = 2; + } + THREESHIFTA => { + lastset = set; + set = 0; + shift = 3; + } + NS => { + // let nsval = (bytes[++i] << 24) + (bytes[++i] << 18) + (bytes[++i] << 12) + (bytes[++i] << 6) + bytes[++i]; + i += 1; + let mut nsval = bytes[i as usize] << 24; + i += 1; + nsval += bytes[i as usize] << 18; + i += 1; + nsval += bytes[i as usize] << 12; + i += 1; + nsval += bytes[i as usize] << 6; + i += 1; + nsval += bytes[i as usize]; + // sb.append(new DecimalFormat("000000000").format(nsval));}, + sb.push_str(&format!("{:0>9}", nsval)); + } + LOCK => { + shift = -1; + } + _ => { + sb.push_str(c); + } + } + if shift == 0 { + set = lastset; + } + shift -= 1; + i += 1; + } + + String::from(sb.trim_end_matches(PAD)) + // while sb.len() > 0 && sb.chars().nth(sb.len() - 1).unwrap() == PAD { + // sb.setLength(sb.length() - 1); + // } + + // sb +} + +fn subtract_two_single_char_strings(str1: &str, str2: &str) -> usize { + let str1_bytes = str1.as_bytes(); + let str2_bytes = str2.as_bytes(); + + let str1_u16 = ((str1_bytes[0] as u16) << 2) + str1_bytes[1] as u16; + let str2_u16 = ((str2_bytes[0] as u16) << 2) + str2_bytes[1] as u16; + + (str1_u16 - str2_u16) as usize +} diff --git a/src/maxicode/decoder/Decoder.java b/src/maxicode/decoder/decoder.rs similarity index 100% rename from src/maxicode/decoder/Decoder.java rename to src/maxicode/decoder/decoder.rs diff --git a/src/maxicode/decoder/mod.rs b/src/maxicode/decoder/mod.rs new file mode 100644 index 0000000..d628228 --- /dev/null +++ b/src/maxicode/decoder/mod.rs @@ -0,0 +1,6 @@ +mod bit_matrix_parser; +pub mod decoded_bit_stream_parser; +mod decoder; + +pub use bit_matrix_parser::*; +pub use decoder::*; \ No newline at end of file diff --git a/src/maxicode/mod.rs b/src/maxicode/mod.rs new file mode 100644 index 0000000..2d0278d --- /dev/null +++ b/src/maxicode/mod.rs @@ -0,0 +1 @@ +mod decoder; \ No newline at end of file