添加项目文件。

This commit is contained in:
akwkevin
2021-07-23 09:42:22 +08:00
commit f25a958797
2798 changed files with 352360 additions and 0 deletions

View File

@@ -0,0 +1,281 @@
/*
* Copyright 2007 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.
*/
using ZXing.Common;
namespace ZXing.QrCode.Internal
{
/// <author>Sean Owen</author>
sealed class BitMatrixParser
{
private readonly BitMatrix bitMatrix;
private Version parsedVersion;
private FormatInformation parsedFormatInfo;
private bool mirrored;
/// <param name="bitMatrix">{@link BitMatrix} to parse</param>
/// <throws>ReaderException if dimension is not >= 21 and 1 mod 4</throws>
internal static BitMatrixParser createBitMatrixParser(BitMatrix bitMatrix)
{
int dimension = bitMatrix.Height;
if (dimension < 21 || (dimension & 0x03) != 1)
{
return null;
}
return new BitMatrixParser(bitMatrix);
}
private BitMatrixParser(BitMatrix bitMatrix)
{
// Should only be called from createBitMatrixParser with the important checks before
this.bitMatrix = bitMatrix;
}
/// <summary> <p>Reads format information from one of its two locations within the QR Code.</p>
///
/// </summary>
/// <returns> {@link FormatInformation} encapsulating the QR Code's format info
/// </returns>
/// <throws> ReaderException if both format information locations cannot be parsed as </throws>
/// <summary> the valid encoding of format information
/// </summary>
internal FormatInformation readFormatInformation()
{
if (parsedFormatInfo != null)
{
return parsedFormatInfo;
}
// Read top-left format info bits
int formatInfoBits1 = 0;
for (int i = 0; i < 6; i++)
{
formatInfoBits1 = copyBit(i, 8, formatInfoBits1);
}
// .. and skip a bit in the timing pattern ...
formatInfoBits1 = copyBit(7, 8, formatInfoBits1);
formatInfoBits1 = copyBit(8, 8, formatInfoBits1);
formatInfoBits1 = copyBit(8, 7, formatInfoBits1);
// .. and skip a bit in the timing pattern ...
for (int j = 5; j >= 0; j--)
{
formatInfoBits1 = copyBit(8, j, formatInfoBits1);
}
// Read the top-right/bottom-left pattern too
int dimension = bitMatrix.Height;
int formatInfoBits2 = 0;
int jMin = dimension - 7;
for (int j = dimension - 1; j >= jMin; j--)
{
formatInfoBits2 = copyBit(8, j, formatInfoBits2);
}
for (int i = dimension - 8; i < dimension; i++)
{
formatInfoBits2 = copyBit(i, 8, formatInfoBits2);
}
parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits1, formatInfoBits2);
if (parsedFormatInfo != null)
{
return parsedFormatInfo;
}
return null;
}
/// <summary> <p>Reads version information from one of its two locations within the QR Code.</p>
///
/// </summary>
/// <returns> {@link Version} encapsulating the QR Code's version
/// </returns>
/// <throws> ReaderException if both version information locations cannot be parsed as </throws>
/// <summary> the valid encoding of version information
/// </summary>
internal Version readVersion()
{
if (parsedVersion != null)
{
return parsedVersion;
}
int dimension = bitMatrix.Height;
int provisionalVersion = (dimension - 17) >> 2;
if (provisionalVersion <= 6)
{
return Version.getVersionForNumber(provisionalVersion);
}
// Read top-right version info: 3 wide by 6 tall
int versionBits = 0;
int ijMin = dimension - 11;
for (int j = 5; j >= 0; j--)
{
for (int i = dimension - 9; i >= ijMin; i--)
{
versionBits = copyBit(i, j, versionBits);
}
}
parsedVersion = Version.decodeVersionInformation(versionBits);
if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension)
{
return parsedVersion;
}
// Hmm, failed. Try bottom left: 6 wide by 3 tall
versionBits = 0;
for (int i = 5; i >= 0; i--)
{
for (int j = dimension - 9; j >= ijMin; j--)
{
versionBits = copyBit(i, j, versionBits);
}
}
parsedVersion = Version.decodeVersionInformation(versionBits);
if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension)
{
return parsedVersion;
}
return null;
}
private int copyBit(int i, int j, int versionBits)
{
bool bit = mirrored ? bitMatrix[j, i] : bitMatrix[i, j];
return bit ? (versionBits << 1) | 0x1 : versionBits << 1;
}
/// <summary> <p>Reads the bits in the {@link BitMatrix} representing the finder pattern in the
/// correct order in order to reconstruct the codewords bytes contained within the
/// QR Code.</p>
///
/// </summary>
/// <returns> bytes encoded within the QR Code
/// </returns>
/// <throws> ReaderException if the exact number of bytes expected is not read </throws>
internal byte[] readCodewords()
{
FormatInformation formatInfo = readFormatInformation();
if (formatInfo == null)
return null;
Version version = readVersion();
if (version == null)
return null;
// Get the data mask for the format used in this QR Code. This will exclude
// some bits from reading as we wind through the bit matrix.
DataMask dataMask = DataMask.forReference(formatInfo.DataMask);
int dimension = bitMatrix.Height;
dataMask.unmaskBitMatrix(bitMatrix, dimension);
BitMatrix functionPattern = version.buildFunctionPattern();
bool readingUp = true;
byte[] result = new byte[version.TotalCodewords];
int resultOffset = 0;
int currentByte = 0;
int bitsRead = 0;
// Read columns in pairs, from right to left
for (int j = dimension - 1; j > 0; j -= 2)
{
if (j == 6)
{
// Skip whole column with vertical alignment pattern;
// saves time and makes the other code proceed more cleanly
j--;
}
// Read alternatingly from bottom to top then top to bottom
for (int count = 0; count < dimension; count++)
{
int i = readingUp ? dimension - 1 - count : count;
for (int col = 0; col < 2; col++)
{
// Ignore bits covered by the function pattern
if (!functionPattern[j - col, i])
{
// Read a bit
bitsRead++;
currentByte <<= 1;
if (bitMatrix[j - col, i])
{
currentByte |= 1;
}
// If we've made a whole byte, save it off
if (bitsRead == 8)
{
result[resultOffset++] = (byte)currentByte;
bitsRead = 0;
currentByte = 0;
}
}
}
}
readingUp ^= true; // readingUp = !readingUp; // switch directions
}
if (resultOffset != version.TotalCodewords)
{
return null;
}
return result;
}
/**
* Revert the mask removal done while reading the code words. The bit matrix should revert to its original state.
*/
internal void remask()
{
if (parsedFormatInfo == null)
{
return; // We have no format information, and have no data mask
}
DataMask dataMask = DataMask.forReference(parsedFormatInfo.DataMask);
int dimension = bitMatrix.Height;
dataMask.unmaskBitMatrix(bitMatrix, dimension);
}
/**
* Prepare the parser for a mirrored operation.
* This flag has effect only on the {@link #readFormatInformation()} and the
* {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the
* {@link #mirror()} method should be called.
*
* @param mirror Whether to read version and format information mirrored.
*/
internal void setMirror(bool mirror)
{
parsedVersion = null;
parsedFormatInfo = null;
mirrored = mirror;
}
/** Mirror the bit matrix in order to attempt a second reading. */
internal void mirror()
{
for (int x = 0; x < bitMatrix.Width; x++)
{
for (int y = x + 1; y < bitMatrix.Height; y++)
{
if (bitMatrix[x, y] != bitMatrix[y, x])
{
bitMatrix.flip(y, x);
bitMatrix.flip(x, y);
}
}
}
}
}
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright 2007 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.
*/
namespace ZXing.QrCode.Internal
{
/// <summary> <p>Encapsulates a block of data within a QR Code. QR Codes may split their data into
/// multiple blocks, each of which is a unit of data and error-correction codewords. Each
/// is represented by an instance of this class.</p>
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
internal sealed class DataBlock
{
private readonly int numDataCodewords;
private readonly byte[] codewords;
private DataBlock(int numDataCodewords, byte[] codewords)
{
this.numDataCodewords = numDataCodewords;
this.codewords = codewords;
}
/// <summary> <p>When QR Codes use multiple data blocks, they are actually interleaved.
/// That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
/// method will separate the data into original blocks.</p>
///
/// </summary>
/// <param name="rawCodewords">bytes as read directly from the QR Code
/// </param>
/// <param name="version">version of the QR Code
/// </param>
/// <param name="ecLevel">error-correction level of the QR Code
/// </param>
/// <returns> {@link DataBlock}s containing original bytes, "de-interleaved" from representation in the
/// QR Code
/// </returns>
internal static DataBlock[] getDataBlocks(byte[] rawCodewords, Version version, ErrorCorrectionLevel ecLevel)
{
if (rawCodewords.Length != version.TotalCodewords)
{
throw new System.ArgumentException();
}
// Figure out the number and size of data blocks used by this version and
// error correction level
Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);
// First count the total number of data blocks
int totalBlocks = 0;
Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();
foreach (var ecBlock in ecBlockArray)
{
totalBlocks += ecBlock.Count;
}
// Now establish DataBlocks of the appropriate size and number of data codewords
DataBlock[] result = new DataBlock[totalBlocks];
int numResultBlocks = 0;
foreach (var ecBlock in ecBlockArray)
{
for (int i = 0; i < ecBlock.Count; i++)
{
int numDataCodewords = ecBlock.DataCodewords;
int numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords;
result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]);
}
}
// All blocks have the same amount of data, except that the last n
// (where n may be 0) have 1 more byte. Figure out where these start.
int shorterBlocksTotalCodewords = result[0].codewords.Length;
int longerBlocksStartAt = result.Length - 1;
while (longerBlocksStartAt >= 0)
{
int numCodewords = result[longerBlocksStartAt].codewords.Length;
if (numCodewords == shorterBlocksTotalCodewords)
{
break;
}
longerBlocksStartAt--;
}
longerBlocksStartAt++;
int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock;
// The last elements of result may be 1 element longer;
// first fill out as many elements as all of them have
int rawCodewordsOffset = 0;
for (int i = 0; i < shorterBlocksNumDataCodewords; i++)
{
for (int j = 0; j < numResultBlocks; j++)
{
result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
}
}
// Fill out the last data block in the longer ones
for (int j = longerBlocksStartAt; j < numResultBlocks; j++)
{
result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
}
// Now add in error correction blocks
int max = result[0].codewords.Length;
for (int i = shorterBlocksNumDataCodewords; i < max; i++)
{
for (int j = 0; j < numResultBlocks; j++)
{
int iOffset = j < longerBlocksStartAt ? i : i + 1;
result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
}
}
return result;
}
internal int NumDataCodewords
{
get
{
return numDataCodewords;
}
}
internal byte[] Codewords
{
get
{
return codewords;
}
}
}
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright 2007 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.
*/
using ZXing.Common;
namespace ZXing.QrCode.Internal
{
/// <summary> <p>Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations
/// of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix,
/// including areas used for finder patterns, timing patterns, etc. These areas should be unused
/// after the point they are unmasked anyway.</p>
///
/// <p>Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position
/// and j is row position. In fact, as the text says, i is row position and j is column position.</p>
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
abstract class DataMask
{
/// <summary> See ISO 18004:2006 6.8.1</summary>
private static readonly DataMask[] DATA_MASKS = new DataMask[]
{
new DataMask000(),
new DataMask001(),
new DataMask010(),
new DataMask011(),
new DataMask100(),
new DataMask101(),
new DataMask110(),
new DataMask111()
};
private DataMask()
{
}
/// <summary> <p>Implementations of this method reverse the data masking process applied to a QR Code and
/// make its bits ready to read.</p>
///
/// </summary>
/// <param name="bits">representation of QR Code bits
/// </param>
/// <param name="dimension">dimension of QR Code, represented by bits, being unmasked
/// </param>
internal void unmaskBitMatrix(BitMatrix bits, int dimension)
{
for (int i = 0; i < dimension; i++)
{
for (int j = 0; j < dimension; j++)
{
if (isMasked(i, j))
{
bits.flip(j, i);
}
}
}
}
internal abstract bool isMasked(int i, int j);
/// <param name="reference">a value between 0 and 7 indicating one of the eight possible
/// data mask patterns a QR Code may use
/// </param>
/// <returns> {@link DataMask} encapsulating the data mask pattern
/// </returns>
internal static DataMask forReference(int reference)
{
if (reference < 0 || reference > 7)
{
throw new System.ArgumentException();
}
return DATA_MASKS[reference];
}
/// <summary> 000: mask bits for which (x + y) mod 2 == 0</summary>
private sealed class DataMask000 : DataMask
{
internal override bool isMasked(int i, int j)
{
return ((i + j) & 0x01) == 0;
}
}
/// <summary> 001: mask bits for which x mod 2 == 0</summary>
private sealed class DataMask001 : DataMask
{
internal override bool isMasked(int i, int j)
{
return (i & 0x01) == 0;
}
}
/// <summary> 010: mask bits for which y mod 3 == 0</summary>
private sealed class DataMask010 : DataMask
{
internal override bool isMasked(int i, int j)
{
return j % 3 == 0;
}
}
/// <summary> 011: mask bits for which (x + y) mod 3 == 0</summary>
private sealed class DataMask011 : DataMask
{
internal override bool isMasked(int i, int j)
{
return (i + j) % 3 == 0;
}
}
/// <summary> 100: mask bits for which (x/2 + y/3) mod 2 == 0</summary>
private sealed class DataMask100 : DataMask
{
internal override bool isMasked(int i, int j)
{
return ((((int)((uint)i >> 1)) + (j / 3)) & 0x01) == 0;
}
}
/// <summary> 101: mask bits for which xy mod 2 + xy mod 3 == 0</summary>
private sealed class DataMask101 : DataMask
{
internal override bool isMasked(int i, int j)
{
int temp = i * j;
return (temp & 0x01) + (temp % 3) == 0;
}
}
/// <summary> 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0</summary>
private sealed class DataMask110 : DataMask
{
internal override bool isMasked(int i, int j)
{
int temp = i * j;
return (((temp & 0x01) + (temp % 3)) & 0x01) == 0;
}
}
/// <summary> 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0</summary>
private sealed class DataMask111 : DataMask
{
internal override bool isMasked(int i, int j)
{
return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0;
}
}
}
}

