begin work on maxicode

This commit is contained in:
Henry Schimke
2022-10-15 17:49:18 -05:00
parent 7d8bee6ccc
commit 64abf21e1e
8 changed files with 357 additions and 305 deletions

View File

@@ -6,6 +6,7 @@ pub mod client;
pub mod common;
mod exceptions;
pub mod qrcode;
pub mod maxicode;
pub use exceptions::Exceptions;

View File

@@ -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;
}
}

View File

@@ -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;
/**
* <p>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.</p>
*
* @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();
}
}

View File

@@ -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
}
}

View File

@@ -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;
/**
* <p>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.</p>
*
* @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<DecoderRXingResult, Exceptions> {
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
}

View File

@@ -0,0 +1,6 @@
mod bit_matrix_parser;
pub mod decoded_bit_stream_parser;
mod decoder;
pub use bit_matrix_parser::*;
pub use decoder::*;

1
src/maxicode/mod.rs Normal file
View File

@@ -0,0 +1 @@
mod decoder;