View File

@@ -0,0 +1,524 @@
/*
* Copyright 2007 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.
*/
using System;
using System.Collections.Generic;
using System.Text;
using ZXing.Common;
namespace ZXing.QrCode.Internal
{
/// <summary> <p>QR Codes can encode text as bits in one of several modes, and can use multiple modes
/// in one QR Code. This class decodes the bits back into text.</p>
///
/// <p>See ISO 18004:2006, 6.4.3 - 6.4.7</p>
/// <author>Sean Owen</author>
/// </summary>
internal static class DecodedBitStreamParser
{
/// <summary>
/// See ISO 18004:2006, 6.4.4 Table 5
/// </summary>
private static readonly char[] ALPHANUMERIC_CHARS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
' ', '$', '%', '*', '+', '-', '.', '/', ':'
};
private const int GB2312_SUBSET = 1;
internal static DecoderResult decode(byte[] bytes,
Version version,
ErrorCorrectionLevel ecLevel,
IDictionary<DecodeHintType, object> hints)
{
var bits = new BitSource(bytes);
var result = new StringBuilder(50);
var byteSegments = new List<byte[]>(1);
var symbolSequence = -1;
var parityData = -1;
try
{
CharacterSetECI currentCharacterSetECI = null;
bool fc1InEffect = false;
Mode mode;
do
{
// While still another segment to read...
if (bits.available() < 4)
{
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
mode = Mode.TERMINATOR;
}
else
{
try
{
mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits
}
catch (ArgumentException)
{
return null;
}
}
if (mode != Mode.TERMINATOR)
{
if (mode == Mode.FNC1_FIRST_POSITION || mode == Mode.FNC1_SECOND_POSITION)
{
// We do little with FNC1 except alter the parsed result a bit according to the spec
fc1InEffect = true;
}
else if (mode == Mode.STRUCTURED_APPEND)
{
if (bits.available() < 16)
{
return null;
}
// not really supported; but sequence number and parity is added later to the result metadata
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
symbolSequence = bits.readBits(8);
parityData = bits.readBits(8);
}
else if (mode == Mode.ECI)
{
// Count doesn't apply to ECI
int value = parseECIValue(bits);
currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
if (currentCharacterSetECI == null)
{
return null;
}
}
else
{
// First handle Hanzi mode which does not start with character count
if (mode == Mode.HANZI)
{
//chinese mode contains a sub set indicator right after mode indicator
int subset = bits.readBits(4);
int countHanzi = bits.readBits(mode.getCharacterCountBits(version));
if (subset == GB2312_SUBSET)
{
if (!decodeHanziSegment(bits, result, countHanzi))
return null;
}
}
else
{
// "Normal" QR code modes:
// How many characters will follow, encoded in this mode?
int count = bits.readBits(mode.getCharacterCountBits(version));
if (mode == Mode.NUMERIC)
{
if (!decodeNumericSegment(bits, result, count))
return null;
}
else if (mode == Mode.ALPHANUMERIC)
{
if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect))
return null;
}
else if (mode == Mode.BYTE)
{
if (!decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints))
return null;
}
else if (mode == Mode.KANJI)
{
if (!decodeKanjiSegment(bits, result, count))
return null;
}
else
{
return null;
}
}
}
}
} while (mode != Mode.TERMINATOR);
}
catch (ArgumentException)
{
// from readBits() calls
return null;
}
#if WindowsCE
var resultString = result.ToString().Replace("\n", "\r\n");
#else
var resultString = result.ToString().Replace("\r\n", "\n").Replace("\n", Environment.NewLine);
#endif
return new DecoderResult(bytes,
resultString,
byteSegments.Count == 0 ? null : byteSegments,
ecLevel == null ? null : ecLevel.ToString(),
symbolSequence, parityData);
}
/// <summary>
/// See specification GBT 18284-2000
/// </summary>
/// <param name="bits">The bits.</param>
/// <param name="result">The result.</param>
/// <param name="count">The count.</param>
/// <returns></returns>
private static bool decodeHanziSegment(BitSource bits,
StringBuilder result,
int count)
{
// Don't crash trying to read more bits than we have available.
if (count * 13 > bits.available())
{
return false;
}
// Each character will require 2 bytes. Read the characters as 2-byte pairs
// and decode as GB2312 afterwards
byte[] buffer = new byte[2 * count];
int offset = 0;
while (count > 0)
{
// Each 13 bits encodes a 2-byte character
int twoBytes = bits.readBits(13);
int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060);
if (assembledTwoBytes < 0x003BF)
{
// In the 0xA1A1 to 0xAAFE range
assembledTwoBytes += 0x0A1A1;
}
else
{
// In the 0xB0A1 to 0xFAFE range
assembledTwoBytes += 0x0A6A1;
}
buffer[offset] = (byte)((assembledTwoBytes >> 8) & 0xFF);
buffer[offset + 1] = (byte)(assembledTwoBytes & 0xFF);
offset += 2;
count--;
}
try
{
result.Append(Encoding.GetEncoding(StringUtils.GB2312).GetString(buffer, 0, buffer.Length));
}
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH)
catch (ArgumentException)
{
try
{
// Silverlight only supports a limited number of character sets, trying fallback to UTF-8
result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length));
}
catch (Exception)
{
return false;
}
}
#endif
catch (Exception)
{
return false;
}
return true;
}
private static bool decodeKanjiSegment(BitSource bits,
StringBuilder result,
int count)
{
// Don't crash trying to read more bits than we have available.
if (count * 13 > bits.available())
{
return false;
}
// Each character will require 2 bytes. Read the characters as 2-byte pairs
// and decode as Shift_JIS afterwards
byte[] buffer = new byte[2 * count];
int offset = 0;
while (count > 0)
{
// Each 13 bits encodes a 2-byte character
int twoBytes = bits.readBits(13);
int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);
if (assembledTwoBytes < 0x01F00)
{
// In the 0x8140 to 0x9FFC range
assembledTwoBytes += 0x08140;
}
else
{
// In the 0xE040 to 0xEBBF range
assembledTwoBytes += 0x0C140;
}
buffer[offset] = (byte)(assembledTwoBytes >> 8);
buffer[offset + 1] = (byte)assembledTwoBytes;
offset += 2;
count--;
}
// Shift_JIS may not be supported in some environments:
try
{
result.Append(Encoding.GetEncoding(StringUtils.SHIFT_JIS).GetString(buffer, 0, buffer.Length));
}
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH)
catch (ArgumentException)
{
try
{
// Silverlight only supports a limited number of character sets, trying fallback to UTF-8
result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length));
}
catch (Exception)
{
return false;
}
}
#endif
catch (Exception)
{
return false;
}
return true;
}
private static bool decodeByteSegment(BitSource bits,
StringBuilder result,
int count,
CharacterSetECI currentCharacterSetECI,
IList<byte[]> byteSegments,
IDictionary<DecodeHintType, object> hints)
{
// Don't crash trying to read more bits than we have available.
if (count << 3 > bits.available())
{
return false;
}
byte[] readBytes = new byte[count];
for (int i = 0; i < count; i++)
{
readBytes[i] = (byte)bits.readBits(8);
}
String encoding;
if (currentCharacterSetECI == null)
{
// The spec isn't clear on this mode; see
// section 6.4.5: t does not say which encoding to assuming
// upon decoding. I have seen ISO-8859-1 used as well as
// Shift_JIS -- without anything like an ECI designator to
// give a hint.
encoding = StringUtils.guessEncoding(readBytes, hints);
}
else
{
encoding = currentCharacterSetECI.EncodingName;
}
try
{
result.Append(Encoding.GetEncoding(encoding).GetString(readBytes, 0, readBytes.Length));
}
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH)
catch (ArgumentException)
{
try
{
// Silverlight only supports a limited number of character sets, trying fallback to UTF-8
result.Append(Encoding.GetEncoding("UTF-8").GetString(readBytes, 0, readBytes.Length));
}
catch (Exception)
{
return false;
}
}
#endif
#if WindowsCE
catch (PlatformNotSupportedException)
{
try
{
// WindowsCE doesn't support all encodings. But it is device depended.
// So we try here the some different ones
if (encoding == "ISO-8859-1")
{
result.Append(Encoding.GetEncoding(1252).GetString(readBytes, 0, readBytes.Length));
}
else
{
result.Append(Encoding.GetEncoding("UTF-8").GetString(readBytes, 0, readBytes.Length));
}
}
catch (Exception)
{
return false;
}
}
#endif
catch (Exception)
{
return false;
}
byteSegments.Add(readBytes);
return true;
}
private static char toAlphaNumericChar(int value)
{
if (value >= ALPHANUMERIC_CHARS.Length)
{
throw FormatException.Instance;
}
return ALPHANUMERIC_CHARS[value];
}
private static bool decodeAlphanumericSegment(BitSource bits,
StringBuilder result,
int count,
bool fc1InEffect)
{
// Read two characters at a time
int start = result.Length;
while (count > 1)
{
if (bits.available() < 11)
{
return false;
}
int nextTwoCharsBits = bits.readBits(11);
result.Append(toAlphaNumericChar(nextTwoCharsBits / 45));
result.Append(toAlphaNumericChar(nextTwoCharsBits % 45));
count -= 2;
}
if (count == 1)
{
// special case: one character left
if (bits.available() < 6)
{
return false;
}
result.Append(toAlphaNumericChar(bits.readBits(6)));
}
// See section 6.4.8.1, 6.4.8.2
if (fc1InEffect)
{
// We need to massage the result a bit if in an FNC1 mode:
for (int i = start; i < result.Length; i++)
{
if (result[i] == '%')
{
if (i < result.Length - 1 && result[i + 1] == '%')
{
// %% is rendered as %
result.Remove(i + 1, 1);
}
else
{
// In alpha mode, % should be converted to FNC1 separator 0x1D
result.Remove(i, 1);
result.Insert(i, new[] { (char)0x1D });
}
}
}
}
return true;
}
private static bool decodeNumericSegment(BitSource bits,
StringBuilder result,
int count)
{
// Read three digits at a time
while (count >= 3)
{
// Each 10 bits encodes three digits
if (bits.available() < 10)
{
return false;
}
int threeDigitsBits = bits.readBits(10);
if (threeDigitsBits >= 1000)
{
return false;
}
result.Append(toAlphaNumericChar(threeDigitsBits / 100));
result.Append(toAlphaNumericChar((threeDigitsBits / 10) % 10));
result.Append(toAlphaNumericChar(threeDigitsBits % 10));
count -= 3;
}
if (count == 2)
{
// Two digits left over to read, encoded in 7 bits
if (bits.available() < 7)
{
return false;
}
int twoDigitsBits = bits.readBits(7);
if (twoDigitsBits >= 100)
{
return false;
}
result.Append(toAlphaNumericChar(twoDigitsBits / 10));
result.Append(toAlphaNumericChar(twoDigitsBits % 10));
}
else if (count == 1)
{
// One digit left over to read
if (bits.available() < 4)
{
return false;
}
int digitBits = bits.readBits(4);
if (digitBits >= 10)
{
return false;
}
result.Append(toAlphaNumericChar(digitBits));
}
return true;
}
private static int parseECIValue(BitSource bits)
{
int firstByte = bits.readBits(8);
if ((firstByte & 0x80) == 0)
{
// just one byte
return firstByte & 0x7F;
}
if ((firstByte & 0xC0) == 0x80)
{
// two bytes
int secondByte = bits.readBits(8);
return ((firstByte & 0x3F) << 8) | secondByte;
}
if ((firstByte & 0xE0) == 0xC0)
{
// three bytes
int secondThirdBytes = bits.readBits(16);
return ((firstByte & 0x1F) << 16) | secondThirdBytes;
}
throw new ArgumentException("Bad ECI bits starting with byte " + firstByte);
}
}
}

View File

@@ -0,0 +1,195 @@
/*
* Copyright 2007 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.
*/
using System.Collections.Generic;
using ZXing.Common;
using ZXing.Common.ReedSolomon;
namespace ZXing.QrCode.Internal
{
/// <summary>
/// <p>The main class which implements QR Code decoding -- as opposed to locating and extracting
/// the QR Code from an image.</p>
/// </summary>
/// <author>
/// Sean Owen
/// </author>
public sealed class Decoder
{
private readonly ReedSolomonDecoder rsDecoder;
/// <summary>
/// Initializes a new instance of the <see cref="Decoder"/> class.
/// </summary>
public Decoder()
{
rsDecoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256);
}
/// <summary>
/// <p>Convenience method that can decode a QR Code represented as a 2D array of booleans.
/// "true" is taken to mean a black module.</p>
/// </summary>
/// <param name="image">booleans representing white/black QR Code modules</param>
/// <param name="hints">decoding hints that should be used to influence decoding</param>
/// <returns>
/// text and bytes encoded within the QR Code
/// </returns>
public DecoderResult decode(bool[][] image, IDictionary<DecodeHintType, object> hints)
{
var dimension = image.Length;
var bits = new BitMatrix(dimension);
for (int i = 0; i < dimension; i++)
{
for (int j = 0; j < dimension; j++)
{
bits[j, i] = image[i][j];
}
}
return decode(bits, hints);
}
/// <summary>
/// <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p>
/// </summary>
/// <param name="bits">booleans representing white/black QR Code modules</param>
/// <param name="hints">decoding hints that should be used to influence decoding</param>
/// <returns>
/// text and bytes encoded within the QR Code
/// </returns>
public DecoderResult decode(BitMatrix bits, IDictionary<DecodeHintType, object> hints)
{
// Construct a parser and read version, error-correction level
var parser = BitMatrixParser.createBitMatrixParser(bits);
if (parser == null)
return null;
var result = decode(parser, hints);
if (result == null)
{
// Revert the bit matrix
parser.remask();
// Will be attempting a mirrored reading of the version and format info.
parser.setMirror(true);
// Preemptively read the version.
var version = parser.readVersion();
if (version == null)
return null;
// Preemptively read the format information.
var formatinfo = parser.readFormatInformation();
if (formatinfo == null)
return null;
/*
* Since we're here, this means we have successfully detected some kind
* of version and format information when mirrored. This is a good sign,
* that the QR code may be mirrored, and we should try once more with a
* mirrored content.
*/
// Prepare for a mirrored reading.
parser.mirror();
result = decode(parser, hints);
if (result != null)
{
// Success! Notify the caller that the code was mirrored.
result.Other = new QRCodeDecoderMetaData(true);
}
}
return result;
}
private DecoderResult decode(BitMatrixParser parser, IDictionary<DecodeHintType, object> hints)
{
Version version = parser.readVersion();
if (version == null)
return null;
var formatinfo = parser.readFormatInformation();
if (formatinfo == null)
return null;
ErrorCorrectionLevel ecLevel = formatinfo.ErrorCorrectionLevel;
// Read codewords
byte[] codewords = parser.readCodewords();
if (codewords == null)
return null;
// Separate into data blocks
DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel);
// Count total number of data bytes
int totalBytes = 0;
foreach (var dataBlock in dataBlocks)
{
totalBytes += dataBlock.NumDataCodewords;
}
byte[] resultBytes = new byte[totalBytes];
int resultOffset = 0;
// Error-correct and copy data blocks together into a stream of bytes
foreach (var dataBlock in dataBlocks)
{
byte[] codewordBytes = dataBlock.Codewords;
int numDataCodewords = dataBlock.NumDataCodewords;
if (!correctErrors(codewordBytes, numDataCodewords))
return null;
for (int i = 0; i < numDataCodewords; i++)
{
resultBytes[resultOffset++] = codewordBytes[i];
}
}
// Decode the contents of that stream of bytes
return DecodedBitStreamParser.decode(resultBytes, version, ecLevel, hints);
}
/// <summary>
/// <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
/// correct the errors in-place using Reed-Solomon error correction.</p>
/// </summary>
/// <param name="codewordBytes">data and error correction codewords</param>
/// <param name="numDataCodewords">number of codewords that are data bytes</param>
/// <returns></returns>
private bool correctErrors(byte[] codewordBytes, int numDataCodewords)
{
int numCodewords = codewordBytes.Length;
// First read into an array of ints
int[] codewordsInts = new int[numCodewords];
for (int i = 0; i < numCodewords; i++)
{
codewordsInts[i] = codewordBytes[i] & 0xFF;
}
int numECCodewords = codewordBytes.Length - numDataCodewords;
if (!rsDecoder.decode(codewordsInts, numECCodewords))
return false;
// Copy back into array of bytes -- only need to worry about the bytes that were data
// We don't care about errors in the error-correction codewords
for (int i = 0; i < numDataCodewords; i++)
{
codewordBytes[i] = (byte)codewordsInts[i];
}
return true;
}
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2007 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.
*/
using System;
namespace ZXing.QrCode.Internal
{
/// <summary>
/// <p>See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels
/// defined by the QR code standard.</p>
/// </summary>
/// <author>Sean Owen</author>
public sealed class ErrorCorrectionLevel
{
/// <summary> L = ~7% correction</summary>
public static readonly ErrorCorrectionLevel L = new ErrorCorrectionLevel(0, 0x01, "L");
/// <summary> M = ~15% correction</summary>
public static readonly ErrorCorrectionLevel M = new ErrorCorrectionLevel(1, 0x00, "M");
/// <summary> Q = ~25% correction</summary>
public static readonly ErrorCorrectionLevel Q = new ErrorCorrectionLevel(2, 0x03, "Q");
/// <summary> H = ~30% correction</summary>
public static readonly ErrorCorrectionLevel H = new ErrorCorrectionLevel(3, 0x02, "H");
private static readonly ErrorCorrectionLevel[] FOR_BITS = new [] { M, L, H, Q };
private readonly int bits;
private ErrorCorrectionLevel(int ordinal, int bits, String name)
{
this.ordinal_Renamed_Field = ordinal;
this.bits = bits;
this.name = name;
}
/// <summary>
/// Gets the bits.
/// </summary>
public int Bits
{
get
{
return bits;
}
}
/// <summary>
/// Gets the name.
/// </summary>
public String Name
{
get
{
return name;
}
}
private readonly int ordinal_Renamed_Field;
private readonly String name;
/// <summary>
/// Ordinals this instance.
/// </summary>
/// <returns></returns>
public int ordinal()
{
return ordinal_Renamed_Field;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override String ToString()
{
return name;
}
/// <summary>
/// Fors the bits.
/// </summary>
/// <param name="bits">int containing the two bits encoding a QR Code's error correction level</param>
/// <returns>
/// <see cref="ErrorCorrectionLevel"/> representing the encoded error correction level
/// </returns>
public static ErrorCorrectionLevel forBits(int bits)
{
if (bits < 0 || bits >= FOR_BITS.Length)
{
throw new ArgumentException();
}
return FOR_BITS[bits];
}
}
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright 2007 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.
*/
using System;
namespace ZXing.QrCode.Internal
{
/// <summary> <p>Encapsulates a QR Code's format information, including the data mask used and
/// error correction level.</p>
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
/// <seealso cref="DataMask">
/// </seealso>
/// <seealso cref="ErrorCorrectionLevel">
/// </seealso>
sealed class FormatInformation
{
private const int FORMAT_INFO_MASK_QR = 0x5412;
/// <summary> See ISO 18004:2006, Annex C, Table C.1</summary>
private static readonly int[][] FORMAT_INFO_DECODE_LOOKUP = new int[][]
{
new [] { 0x5412, 0x00 },
new [] { 0x5125, 0x01 },
new [] { 0x5E7C, 0x02 },
new [] { 0x5B4B, 0x03 },
new [] { 0x45F9, 0x04 },
new [] { 0x40CE, 0x05 },
new [] { 0x4F97, 0x06 },
new [] { 0x4AA0, 0x07 },
new [] { 0x77C4, 0x08 },
new [] { 0x72F3, 0x09 },
new [] { 0x7DAA, 0x0A },
new [] { 0x789D, 0x0B },
new [] { 0x662F, 0x0C },
new [] { 0x6318, 0x0D },
new [] { 0x6C41, 0x0E },
new [] { 0x6976, 0x0F },
new [] { 0x1689, 0x10 },
new [] { 0x13BE, 0x11 },
new [] { 0x1CE7, 0x12 },
new [] { 0x19D0, 0x13 },
new [] { 0x0762, 0x14 },
new [] { 0x0255, 0x15 },
new [] { 0x0D0C, 0x16 },
new [] { 0x083B, 0x17 },
new [] { 0x355F, 0x18 },
new [] { 0x3068, 0x19 },
new [] { 0x3F31, 0x1A },
new [] { 0x3A06, 0x1B },
new [] { 0x24B4, 0x1C },
new [] { 0x2183, 0x1D },
new [] { 0x2EDA, 0x1E },
new [] { 0x2BED, 0x1F }
};
/// <summary> Offset i holds the number of 1 bits in the binary representation of i</summary>
private static readonly int[] BITS_SET_IN_HALF_BYTE = new []
{ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
private readonly ErrorCorrectionLevel errorCorrectionLevel;
private readonly byte dataMask;
private FormatInformation(int formatInfo)
{
// Bits 3,4
errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03);
// Bottom 3 bits
dataMask = (byte)(formatInfo & 0x07);
}
internal static int numBitsDiffering(int a, int b)
{
a ^= b; // a now has a 1 bit exactly where its bit differs with b's
// Count bits set quickly with a series of lookups:
return BITS_SET_IN_HALF_BYTE[a & 0x0F] +
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 4)) & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 8)) & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 12)) & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 16)) & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 20)) & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 24)) & 0x0F)] +
BITS_SET_IN_HALF_BYTE[(((int)((uint)a >> 28)) & 0x0F)];
}
/// <summary>
/// Decodes the format information.
/// </summary>
/// <param name="maskedFormatInfo1">format info indicator, with mask still applied</param>
/// <param name="maskedFormatInfo2">The masked format info2.</param>
/// <returns>
/// information about the format it specifies, or <code>null</code>
/// if doesn't seem to match any known pattern
/// </returns>
internal static FormatInformation decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2)
{
FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2);
if (formatInfo != null)
{
return formatInfo;
}
// Should return null, but, some QR codes apparently
// do not mask this info. Try again by actually masking the pattern
// first
return doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR,
maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR);
}
private static FormatInformation doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2)
{
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
int bestDifference = Int32.MaxValue;
int bestFormatInfo = 0;
foreach (var decodeInfo in FORMAT_INFO_DECODE_LOOKUP)
{
int targetInfo = decodeInfo[0];
if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2)
{
// Found an exact match
return new FormatInformation(decodeInfo[1]);
}
int bitsDifference = numBitsDiffering(maskedFormatInfo1, targetInfo);
if (bitsDifference < bestDifference)
{
bestFormatInfo = decodeInfo[1];
bestDifference = bitsDifference;
}
if (maskedFormatInfo1 != maskedFormatInfo2)
{
// also try the other option
bitsDifference = numBitsDiffering(maskedFormatInfo2, targetInfo);
if (bitsDifference < bestDifference)
{
bestFormatInfo = decodeInfo[1];
bestDifference = bitsDifference;
}
}
}
// Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
// differing means we found a match
if (bestDifference <= 3)
{
return new FormatInformation(bestFormatInfo);
}
return null;
}
internal ErrorCorrectionLevel ErrorCorrectionLevel
{
get
{
return errorCorrectionLevel;
}
}
internal byte DataMask
{
get
{
return dataMask;
}
}
public override int GetHashCode()
{
return (errorCorrectionLevel.ordinal() << 3) | dataMask;
}
public override bool Equals(Object o)
{
if (!(o is FormatInformation))
{
return false;
}
var other = (FormatInformation)o;
return errorCorrectionLevel == other.errorCorrectionLevel && dataMask == other.dataMask;
}
}
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright 2007 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.
*/
using System;
namespace ZXing.QrCode.Internal
{
/// <summary>
/// <p>See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which
/// data can be encoded to bits in the QR code standard.</p>
/// </summary>
/// <author>Sean Owen</author>
public sealed class Mode
{
/// <summary>
/// Gets the name.
/// </summary>
public String Name
{
get
{
return name;
}
}
// No, we can't use an enum here. J2ME doesn't support it.
/// <summary>
///
/// </summary>
public static readonly Mode TERMINATOR = new Mode(new int[] { 0, 0, 0 }, 0x00, "TERMINATOR"); // Not really a mode...
/// <summary>
///
/// </summary>
public static readonly Mode NUMERIC = new Mode(new int[] { 10, 12, 14 }, 0x01, "NUMERIC");
/// <summary>
///
/// </summary>
public static readonly Mode ALPHANUMERIC = new Mode(new int[] { 9, 11, 13 }, 0x02, "ALPHANUMERIC");
/// <summary>
///
/// </summary>
public static readonly Mode STRUCTURED_APPEND = new Mode(new int[] { 0, 0, 0 }, 0x03, "STRUCTURED_APPEND"); // Not supported
/// <summary>
///
/// </summary>
public static readonly Mode BYTE = new Mode(new int[] { 8, 16, 16 }, 0x04, "BYTE");
/// <summary>
///
/// </summary>
public static readonly Mode ECI = new Mode(null, 0x07, "ECI"); // character counts don't apply
/// <summary>
///
/// </summary>
public static readonly Mode KANJI = new Mode(new int[] { 8, 10, 12 }, 0x08, "KANJI");
/// <summary>
///
/// </summary>
public static readonly Mode FNC1_FIRST_POSITION = new Mode(null, 0x05, "FNC1_FIRST_POSITION");
/// <summary>
///
/// </summary>
public static readonly Mode FNC1_SECOND_POSITION = new Mode(null, 0x09, "FNC1_SECOND_POSITION");
/// <summary>See GBT 18284-2000; "Hanzi" is a transliteration of this mode name.</summary>
public static readonly Mode HANZI = new Mode(new int[] { 8, 10, 12 }, 0x0D, "HANZI");
private readonly int[] characterCountBitsForVersions;
private readonly int bits;
private readonly String name;
private Mode(int[] characterCountBitsForVersions, int bits, System.String name)
{
this.characterCountBitsForVersions = characterCountBitsForVersions;
this.bits = bits;
this.name = name;
}
/// <summary>
/// Fors the bits.
/// </summary>
/// <param name="bits">four bits encoding a QR Code data mode</param>
/// <returns>
/// <see cref="Mode"/> encoded by these bits
/// </returns>
/// <exception cref="ArgumentException">if bits do not correspond to a known mode</exception>
public static Mode forBits(int bits)
{
switch (bits)
{
case 0x0:
return TERMINATOR;
case 0x1:
return NUMERIC;
case 0x2:
return ALPHANUMERIC;
case 0x3:
return STRUCTURED_APPEND;
case 0x4:
return BYTE;
case 0x5:
return FNC1_FIRST_POSITION;
case 0x7:
return ECI;
case 0x8:
return KANJI;
case 0x9:
return FNC1_SECOND_POSITION;
case 0xD:
// 0xD is defined in GBT 18284-2000, may not be supported in foreign country
return HANZI;
default:
throw new ArgumentException();
}
}
/// <param name="version">version in question
/// </param>
/// <returns> number of bits used, in this QR Code symbol {@link Version}, to encode the
/// count of characters that will follow encoded in this {@link Mode}
/// </returns>
public int getCharacterCountBits(Version version)
{
if (characterCountBitsForVersions == null)
{
throw new ArgumentException("Character count doesn't apply to this mode");
}
int number = version.VersionNumber;
int offset;
if (number <= 9)
{
offset = 0;
}
else if (number <= 26)
{
offset = 1;
}
else
{
offset = 2;
}
return characterCountBitsForVersions[offset];
}
/// <summary>
/// Gets the bits.
/// </summary>
public int Bits
{
get
{
return bits;
}
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override String ToString()
{
return name;
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2013 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.
*/
namespace ZXing.QrCode.Internal
{
/// <summary>
/// Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the
/// decoding caller. Callers are expected to process this.
/// </summary>
public sealed class QRCodeDecoderMetaData
{
private readonly bool mirrored;
/// <summary>
/// Initializes a new instance of the <see cref="QRCodeDecoderMetaData"/> class.
/// </summary>
/// <param name="mirrored">if set to <c>true</c> [mirrored].</param>
public QRCodeDecoderMetaData(bool mirrored)
{
this.mirrored = mirrored;
}
/// <summary>
/// true if the QR Code was mirrored.
/// </summary>
public bool IsMirrored
{
get { return mirrored; }
}
/// <summary>
/// Apply the result points' order correction due to mirroring.
/// </summary>
/// <param name="points">Array of points to apply mirror correction to.</param>
public void applyMirroredCorrection(ResultPoint[] points)
{
if (!mirrored || points == null || points.Length < 3)
{
return;
}
ResultPoint bottomLeft = points[0];
points[0] = points[2];
points[2] = bottomLeft;
// No need to 'fix' top-left and alignment pattern.
}
}
}

View File

@@ -0,0 +1,685 @@
/*
* Copyright 2007 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.
*/
using System;
using ZXing.Common;
namespace ZXing.QrCode.Internal
{
/// <summary>
/// See ISO 18004:2006 Annex D
/// </summary>
/// <author>Sean Owen</author>
public sealed class Version
{
/// <summary> See ISO 18004:2006 Annex D.
/// Element i represents the raw version bits that specify version i + 7
/// </summary>
private static readonly int[] VERSION_DECODE_INFO = new[]
{
0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6,
0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78,
0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683,
0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250,
0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B,
0x2542E, 0x26A64, 0x27541, 0x28C69
};
private static readonly Version[] VERSIONS = buildVersions();
private readonly int versionNumber;
private readonly int[] alignmentPatternCenters;
private readonly ECBlocks[] ecBlocks;
private readonly int totalCodewords;
private Version(int versionNumber, int[] alignmentPatternCenters, params ECBlocks[] ecBlocks)
{
this.versionNumber = versionNumber;
this.alignmentPatternCenters = alignmentPatternCenters;
this.ecBlocks = ecBlocks;
int total = 0;
int ecCodewords = ecBlocks[0].ECCodewordsPerBlock;
ECB[] ecbArray = ecBlocks[0].getECBlocks();
foreach (var ecBlock in ecbArray)
{
total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords);
}
this.totalCodewords = total;
}
/// <summary>
/// Gets the version number.
/// </summary>
public int VersionNumber
{
get
{
return versionNumber;
}
}
/// <summary>
/// Gets the alignment pattern centers.
/// </summary>
public int[] AlignmentPatternCenters
{
get
{
return alignmentPatternCenters;
}
}
/// <summary>
/// Gets the total codewords.
/// </summary>
public int TotalCodewords
{
get
{
return totalCodewords;
}
}
/// <summary>
/// Gets the dimension for version.
/// </summary>
public int DimensionForVersion
{
get
{
return 17 + 4 * versionNumber;
}
}
/// <summary>
/// Gets the EC blocks for level.
/// </summary>
/// <param name="ecLevel">The ec level.</param>
/// <returns></returns>
public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel)
{
return ecBlocks[ecLevel.ordinal()];
}
/// <summary> <p>Deduces version information purely from QR Code dimensions.</p>
///
/// </summary>
/// <param name="dimension">dimension in modules
/// </param>
/// <returns><see cref="Version" /> for a QR Code of that dimension or null</returns>
public static Version getProvisionalVersionForDimension(int dimension)
{
if (dimension % 4 != 1)
{
return null;
}
try
{
return getVersionForNumber((dimension - 17) >> 2);
}
catch (ArgumentException)
{
return null;
}
}
/// <summary>
/// Gets the version for number.
/// </summary>
/// <param name="versionNumber">The version number.</param>
/// <returns></returns>
public static Version getVersionForNumber(int versionNumber)
{
if (versionNumber < 1 || versionNumber > 40)
{
throw new ArgumentException();
}
return VERSIONS[versionNumber - 1];
}
internal static Version decodeVersionInformation(int versionBits)
{
int bestDifference = Int32.MaxValue;
int bestVersion = 0;
for (int i = 0; i < VERSION_DECODE_INFO.Length; i++)
{
int targetVersion = VERSION_DECODE_INFO[i];
// Do the version info bits match exactly? done.
if (targetVersion == versionBits)
{
return getVersionForNumber(i + 7);
}
// Otherwise see if this is the closest to a real version info bit string
// we have seen so far
int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
if (bitsDifference < bestDifference)
{
bestVersion = i + 7;
bestDifference = bitsDifference;
}
}
// We can tolerate up to 3 bits of error since no two version info codewords will
// differ in less than 8 bits.
if (bestDifference <= 3)
{
return getVersionForNumber(bestVersion);
}
// If we didn't find a close enough match, fail
return null;
}
/// <summary> See ISO 18004:2006 Annex E</summary>
internal BitMatrix buildFunctionPattern()
{
int dimension = DimensionForVersion;
BitMatrix bitMatrix = new BitMatrix(dimension);
// Top left finder pattern + separator + format
bitMatrix.setRegion(0, 0, 9, 9);
// Top right finder pattern + separator + format
bitMatrix.setRegion(dimension - 8, 0, 8, 9);
// Bottom left finder pattern + separator + format
bitMatrix.setRegion(0, dimension - 8, 9, 8);
// Alignment patterns
int max = alignmentPatternCenters.Length;
for (int x = 0; x < max; x++)
{
int i = alignmentPatternCenters[x] - 2;
for (int y = 0; y < max; y++)
{
if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0))
{
// No alignment patterns near the three finder paterns
continue;
}
bitMatrix.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5);
}
}
// Vertical timing pattern
bitMatrix.setRegion(6, 9, 1, dimension - 17);
// Horizontal timing pattern
bitMatrix.setRegion(9, 6, dimension - 17, 1);
if (versionNumber > 6)
{
// Version info, top right
bitMatrix.setRegion(dimension - 11, 0, 3, 6);
// Version info, bottom left
bitMatrix.setRegion(0, dimension - 11, 6, 3);
}
return bitMatrix;
}
/// <summary> <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
/// use blocks of differing sizes within one version, so, this encapsulates the parameters for
/// each set of blocks. It also holds the number of error-correction codewords per block since it
/// will be the same across all blocks within one version.</p>
/// </summary>
public sealed class ECBlocks
{
private readonly int ecCodewordsPerBlock;
private readonly ECB[] ecBlocks;
internal ECBlocks(int ecCodewordsPerBlock, params ECB[] ecBlocks)
{
this.ecCodewordsPerBlock = ecCodewordsPerBlock;
this.ecBlocks = ecBlocks;
}
/// <summary>
/// Gets the EC codewords per block.
/// </summary>
public int ECCodewordsPerBlock
{
get
{
return ecCodewordsPerBlock;
}
}
/// <summary>
/// Gets the num blocks.
/// </summary>
public int NumBlocks
{
get
{
int total = 0;
foreach (var ecBlock in ecBlocks)
{
total += ecBlock.Count;
}
return total;
}
}
/// <summary>
/// Gets the total EC codewords.
/// </summary>
public int TotalECCodewords
{
get
{
return ecCodewordsPerBlock * NumBlocks;
}
}
/// <summary>
/// Gets the EC blocks.
/// </summary>
/// <returns></returns>
public ECB[] getECBlocks()
{
return ecBlocks;
}
}
/// <summary> <p>Encapsualtes the parameters for one error-correction block in one symbol version.
/// This includes the number of data codewords, and the number of times a block with these
/// parameters is used consecutively in the QR code version's format.</p>
/// </summary>
public sealed class ECB
{
private readonly int count;
private readonly int dataCodewords;
internal ECB(int count, int dataCodewords)
{
this.count = count;
this.dataCodewords = dataCodewords;
}
/// <summary>
/// Gets the count.
/// </summary>
public int Count
{
get
{
return count;
}
}
/// <summary>
/// Gets the data codewords.
/// </summary>
public int DataCodewords
{
get
{
return dataCodewords;
}
}
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override String ToString()
{
return Convert.ToString(versionNumber);
}
/// <summary> See ISO 18004:2006 6.5.1 Table 9</summary>
private static Version[] buildVersions()
{
return new Version[]
{
new Version(1, new int[] {},
new ECBlocks(7, new ECB(1, 19)),
new ECBlocks(10, new ECB(1, 16)),
new ECBlocks(13, new ECB(1, 13)),
new ECBlocks(17, new ECB(1, 9))),
new Version(2, new int[] {6, 18},
new ECBlocks(10, new ECB(1, 34)),
new ECBlocks(16, new ECB(1, 28)),
new ECBlocks(22, new ECB(1, 22)),
new ECBlocks(28, new ECB(1, 16))),
new Version(3, new int[] {6, 22},
new ECBlocks(15, new ECB(1, 55)),
new ECBlocks(26, new ECB(1, 44)),
new ECBlocks(18, new ECB(2, 17)),
new ECBlocks(22, new ECB(2, 13))),
new Version(4, new int[] {6, 26},
new ECBlocks(20, new ECB(1, 80)),
new ECBlocks(18, new ECB(2, 32)),
new ECBlocks(26, new ECB(2, 24)),
new ECBlocks(16, new ECB(4, 9))),
new Version(5, new int[] {6, 30},
new ECBlocks(26, new ECB(1, 108)),
new ECBlocks(24, new ECB(2, 43)),
new ECBlocks(18, new ECB(2, 15),
new ECB(2, 16)),
new ECBlocks(22, new ECB(2, 11),
new ECB(2, 12))),
new Version(6, new int[] {6, 34},
new ECBlocks(18, new ECB(2, 68)),
new ECBlocks(16, new ECB(4, 27)),
new ECBlocks(24, new ECB(4, 19)),
new ECBlocks(28, new ECB(4, 15))),
new Version(7, new int[] {6, 22, 38},
new ECBlocks(20, new ECB(2, 78)),
new ECBlocks(18, new ECB(4, 31)),
new ECBlocks(18, new ECB(2, 14),
new ECB(4, 15)),
new ECBlocks(26, new ECB(4, 13),
new ECB(1, 14))),
new Version(8, new int[] {6, 24, 42},
new ECBlocks(24, new ECB(2, 97)),
new ECBlocks(22, new ECB(2, 38),
new ECB(2, 39)),
new ECBlocks(22, new ECB(4, 18),
new ECB(2, 19)),
new ECBlocks(26, new ECB(4, 14),
new ECB(2, 15))),
new Version(9, new int[] {6, 26, 46},
new ECBlocks(30, new ECB(2, 116)),
new ECBlocks(22, new ECB(3, 36),
new ECB(2, 37)),
new ECBlocks(20, new ECB(4, 16),
new ECB(4, 17)),
new ECBlocks(24, new ECB(4, 12),
new ECB(4, 13))),
new Version(10, new int[] {6, 28, 50},
new ECBlocks(18, new ECB(2, 68),
new ECB(2, 69)),
new ECBlocks(26, new ECB(4, 43),
new ECB(1, 44)),
new ECBlocks(24, new ECB(6, 19),
new ECB(2, 20)),
new ECBlocks(28, new ECB(6, 15),
new ECB(2, 16))),
new Version(11, new int[] {6, 30, 54},
new ECBlocks(20, new ECB(4, 81)),
new ECBlocks(30, new ECB(1, 50),
new ECB(4, 51)),
new ECBlocks(28, new ECB(4, 22),
new ECB(4, 23)),
new ECBlocks(24, new ECB(3, 12),
new ECB(8, 13))),
new Version(12, new int[] {6, 32, 58},
new ECBlocks(24, new ECB(2, 92),
new ECB(2, 93)),
new ECBlocks(22, new ECB(6, 36),
new ECB(2, 37)),
new ECBlocks(26, new ECB(4, 20),
new ECB(6, 21)),
new ECBlocks(28, new ECB(7, 14),
new ECB(4, 15))),
new Version(13, new int[] {6, 34, 62},
new ECBlocks(26, new ECB(4, 107)),
new ECBlocks(22, new ECB(8, 37),
new ECB(1, 38)),
new ECBlocks(24, new ECB(8, 20),
new ECB(4, 21)),
new ECBlocks(22, new ECB(12, 11),
new ECB(4, 12))),
new Version(14, new int[] {6, 26, 46, 66},
new ECBlocks(30, new ECB(3, 115),
new ECB(1, 116)),
new ECBlocks(24, new ECB(4, 40),
new ECB(5, 41)),
new ECBlocks(20, new ECB(11, 16),
new ECB(5, 17)),
new ECBlocks(24, new ECB(11, 12),
new ECB(5, 13))),
new Version(15, new int[] {6, 26, 48, 70},
new ECBlocks(22, new ECB(5, 87),
new ECB(1, 88)),
new ECBlocks(24, new ECB(5, 41),
new ECB(5, 42)),
new ECBlocks(30, new ECB(5, 24),
new ECB(7, 25)),
new ECBlocks(24, new ECB(11, 12),
new ECB(7, 13))),
new Version(16, new int[] {6, 26, 50, 74},
new ECBlocks(24, new ECB(5, 98),
new ECB(1, 99)),
new ECBlocks(28, new ECB(7, 45),
new ECB(3, 46)),
new ECBlocks(24, new ECB(15, 19),
new ECB(2, 20)),
new ECBlocks(30, new ECB(3, 15),
new ECB(13, 16))),
new Version(17, new int[] {6, 30, 54, 78},
new ECBlocks(28, new ECB(1, 107),
new ECB(5, 108)),
new ECBlocks(28, new ECB(10, 46),
new ECB(1, 47)),
new ECBlocks(28, new ECB(1, 22),
new ECB(15, 23)),
new ECBlocks(28, new ECB(2, 14),
new ECB(17, 15))),
new Version(18, new int[] {6, 30, 56, 82},
new ECBlocks(30, new ECB(5, 120),
new ECB(1, 121)),
new ECBlocks(26, new ECB(9, 43),
new ECB(4, 44)),
new ECBlocks(28, new ECB(17, 22),
new ECB(1, 23)),
new ECBlocks(28, new ECB(2, 14),
new ECB(19, 15))),
new Version(19, new int[] {6, 30, 58, 86},
new ECBlocks(28, new ECB(3, 113),
new ECB(4, 114)),
new ECBlocks(26, new ECB(3, 44),
new ECB(11, 45)),
new ECBlocks(26, new ECB(17, 21),
new ECB(4, 22)),
new ECBlocks(26, new ECB(9, 13),
new ECB(16, 14))),
new Version(20, new int[] {6, 34, 62, 90},
new ECBlocks(28, new ECB(3, 107),
new ECB(5, 108)),
new ECBlocks(26, new ECB(3, 41),
new ECB(13, 42)),
new ECBlocks(30, new ECB(15, 24),
new ECB(5, 25)),
new ECBlocks(28, new ECB(15, 15),
new ECB(10, 16))),
new Version(21, new int[] {6, 28, 50, 72, 94},
new ECBlocks(28, new ECB(4, 116),
new ECB(4, 117)),
new ECBlocks(26, new ECB(17, 42)),
new ECBlocks(28, new ECB(17, 22),
new ECB(6, 23)),
new ECBlocks(30, new ECB(19, 16),
new ECB(6, 17))),
new Version(22, new int[] {6, 26, 50, 74, 98},
new ECBlocks(28, new ECB(2, 111),
new ECB(7, 112)),
new ECBlocks(28, new ECB(17, 46)),
new ECBlocks(30, new ECB(7, 24),
new ECB(16, 25)),
new ECBlocks(24, new ECB(34, 13))),
new Version(23, new int[] {6, 30, 54, 78, 102},
new ECBlocks(30, new ECB(4, 121),
new ECB(5, 122)),
new ECBlocks(28, new ECB(4, 47),
new ECB(14, 48)),
new ECBlocks(30, new ECB(11, 24),
new ECB(14, 25)),
new ECBlocks(30, new ECB(16, 15),
new ECB(14, 16))),
new Version(24, new int[] {6, 28, 54, 80, 106},
new ECBlocks(30, new ECB(6, 117),
new ECB(4, 118)),
new ECBlocks(28, new ECB(6, 45),
new ECB(14, 46)),
new ECBlocks(30, new ECB(11, 24),
new ECB(16, 25)),
new ECBlocks(30, new ECB(30, 16),
new ECB(2, 17))),
new Version(25, new int[] {6, 32, 58, 84, 110},
new ECBlocks(26, new ECB(8, 106),
new ECB(4, 107)),
new ECBlocks(28, new ECB(8, 47),
new ECB(13, 48)),
new ECBlocks(30, new ECB(7, 24),
new ECB(22, 25)),
new ECBlocks(30, new ECB(22, 15),
new ECB(13, 16))),
new Version(26, new int[] {6, 30, 58, 86, 114},
new ECBlocks(28, new ECB(10, 114),
new ECB(2, 115)),
new ECBlocks(28, new ECB(19, 46),
new ECB(4, 47)),
new ECBlocks(28, new ECB(28, 22),
new ECB(6, 23)),
new ECBlocks(30, new ECB(33, 16),
new ECB(4, 17))),
new Version(27, new int[] {6, 34, 62, 90, 118},
new ECBlocks(30, new ECB(8, 122),
new ECB(4, 123)),
new ECBlocks(28, new ECB(22, 45),
new ECB(3, 46)),
new ECBlocks(30, new ECB(8, 23),
new ECB(26, 24)),
new ECBlocks(30, new ECB(12, 15),
new ECB(28, 16))),
new Version(28, new int[] {6, 26, 50, 74, 98, 122},
new ECBlocks(30, new ECB(3, 117),
new ECB(10, 118)),
new ECBlocks(28, new ECB(3, 45),
new ECB(23, 46)),
new ECBlocks(30, new ECB(4, 24),
new ECB(31, 25)),
new ECBlocks(30, new ECB(11, 15),
new ECB(31, 16))),
new Version(29, new int[] {6, 30, 54, 78, 102, 126},
new ECBlocks(30, new ECB(7, 116),
new ECB(7, 117)),
new ECBlocks(28, new ECB(21, 45),
new ECB(7, 46)),
new ECBlocks(30, new ECB(1, 23),
new ECB(37, 24)),
new ECBlocks(30, new ECB(19, 15),
new ECB(26, 16))),
new Version(30, new int[] {6, 26, 52, 78, 104, 130},
new ECBlocks(30, new ECB(5, 115),
new ECB(10, 116)),
new ECBlocks(28, new ECB(19, 47),
new ECB(10, 48)),
new ECBlocks(30, new ECB(15, 24),
new ECB(25, 25)),
new ECBlocks(30, new ECB(23, 15),
new ECB(25, 16))),
new Version(31, new int[] {6, 30, 56, 82, 108, 134},
new ECBlocks(30, new ECB(13, 115),
new ECB(3, 116)),
new ECBlocks(28, new ECB(2, 46),
new ECB(29, 47)),
new ECBlocks(30, new ECB(42, 24),
new ECB(1, 25)),
new ECBlocks(30, new ECB(23, 15),
new ECB(28, 16))),
new Version(32, new int[] {6, 34, 60, 86, 112, 138},
new ECBlocks(30, new ECB(17, 115)),
new ECBlocks(28, new ECB(10, 46),
new ECB(23, 47)),
new ECBlocks(30, new ECB(10, 24),
new ECB(35, 25)),
new ECBlocks(30, new ECB(19, 15),
new ECB(35, 16))),
new Version(33, new int[] {6, 30, 58, 86, 114, 142},
new ECBlocks(30, new ECB(17, 115),
new ECB(1, 116)),
new ECBlocks(28, new ECB(14, 46),
new ECB(21, 47)),
new ECBlocks(30, new ECB(29, 24),
new ECB(19, 25)),
new ECBlocks(30, new ECB(11, 15),
new ECB(46, 16))),
new Version(34, new int[] {6, 34, 62, 90, 118, 146},
new ECBlocks(30, new ECB(13, 115),
new ECB(6, 116)),
new ECBlocks(28, new ECB(14, 46),
new ECB(23, 47)),
new ECBlocks(30, new ECB(44, 24),
new ECB(7, 25)),
new ECBlocks(30, new ECB(59, 16),
new ECB(1, 17))),
new Version(35, new int[] {6, 30, 54, 78, 102, 126, 150},
new ECBlocks(30, new ECB(12, 121),
new ECB(7, 122)),
new ECBlocks(28, new ECB(12, 47),
new ECB(26, 48)),
new ECBlocks(30, new ECB(39, 24),
new ECB(14, 25)),
new ECBlocks(30, new ECB(22, 15),
new ECB(41, 16))),
new Version(36, new int[] {6, 24, 50, 76, 102, 128, 154},
new ECBlocks(30, new ECB(6, 121),
new ECB(14, 122)),
new ECBlocks(28, new ECB(6, 47),
new ECB(34, 48)),
new ECBlocks(30, new ECB(46, 24),
new ECB(10, 25)),
new ECBlocks(30, new ECB(2, 15),
new ECB(64, 16))),
new Version(37, new int[] {6, 28, 54, 80, 106, 132, 158},
new ECBlocks(30, new ECB(17, 122),
new ECB(4, 123)),
new ECBlocks(28, new ECB(29, 46),
new ECB(14, 47)),
new ECBlocks(30, new ECB(49, 24),
new ECB(10, 25)),
new ECBlocks(30, new ECB(24, 15),
new ECB(46, 16))),
new Version(38, new int[] {6, 32, 58, 84, 110, 136, 162},
new ECBlocks(30, new ECB(4, 122),
new ECB(18, 123)),
new ECBlocks(28, new ECB(13, 46),
new ECB(32, 47)),
new ECBlocks(30, new ECB(48, 24),
new ECB(14, 25)),
new ECBlocks(30, new ECB(42, 15),
new ECB(32, 16))),
new Version(39, new int[] {6, 26, 54, 82, 110, 138, 166},
new ECBlocks(30, new ECB(20, 117),
new ECB(4, 118)),
new ECBlocks(28, new ECB(40, 47),
new ECB(7, 48)),
new ECBlocks(30, new ECB(43, 24),
new ECB(22, 25)),
new ECBlocks(30, new ECB(10, 15),
new ECB(67, 16))),
new Version(40, new int[] {6, 30, 58, 86, 114, 142, 170},
new ECBlocks(30, new ECB(19, 118),
new ECB(6, 119)),
new ECBlocks(28, new ECB(18, 47),
new ECB(31, 48)),
new ECBlocks(30, new ECB(34, 24),
new ECB(34, 25)),
new ECBlocks(30, new ECB(20, 15),
new ECB(61, 16)))
};
}
}
}