Browse Source

use zxing instead

tags/2.3
clowwindy 9 years ago
parent
commit
1b126fa78e
19 changed files with 4823 additions and 1246 deletions
  1. +0
    -1209
      shadowsocks-csharp/3rd/QRCodeCS.cs
  2. +488
    -0
      shadowsocks-csharp/3rd/zxing/BitArray.cs
  3. +435
    -0
      shadowsocks-csharp/3rd/zxing/BitMatrix.cs
  4. +40
    -0
      shadowsocks-csharp/3rd/zxing/BlockPair.cs
  5. +148
    -0
      shadowsocks-csharp/3rd/zxing/ByteMatrix.cs
  6. +131
    -0
      shadowsocks-csharp/3rd/zxing/EncodeHintType.cs
  7. +762
    -0
      shadowsocks-csharp/3rd/zxing/Encoder.cs
  8. +109
    -0
      shadowsocks-csharp/3rd/zxing/ErrorCorrectionLevel.cs
  9. +197
    -0
      shadowsocks-csharp/3rd/zxing/FormatInformation.cs
  10. +210
    -0
      shadowsocks-csharp/3rd/zxing/GenericGF.cs
  11. +331
    -0
      shadowsocks-csharp/3rd/zxing/GenericGFPoly.cs
  12. +271
    -0
      shadowsocks-csharp/3rd/zxing/MaskUtil.cs
  13. +604
    -0
      shadowsocks-csharp/3rd/zxing/MatrixUtil.cs
  14. +179
    -0
      shadowsocks-csharp/3rd/zxing/Mode.cs
  15. +125
    -0
      shadowsocks-csharp/3rd/zxing/QRCode.cs
  16. +84
    -0
      shadowsocks-csharp/3rd/zxing/ReedSolomonEncoder.cs
  17. +685
    -0
      shadowsocks-csharp/3rd/zxing/Version.cs
  18. +8
    -36
      shadowsocks-csharp/View/QRCodeForm.cs
  19. +16
    -1
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 0
- 1209
shadowsocks-csharp/3rd/QRCodeCS.cs
File diff suppressed because it is too large
View File


+ 488
- 0
shadowsocks-csharp/3rd/zxing/BitArray.cs View File

@@ -0,0 +1,488 @@
/*
* 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.Common
{
/// <summary>
/// A simple, fast array of bits, represented compactly by an array of ints internally.
/// </summary>
/// <author>Sean Owen</author>
public sealed class BitArray
{
private int[] bits;
private int size;
public int Size
{
get
{
return size;
}
}
public int SizeInBytes
{
get
{
return (size + 7) >> 3;
}
}
public bool this[int i]
{
get
{
return (bits[i >> 5] & (1 << (i & 0x1F))) != 0;
}
set
{
if (value)
bits[i >> 5] |= 1 << (i & 0x1F);
}
}
public BitArray()
{
this.size = 0;
this.bits = new int[1];
}
public BitArray(int size)
{
if (size < 1)
{
throw new ArgumentException("size must be at least 1");
}
this.size = size;
this.bits = makeArray(size);
}
// For testing only
private BitArray(int[] bits, int size)
{
this.bits = bits;
this.size = size;
}
private void ensureCapacity(int size)
{
if (size > bits.Length << 5)
{
int[] newBits = makeArray(size);
System.Array.Copy(bits, 0, newBits, 0, bits.Length);
bits = newBits;
}
}
/// <summary> Flips bit i.
///
/// </summary>
/// <param name="i">bit to set
/// </param>
public void flip(int i)
{
bits[i >> 5] ^= 1 << (i & 0x1F);
}
private static int numberOfTrailingZeros(int num)
{
var index = (-num & num)%37;
if (index < 0)
index *= -1;
return _lookup[index];
}
private static readonly int[] _lookup =
{
32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17,
0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18
};
/// <summary>
/// Gets the next set.
/// </summary>
/// <param name="from">first bit to check</param>
/// <returns>index of first bit that is set, starting from the given index, or size if none are set
/// at or beyond this given index</returns>
public int getNextSet(int from)
{
if (from >= size)
{
return size;
}
int bitsOffset = from >> 5;
int currentBits = bits[bitsOffset];
// mask off lesser bits first
currentBits &= ~((1 << (from & 0x1F)) - 1);
while (currentBits == 0)
{
if (++bitsOffset == bits.Length)
{
return size;
}
currentBits = bits[bitsOffset];
}
int result = (bitsOffset << 5) + numberOfTrailingZeros(currentBits);
return result > size ? size : result;
}
/// <summary>
/// see getNextSet(int)
/// </summary>
/// <param name="from">index to start looking for unset bit</param>
/// <returns>index of next unset bit, or <see cref="Size"/> if none are unset until the end</returns>
public int getNextUnset(int from)
{
if (from >= size)
{
return size;
}
int bitsOffset = from >> 5;
int currentBits = ~bits[bitsOffset];
// mask off lesser bits first
currentBits &= ~((1 << (from & 0x1F)) - 1);
while (currentBits == 0)
{
if (++bitsOffset == bits.Length)
{
return size;
}
currentBits = ~bits[bitsOffset];
}
int result = (bitsOffset << 5) + numberOfTrailingZeros(currentBits);
return result > size ? size : result;
}
/// <summary> Sets a block of 32 bits, starting at bit i.
///
/// </summary>
/// <param name="i">first bit to set
/// </param>
/// <param name="newBits">the new value of the next 32 bits. Note again that the least-significant bit
/// corresponds to bit i, the next-least-significant to i+1, and so on.
/// </param>
public void setBulk(int i, int newBits)
{
bits[i >> 5] = newBits;
}
/// <summary>
/// Sets a range of bits.
/// </summary>
/// <param name="start">start of range, inclusive.</param>
/// <param name="end">end of range, exclusive</param>
public void setRange(int start, int end)
{
if (end < start)
{
throw new ArgumentException();
}
if (end == start)
{
return;
}
end--; // will be easier to treat this as the last actually set bit -- inclusive
int firstInt = start >> 5;
int lastInt = end >> 5;
for (int i = firstInt; i <= lastInt; i++)
{
int firstBit = i > firstInt ? 0 : start & 0x1F;
int lastBit = i < lastInt ? 31 : end & 0x1F;
int mask;
if (firstBit == 0 && lastBit == 31)
{
mask = -1;
}
else
{
mask = 0;
for (int j = firstBit; j <= lastBit; j++)
{
mask |= 1 << j;
}
}
bits[i] |= mask;
}
}
/// <summary> Clears all bits (sets to false).</summary>
public void clear()
{
int max = bits.Length;
for (int i = 0; i < max; i++)
{
bits[i] = 0;
}
}
/// <summary> Efficient method to check if a range of bits is set, or not set.
///
/// </summary>
/// <param name="start">start of range, inclusive.
/// </param>
/// <param name="end">end of range, exclusive
/// </param>
/// <param name="value">if true, checks that bits in range are set, otherwise checks that they are not set
/// </param>
/// <returns> true iff all bits are set or not set in range, according to value argument
/// </returns>
/// <throws> IllegalArgumentException if end is less than or equal to start </throws>
public bool isRange(int start, int end, bool value)
{
if (end < start)
{
throw new System.ArgumentException();
}
if (end == start)
{
return true; // empty range matches
}
end--; // will be easier to treat this as the last actually set bit -- inclusive
int firstInt = start >> 5;
int lastInt = end >> 5;
for (int i = firstInt; i <= lastInt; i++)
{
int firstBit = i > firstInt ? 0 : start & 0x1F;
int lastBit = i < lastInt ? 31 : end & 0x1F;
int mask;
if (firstBit == 0 && lastBit == 31)
{
mask = -1;
}
else
{
mask = 0;
for (int j = firstBit; j <= lastBit; j++)
{
mask |= 1 << j;
}
}
// Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is,
// equals the mask, or we're looking for 0s and the masked portion is not all 0s
if ((bits[i] & mask) != (value ? mask : 0))
{
return false;
}
}
return true;
}
/// <summary>
/// Appends the bit.
/// </summary>
/// <param name="bit">The bit.</param>
public void appendBit(bool bit)
{
ensureCapacity(size + 1);
if (bit)
{
bits[size >> 5] |= 1 << (size & 0x1F);
}
size++;
}
/// <returns> underlying array of ints. The first element holds the first 32 bits, and the least
/// significant bit is bit 0.
/// </returns>
public int[] Array
{
get { return bits; }
}
/// <summary>
/// Appends the least-significant bits, from value, in order from most-significant to
/// least-significant. For example, appending 6 bits from 0x000001E will append the bits
/// 0, 1, 1, 1, 1, 0 in that order.
/// </summary>
/// <param name="value"><see cref="int"/> containing bits to append</param>
/// <param name="numBits">bits from value to append</param>
public void appendBits(int value, int numBits)
{
if (numBits < 0 || numBits > 32)
{
throw new ArgumentException("Num bits must be between 0 and 32");
}
ensureCapacity(size + numBits);
for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--)
{
appendBit(((value >> (numBitsLeft - 1)) & 0x01) == 1);
}
}
public void appendBitArray(BitArray other)
{
int otherSize = other.size;
ensureCapacity(size + otherSize);
for (int i = 0; i < otherSize; i++)
{
appendBit(other[i]);
}
}
public void xor(BitArray other)
{
if (bits.Length != other.bits.Length)
{
throw new ArgumentException("Sizes don't match");
}
for (int i = 0; i < bits.Length; i++)
{
// The last byte could be incomplete (i.e. not have 8 bits in
// it) but there is no problem since 0 XOR 0 == 0.
bits[i] ^= other.bits[i];
}
}
/// <summary>
/// Toes the bytes.
/// </summary>
/// <param name="bitOffset">first bit to start writing</param>
/// <param name="array">array to write into. Bytes are written most-significant byte first. This is the opposite
/// of the internal representation, which is exposed by BitArray</param>
/// <param name="offset">position in array to start writing</param>
/// <param name="numBytes">how many bytes to write</param>
public void toBytes(int bitOffset, byte[] array, int offset, int numBytes)
{
for (int i = 0; i < numBytes; i++)
{
int theByte = 0;
for (int j = 0; j < 8; j++)
{
if (this[bitOffset])
{
theByte |= 1 << (7 - j);
}
bitOffset++;
}
array[offset + i] = (byte)theByte;
}
}
/// <summary> Reverses all bits in the array.</summary>
public void reverse()
{
var newBits = new int[bits.Length];
// reverse all int's first
var len = ((size - 1) >> 5);
var oldBitsLen = len + 1;
for (var i = 0; i < oldBitsLen; i++)
{
var x = (long)bits[i];
x = ((x >> 1) & 0x55555555u) | ((x & 0x55555555u) << 1);
x = ((x >> 2) & 0x33333333u) | ((x & 0x33333333u) << 2);
x = ((x >> 4) & 0x0f0f0f0fu) | ((x & 0x0f0f0f0fu) << 4);
x = ((x >> 8) & 0x00ff00ffu) | ((x & 0x00ff00ffu) << 8);
x = ((x >> 16) & 0x0000ffffu) | ((x & 0x0000ffffu) << 16);
newBits[len - i] = (int)x;
}
// now correct the int's if the bit size isn't a multiple of 32
if (size != oldBitsLen * 32)
{
var leftOffset = oldBitsLen * 32 - size;
var mask = 1;
for (var i = 0; i < 31 - leftOffset; i++)
mask = (mask << 1) | 1;
var currentInt = (newBits[0] >> leftOffset) & mask;
for (var i = 1; i < oldBitsLen; i++)
{
var nextInt = newBits[i];
currentInt |= nextInt << (32 - leftOffset);
newBits[i - 1] = currentInt;
currentInt = (nextInt >> leftOffset) & mask;
}
newBits[oldBitsLen - 1] = currentInt;
}
bits = newBits;
}
private static int[] makeArray(int size)
{
return new int[(size + 31) >> 5];
}
/// <summary>
/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
/// </summary>
/// <param name="o">The <see cref="System.Object"/> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(Object o)
{
var other = o as BitArray;
if (other == null)
return false;
if (size != other.size)
return false;
for (var index = 0; index < size; index++)
{
if (bits[index] != other.bits[index])
return false;
}
return true;
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public override int GetHashCode()
{
var hash = size;
foreach (var bit in bits)
{
hash = 31 * hash + bit.GetHashCode();
}
return hash;
}
/// <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()
{
var result = new System.Text.StringBuilder(size);
for (int i = 0; i < size; i++)
{
if ((i & 0x07) == 0)
{
result.Append(' ');
}
result.Append(this[i] ? 'X' : '.');
}
return result.ToString();
}
/// <summary>
/// Erstellt ein neues Objekt, das eine Kopie der aktuellen Instanz darstellt.
/// </summary>
/// <returns>
/// Ein neues Objekt, das eine Kopie dieser Instanz darstellt.
/// </returns>
public object Clone()
{
return new BitArray((int[])bits.Clone(), size);
}
}
}

+ 435
- 0
shadowsocks-csharp/3rd/zxing/BitMatrix.cs View File

@@ -0,0 +1,435 @@
/*
* 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.Common
{
/// <summary>
/// <p>Represents a 2D matrix of bits. In function arguments below, and throughout the common
/// module, x is the column position, and y is the row position. The ordering is always x, y.
/// The origin is at the top-left.</p>
/// <p>Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins
/// with a new int. This is done intentionally so that we can copy out a row into a BitArray very
/// efficiently.</p>
/// <p>The ordering of bits is row-major. Within each int, the least significant bits are used first,
/// meaning they represent lower x values. This is compatible with BitArray's implementation.</p>
/// </summary>
/// <author>Sean Owen</author>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public sealed partial class BitMatrix
{
private readonly int width;
private readonly int height;
private readonly int rowSize;
private readonly int[] bits;
/// <returns> The width of the matrix
/// </returns>
public int Width
{
get
{
return width;
}
}
/// <returns> The height of the matrix
/// </returns>
public int Height
{
get
{
return height;
}
}
/// <summary> This method is for compatibility with older code. It's only logical to call if the matrix
/// is square, so I'm throwing if that's not the case.
///
/// </summary>
/// <returns> row/column dimension of this matrix
/// </returns>
public int Dimension
{
get
{
if (width != height)
{
throw new System.ArgumentException("Can't call getDimension() on a non-square matrix");
}
return width;
}
}
// A helper to construct a square matrix.
public BitMatrix(int dimension)
: this(dimension, dimension)
{
}
public BitMatrix(int width, int height)
{
if (width < 1 || height < 1)
{
throw new System.ArgumentException("Both dimensions must be greater than 0");
}
this.width = width;
this.height = height;
this.rowSize = (width + 31) >> 5;
bits = new int[rowSize * height];
}
internal BitMatrix(int width, int height, int rowSize, int[] bits)
{
this.width = width;
this.height = height;
this.rowSize = rowSize;
this.bits = bits;
}
internal BitMatrix(int width, int height, int[] bits)
{
this.width = width;
this.height = height;
this.rowSize = (width + 31) >> 5;
this.bits = bits;
}
/// <summary> <p>Gets the requested bit, where true means black.</p>
///
/// </summary>
/// <param name="x">The horizontal component (i.e. which column)
/// </param>
/// <param name="y">The vertical component (i.e. which row)
/// </param>
/// <returns> value of given bit in matrix
/// </returns>
public bool this[int x, int y]
{
get
{
int offset = y * rowSize + (x >> 5);
return (((int)((uint)(bits[offset]) >> (x & 0x1f))) & 1) != 0;
}
set
{
if (value)
{
int offset = y * rowSize + (x >> 5);
bits[offset] |= 1 << (x & 0x1f);
}
}
}
/// <summary> <p>Flips the given bit.</p>
///
/// </summary>
/// <param name="x">The horizontal component (i.e. which column)
/// </param>
/// <param name="y">The vertical component (i.e. which row)
/// </param>
public void flip(int x, int y)
{
int offset = y * rowSize + (x >> 5);
bits[offset] ^= 1 << (x & 0x1f);
}
/// <summary> Clears all bits (sets to false).</summary>
public void clear()
{
int max = bits.Length;
for (int i = 0; i < max; i++)
{
bits[i] = 0;
}
}
/// <summary> <p>Sets a square region of the bit matrix to true.</p>
///
/// </summary>
/// <param name="left">The horizontal position to begin at (inclusive)
/// </param>
/// <param name="top">The vertical position to begin at (inclusive)
/// </param>
/// <param name="width">The width of the region
/// </param>
/// <param name="height">The height of the region
/// </param>
public void setRegion(int left, int top, int width, int height)
{
if (top < 0 || left < 0)
{
throw new System.ArgumentException("Left and top must be nonnegative");
}
if (height < 1 || width < 1)
{
throw new System.ArgumentException("Height and width must be at least 1");
}
int right = left + width;
int bottom = top + height;
if (bottom > this.height || right > this.width)
{
throw new System.ArgumentException("The region must fit inside the matrix");
}
for (int y = top; y < bottom; y++)
{
int offset = y * rowSize;
for (int x = left; x < right; x++)
{
bits[offset + (x >> 5)] |= 1 << (x & 0x1f);
}
}
}
/// <summary> A fast method to retrieve one row of data from the matrix as a BitArray.
///
/// </summary>
/// <param name="y">The row to retrieve
/// </param>
/// <param name="row">An optional caller-allocated BitArray, will be allocated if null or too small
/// </param>
/// <returns> The resulting BitArray - this reference should always be used even when passing
/// your own row
/// </returns>
public BitArray getRow(int y, BitArray row)
{
if (row == null || row.Size < width)
{
row = new BitArray(width);
}
else
{
row.clear();
}
int offset = y * rowSize;
for (int x = 0; x < rowSize; x++)
{
row.setBulk(x << 5, bits[offset + x]);
}
return row;
}
/// <summary>
/// Sets the row.
/// </summary>
/// <param name="y">row to set</param>
/// <param name="row">{@link BitArray} to copy from</param>
public void setRow(int y, BitArray row)
{
Array.Copy(row.Array, 0, bits, y * rowSize, rowSize);
}
/// <summary>
/// Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees
/// </summary>
public void rotate180()
{
var width = Width;
var height = Height;
var topRow = new BitArray(width);
var bottomRow = new BitArray(width);
for (int i = 0; i < (height + 1)/2; i++)
{
topRow = getRow(i, topRow);
bottomRow = getRow(height - 1 - i, bottomRow);
topRow.reverse();
bottomRow.reverse();
setRow(i, bottomRow);
setRow(height - 1 - i, topRow);
}
}
/// <summary>
/// This is useful in detecting the enclosing rectangle of a 'pure' barcode.
/// </summary>
/// <returns>{left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white</returns>
public int[] getEnclosingRectangle()
{
int left = width;
int top = height;
int right = -1;
int bottom = -1;
for (int y = 0; y < height; y++)
{
for (int x32 = 0; x32 < rowSize; x32++)
{
int theBits = bits[y * rowSize + x32];
if (theBits != 0)
{
if (y < top)
{
top = y;
}
if (y > bottom)
{
bottom = y;
}
if (x32 * 32 < left)
{
int bit = 0;
while ((theBits << (31 - bit)) == 0)
{
bit++;
}
if ((x32 * 32 + bit) < left)
{
left = x32 * 32 + bit;
}
}
if (x32 * 32 + 31 > right)
{
int bit = 31;
while (((int)((uint)theBits >> bit)) == 0) // (theBits >>> bit)
{
bit--;
}
if ((x32 * 32 + bit) > right)
{
right = x32 * 32 + bit;
}
}
}
}
}
int widthTmp = right - left;
int heightTmp = bottom - top;
if (widthTmp < 0 || heightTmp < 0)
{
return null;
}
return new [] { left, top, widthTmp, heightTmp };
}
/// <summary>
/// This is useful in detecting a corner of a 'pure' barcode.
/// </summary>
/// <returns>{x,y} coordinate of top-left-most 1 bit, or null if it is all white</returns>
public int[] getTopLeftOnBit()
{
int bitsOffset = 0;
while (bitsOffset < bits.Length && bits[bitsOffset] == 0)
{
bitsOffset++;
}
if (bitsOffset == bits.Length)
{
return null;
}
int y = bitsOffset / rowSize;
int x = (bitsOffset % rowSize) << 5;
int theBits = bits[bitsOffset];
int bit = 0;
while ((theBits << (31 - bit)) == 0)
{
bit++;
}
x += bit;
return new[] { x, y };
}
public int[] getBottomRightOnBit()
{
int bitsOffset = bits.Length - 1;
while (bitsOffset >= 0 && bits[bitsOffset] == 0)
{
bitsOffset--;
}
if (bitsOffset < 0)
{
return null;
}
int y = bitsOffset / rowSize;
int x = (bitsOffset % rowSize) << 5;
int theBits = bits[bitsOffset];
int bit = 31;
while (((int)((uint)theBits >> bit)) == 0) // (theBits >>> bit)
{
bit--;
}
x += bit;
return new int[] { x, y };
}
public override bool Equals(object obj)
{
if (!(obj is BitMatrix))
{
return false;
}
BitMatrix other = (BitMatrix)obj;
if (width != other.width || height != other.height ||
rowSize != other.rowSize || bits.Length != other.bits.Length)
{
return false;
}
for (int i = 0; i < bits.Length; i++)
{
if (bits[i] != other.bits[i])
{
return false;
}
}
return true;
}
public override int GetHashCode()
{
int hash = width;
hash = 31 * hash + width;
hash = 31 * hash + height;
hash = 31 * hash + rowSize;
foreach (var bit in bits)
{
hash = 31 * hash + bit.GetHashCode();
}
return hash;
}
public override String ToString()
{
var result = new System.Text.StringBuilder(height * (width + 1));
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
result.Append(this[x, y] ? "X " : " ");
}
#if WindowsCE
result.Append("\r\n");
#else
result.AppendLine("");
#endif
}
return result.ToString();
}
public object Clone()
{
return new BitMatrix(width, height, rowSize, (int[])bits.Clone());
}
}
}

+ 40
- 0
shadowsocks-csharp/3rd/zxing/BlockPair.cs View File

@@ -0,0 +1,40 @@
/*
* Copyright 2008 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
{
internal sealed class BlockPair
{
private readonly byte[] dataBytes;
private readonly byte[] errorCorrectionBytes;
public BlockPair(byte[] data, byte[] errorCorrection)
{
dataBytes = data;
errorCorrectionBytes = errorCorrection;
}
public byte[] DataBytes
{
get { return dataBytes; }
}
public byte[] ErrorCorrectionBytes
{
get { return errorCorrectionBytes; }
}
}
}

+ 148
- 0
shadowsocks-csharp/3rd/zxing/ByteMatrix.cs View File

@@ -0,0 +1,148 @@
/*
* Copyright 2008 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.Text;
namespace ZXing.QrCode.Internal
{
/// <summary>
/// JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned
/// 0, 1 and 2 I'm going to use less memory and go with bytes.
/// </summary>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public sealed class ByteMatrix
{
private readonly byte[][] bytes;
private readonly int width;
private readonly int height;
/// <summary>
/// Initializes a new instance of the <see cref="ByteMatrix"/> class.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
public ByteMatrix(int width, int height)
{
bytes = new byte[height][];
for (var i = 0; i < height; i++)
bytes[i] = new byte[width];
this.width = width;
this.height = height;
}
/// <summary>
/// Gets the height.
/// </summary>
public int Height
{
get { return height; }
}
/// <summary>
/// Gets the width.
/// </summary>
public int Width
{
get { return width; }
}
/// <summary>
/// Gets or sets the <see cref="System.Int32"/> with the specified x.
/// </summary>
public int this[int x, int y]
{
get { return bytes[y][x]; }
set { bytes[y][x] = (byte)value; }
}
/// <summary>
/// an internal representation as bytes, in row-major order. array[y][x] represents point (x,y)
/// </summary>
public byte[][] Array
{
get { return bytes; }
}
/// <summary>
/// Sets the specified x.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="value">The value.</param>
public void set(int x, int y, byte value)
{
bytes[y][x] = value;
}
/// <summary>
/// Sets the specified x.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="value">if set to <c>true</c> [value].</param>
public void set(int x, int y, bool value)
{
bytes[y][x] = (byte)(value ? 1 : 0);
}
/// <summary>
/// Clears the specified value.
/// </summary>
/// <param name="value">The value.</param>
public void clear(byte value)
{
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
bytes[y][x] = value;
}
}
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
override public String ToString()
{
var result = new StringBuilder(2 * width * height + 2);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
switch (bytes[y][x])
{
case 0:
result.Append(" 0");
break;
case 1:
result.Append(" 1");
break;
default:
result.Append(" ");
break;
}
}
result.Append('\n');
}
return result.ToString();
}
}
}

+ 131
- 0
shadowsocks-csharp/3rd/zxing/EncodeHintType.cs View File

@@ -0,0 +1,131 @@
/*
* Copyright 2008 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
{
/// <summary>
/// These are a set of hints that you may pass to Writers to specify their behavior.
/// </summary>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public enum EncodeHintType
{
/// <summary>
/// Specifies the width of the barcode image
/// type: <see cref="System.Int32" />
/// </summary>
WIDTH,
/// <summary>
/// Specifies the height of the barcode image
/// type: <see cref="System.Int32" />
/// </summary>
HEIGHT,
/// <summary>
/// Don't put the content string into the output image.
/// type: <see cref="System.Boolean" />
/// </summary>
PURE_BARCODE,
/// <summary>
/// Specifies what degree of error correction to use, for example in QR Codes.
/// Type depends on the encoder. For example for QR codes it's type
/// <see cref="ZXing.QrCode.Internal.ErrorCorrectionLevel" />
/// For Aztec it is of type <see cref="System.Int32" />, representing the minimal percentage of error correction words.
/// Note: an Aztec symbol should have a minimum of 25% EC words.
/// For PDF417 it is of type <see cref="ZXing.PDF417.Internal.PDF417ErrorCorrectionLevel"/> or <see cref="System.Int32" /> (between 0 and 8),
/// </summary>
ERROR_CORRECTION,
/// <summary>
/// Specifies what character encoding to use where applicable.
/// type: <see cref="System.String" />
/// </summary>
CHARACTER_SET,
/// <summary>
/// Specifies margin, in pixels, to use when generating the barcode. The meaning can vary
/// by format; for example it controls margin before and after the barcode horizontally for
/// most 1D formats.
/// type: <see cref="System.Int32" />
/// </summary>
MARGIN,
/// <summary>
/// Specifies whether to use compact mode for PDF417.
/// type: <see cref="System.Boolean" />
/// </summary>
PDF417_COMPACT,
/// <summary>
/// Specifies what compaction mode to use for PDF417.
/// type: <see cref="ZXing.PDF417.Internal.Compaction" />
/// </summary>
PDF417_COMPACTION,
/// <summary>
/// Specifies the minimum and maximum number of rows and columns for PDF417.
/// type: <see cref="ZXing.PDF417.Internal.Dimensions" />
/// </summary>
PDF417_DIMENSIONS,
/// <summary>
/// Don't append ECI segment.
/// That is against the specification of QR Code but some
/// readers have problems if the charset is switched from
/// ISO-8859-1 (default) to UTF-8 with the necessary ECI segment.
/// If you set the property to true you can use UTF-8 encoding
/// and the ECI segment is omitted.
/// type: <see cref="System.Boolean" />
/// </summary>
DISABLE_ECI,
/// <summary>
/// Specifies the matrix shape for Data Matrix (type <see cref="ZXing.Datamatrix.Encoder.SymbolShapeHint"/>)
/// </summary>
DATA_MATRIX_SHAPE,
/// <summary>
/// Specifies a minimum barcode size (type <see cref="ZXing.Dimension"/>). Only applicable to Data Matrix now.
/// </summary>
MIN_SIZE,
/// <summary>
/// Specifies a maximum barcode size (type <see cref="ZXing.Dimension"/>). Only applicable to Data Matrix now.
/// </summary>
MAX_SIZE,
/// <summary>
/// if true, don't switch to codeset C for numbers
/// </summary>
CODE128_FORCE_CODESET_B,
/// <summary>
/// Specifies the default encodation for Data Matrix (type <see cref="ZXing.Datamatrix.Encoder.Encodation"/>)
/// Make sure that the content fits into the encodation value, otherwise there will be an exception thrown.
/// standard value: Encodation.ASCII
/// </summary>
DATA_MATRIX_DEFAULT_ENCODATION,
/// <summary>
/// Specifies the required number of layers for an Aztec code:
/// a negative number (-1, -2, -3, -4) specifies a compact Aztec code
/// 0 indicates to use the minimum number of layers (the default)
/// a positive number (1, 2, .. 32) specifies a normal (non-compact) Aztec code
/// </summary>
AZTEC_LAYERS,
}
}

+ 762
- 0
shadowsocks-csharp/3rd/zxing/Encoder.cs View File

@@ -0,0 +1,762 @@
/*
* Copyright 2008 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;
using ZXing.Common.ReedSolomon;
namespace ZXing.QrCode.Internal
{
/// <summary>
/// </summary>
/// <author>satorux@google.com (Satoru Takabayashi) - creator</author>
/// <author>dswitkin@google.com (Daniel Switkin) - ported from C++</author>
public static class Encoder
{
// The original table is defined in the table 5 of JISX0510:2004 (p.19).
private static readonly int[] ALPHANUMERIC_TABLE = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f
36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f
};
internal static String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1";
// The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details.
// Basically it applies four rules and summate all penalties.
private static int calculateMaskPenalty(ByteMatrix matrix)
{
return MaskUtil.applyMaskPenaltyRule1(matrix)
+ MaskUtil.applyMaskPenaltyRule2(matrix)
+ MaskUtil.applyMaskPenaltyRule3(matrix)
+ MaskUtil.applyMaskPenaltyRule4(matrix);
}
/// <summary>
/// Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen
/// internally by chooseMode(). On success, store the result in "qrCode".
/// We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for
/// "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very
/// strong error correction for this purpose.
/// Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode()
/// with which clients can specify the encoding mode. For now, we don't need the functionality.
/// </summary>
/// <param name="content">text to encode</param>
/// <param name="ecLevel">error correction level to use</param>
/// <returns><see cref="QRCode"/> representing the encoded QR code</returns>
public static QRCode encode(String content, ErrorCorrectionLevel ecLevel)
{
return encode(content, ecLevel, null);
}
/// <summary>
/// Encodes the specified content.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="ecLevel">The ec level.</param>
/// <param name="hints">The hints.</param>
/// <returns></returns>
public static QRCode encode(String content,
ErrorCorrectionLevel ecLevel,
IDictionary<EncodeHintType, object> hints)
{
// Determine what character encoding has been specified by the caller, if any
#if !SILVERLIGHT || WINDOWS_PHONE
String encoding = hints == null || !hints.ContainsKey(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET];
if (encoding == null)
{
encoding = DEFAULT_BYTE_MODE_ENCODING;
}
bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding);
#else
// Silverlight supports only UTF-8 and UTF-16 out-of-the-box
const string encoding = "UTF-8";
// caller of the method can only control if the ECI segment should be written
// character set is fixed to UTF-8; but some scanners doesn't like the ECI segment
bool generateECI = (hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET));
#endif
// Pick an encoding mode appropriate for the content. Note that this will not attempt to use
// multiple modes / segments even if that were more efficient. Twould be nice.
Mode mode = chooseMode(content, encoding);
// This will store the header information, like mode and
// length, as well as "header" segments like an ECI segment.
BitArray headerBits = new BitArray();
/*
// Append ECI segment if applicable
if (mode == Mode.BYTE && generateECI)
{
CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding);
if (eci != null)
{
var eciIsExplicitDisabled = (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) ? (bool)hints[EncodeHintType.DISABLE_ECI] : false);
if (!eciIsExplicitDisabled)
{
appendECI(eci, headerBits);
}
}
}
* */
// (With ECI in place,) Write the mode marker
appendModeInfo(mode, headerBits);
// Collect data within the main segment, separately, to count its size if needed. Don't add it to
// main payload yet.
BitArray dataBits = new BitArray();
appendBytes(content, mode, dataBits, encoding);
// Hard part: need to know version to know how many bits length takes. But need to know how many
// bits it takes to know version. First we take a guess at version by assuming version will be
// the minimum, 1:
int provisionalBitsNeeded = headerBits.Size
+ mode.getCharacterCountBits(Version.getVersionForNumber(1))
+ dataBits.Size;
Version provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel);
// Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
int bitsNeeded = headerBits.Size
+ mode.getCharacterCountBits(provisionalVersion)
+ dataBits.Size;
Version version = chooseVersion(bitsNeeded, ecLevel);
BitArray headerAndDataBits = new BitArray();
headerAndDataBits.appendBitArray(headerBits);
// Find "length" of main segment and write it
int numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length;
appendLengthInfo(numLetters, version, mode, headerAndDataBits);
// Put data together into the overall payload
headerAndDataBits.appendBitArray(dataBits);
Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);
int numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords;
// Terminate the bits properly.
terminateBits(numDataBytes, headerAndDataBits);
// Interleave data bits with error correction code.
BitArray finalBits = interleaveWithECBytes(headerAndDataBits,
version.TotalCodewords,
numDataBytes,
ecBlocks.NumBlocks);
QRCode qrCode = new QRCode
{
ECLevel = ecLevel,
Mode = mode,
Version = version
};
// Choose the mask pattern and set to "qrCode".
int dimension = version.DimensionForVersion;
ByteMatrix matrix = new ByteMatrix(dimension, dimension);
int maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix);
qrCode.MaskPattern = maskPattern;
// Build the matrix and set it to "qrCode".
MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix);
qrCode.Matrix = matrix;
return qrCode;
}
/// <summary>
/// Gets the alphanumeric code.
/// </summary>
/// <param name="code">The code.</param>
/// <returns>the code point of the table used in alphanumeric mode or
/// -1 if there is no corresponding code in the table.</returns>
internal static int getAlphanumericCode(int code)
{
if (code < ALPHANUMERIC_TABLE.Length)
{
return ALPHANUMERIC_TABLE[code];
}
return -1;
}
/// <summary>
/// Chooses the mode.
/// </summary>
/// <param name="content">The content.</param>
/// <returns></returns>
public static Mode chooseMode(String content)
{
return chooseMode(content, null);
}
/// <summary>
/// Choose the best mode by examining the content. Note that 'encoding' is used as a hint;
/// if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="encoding">The encoding.</param>
/// <returns></returns>
private static Mode chooseMode(String content, String encoding)
{
if ("Shift_JIS".Equals(encoding))
{
// Choose Kanji mode if all input are double-byte characters
return isOnlyDoubleByteKanji(content) ? Mode.KANJI : Mode.BYTE;
}
bool hasNumeric = false;
bool hasAlphanumeric = false;
for (int i = 0; i < content.Length; ++i)
{
char c = content[i];
if (c >= '0' && c <= '9')
{
hasNumeric = true;
}
else if (getAlphanumericCode(c) != -1)
{
hasAlphanumeric = true;
}
else
{
return Mode.BYTE;
}
}
if (hasAlphanumeric)
{
return Mode.ALPHANUMERIC;
}
if (hasNumeric)
{
return Mode.NUMERIC;
}
return Mode.BYTE;
}
private static bool isOnlyDoubleByteKanji(String content)
{
byte[] bytes;
try
{
bytes = Encoding.GetEncoding("Shift_JIS").GetBytes(content);
}
catch (Exception )
{
return false;
}
int length = bytes.Length;
if (length % 2 != 0)
{
return false;
}
for (int i = 0; i < length; i += 2)
{
int byte1 = bytes[i] & 0xFF;
if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB))
{
return false;
}
}
return true;
}
private static int chooseMaskPattern(BitArray bits,
ErrorCorrectionLevel ecLevel,
Version version,
ByteMatrix matrix)
{
int minPenalty = Int32.MaxValue; // Lower penalty is better.
int bestMaskPattern = -1;
// We try all mask patterns to choose the best one.
for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++)
{
MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix);
int penalty = calculateMaskPenalty(matrix);
if (penalty < minPenalty)
{
minPenalty = penalty;
bestMaskPattern = maskPattern;
}
}
return bestMaskPattern;
}
private static Version chooseVersion(int numInputBits, ErrorCorrectionLevel ecLevel)
{
// In the following comments, we use numbers of Version 7-H.
for (int versionNum = 1; versionNum <= 40; versionNum++)
{
Version version = Version.getVersionForNumber(versionNum);
// numBytes = 196
int numBytes = version.TotalCodewords;
// getNumECBytes = 130
Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);
int numEcBytes = ecBlocks.TotalECCodewords;
// getNumDataBytes = 196 - 130 = 66
int numDataBytes = numBytes - numEcBytes;
int totalInputBytes = (numInputBits + 7) / 8;
if (numDataBytes >= totalInputBytes)
{
return version;
}
}
throw new Exception("Data too big");
}
/// <summary>
/// Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
/// </summary>
/// <param name="numDataBytes">The num data bytes.</param>
/// <param name="bits">The bits.</param>
internal static void terminateBits(int numDataBytes, BitArray bits)
{
int capacity = numDataBytes << 3;
if (bits.Size > capacity)
{
throw new Exception("data bits cannot fit in the QR Code" + bits.Size + " > " +
capacity);
}
for (int i = 0; i < 4 && bits.Size < capacity; ++i)
{
bits.appendBit(false);
}
// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
// If the last byte isn't 8-bit aligned, we'll add padding bits.
int numBitsInLastByte = bits.Size & 0x07;
if (numBitsInLastByte > 0)
{
for (int i = numBitsInLastByte; i < 8; i++)
{
bits.appendBit(false);
}
}
// If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
int numPaddingBytes = numDataBytes - bits.SizeInBytes;
for (int i = 0; i < numPaddingBytes; ++i)
{
bits.appendBits((i & 0x01) == 0 ? 0xEC : 0x11, 8);
}
if (bits.Size != capacity)
{
throw new Exception("Bits size does not equal capacity");
}
}
/// <summary>
/// Get number of data bytes and number of error correction bytes for block id "blockID". Store
/// the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
/// JISX0510:2004 (p.30)
/// </summary>
/// <param name="numTotalBytes">The num total bytes.</param>
/// <param name="numDataBytes">The num data bytes.</param>
/// <param name="numRSBlocks">The num RS blocks.</param>
/// <param name="blockID">The block ID.</param>
/// <param name="numDataBytesInBlock">The num data bytes in block.</param>
/// <param name="numECBytesInBlock">The num EC bytes in block.</param>
internal static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes,
int numDataBytes,
int numRSBlocks,
int blockID,
int[] numDataBytesInBlock,
int[] numECBytesInBlock)
{
if (blockID >= numRSBlocks)
{
throw new Exception("Block ID too large");
}
// numRsBlocksInGroup2 = 196 % 5 = 1
int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
// numRsBlocksInGroup1 = 5 - 1 = 4
int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
// numTotalBytesInGroup1 = 196 / 5 = 39
int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
// numTotalBytesInGroup2 = 39 + 1 = 40
int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
// numDataBytesInGroup1 = 66 / 5 = 13
int numDataBytesInGroup1 = numDataBytes / numRSBlocks;
// numDataBytesInGroup2 = 13 + 1 = 14
int numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
// numEcBytesInGroup1 = 39 - 13 = 26
int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
// numEcBytesInGroup2 = 40 - 14 = 26
int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
// Sanity checks.
// 26 = 26
if (numEcBytesInGroup1 != numEcBytesInGroup2)
{
throw new Exception("EC bytes mismatch");
}
// 5 = 4 + 1.
if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2)
{
throw new Exception("RS blocks mismatch");
}
// 196 = (13 + 26) * 4 + (14 + 26) * 1
if (numTotalBytes !=
((numDataBytesInGroup1 + numEcBytesInGroup1) *
numRsBlocksInGroup1) +
((numDataBytesInGroup2 + numEcBytesInGroup2) *
numRsBlocksInGroup2))
{
throw new Exception("Total bytes mismatch");
}
if (blockID < numRsBlocksInGroup1)
{
numDataBytesInBlock[0] = numDataBytesInGroup1;
numECBytesInBlock[0] = numEcBytesInGroup1;
}
else
{
numDataBytesInBlock[0] = numDataBytesInGroup2;
numECBytesInBlock[0] = numEcBytesInGroup2;
}
}
/// <summary>
/// Interleave "bits" with corresponding error correction bytes. On success, store the result in
/// "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
/// </summary>
/// <param name="bits">The bits.</param>
/// <param name="numTotalBytes">The num total bytes.</param>
/// <param name="numDataBytes">The num data bytes.</param>
/// <param name="numRSBlocks">The num RS blocks.</param>
/// <returns></returns>
internal static BitArray interleaveWithECBytes(BitArray bits,
int numTotalBytes,
int numDataBytes,
int numRSBlocks)
{
// "bits" must have "getNumDataBytes" bytes of data.
if (bits.SizeInBytes != numDataBytes)
{
throw new Exception("Number of bits and data bytes does not match");
}
// Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
// store the divided data bytes blocks and error correction bytes blocks into "blocks".
int dataBytesOffset = 0;
int maxNumDataBytes = 0;
int maxNumEcBytes = 0;
// Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
var blocks = new List<BlockPair>(numRSBlocks);
for (int i = 0; i < numRSBlocks; ++i)
{
int[] numDataBytesInBlock = new int[1];
int[] numEcBytesInBlock = new int[1];
getNumDataBytesAndNumECBytesForBlockID(
numTotalBytes, numDataBytes, numRSBlocks, i,
numDataBytesInBlock, numEcBytesInBlock);
int size = numDataBytesInBlock[0];
byte[] dataBytes = new byte[size];
bits.toBytes(8 * dataBytesOffset, dataBytes, 0, size);
byte[] ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]);
blocks.Add(new BlockPair(dataBytes, ecBytes));
maxNumDataBytes = Math.Max(maxNumDataBytes, size);
maxNumEcBytes = Math.Max(maxNumEcBytes, ecBytes.Length);
dataBytesOffset += numDataBytesInBlock[0];
}
if (numDataBytes != dataBytesOffset)
{
throw new Exception("Data bytes does not match offset");
}
BitArray result = new BitArray();
// First, place data blocks.
for (int i = 0; i < maxNumDataBytes; ++i)
{
foreach (BlockPair block in blocks)
{
byte[] dataBytes = block.DataBytes;
if (i < dataBytes.Length)
{
result.appendBits(dataBytes[i], 8);
}
}
}
// Then, place error correction blocks.
for (int i = 0; i < maxNumEcBytes; ++i)
{
foreach (BlockPair block in blocks)
{
byte[] ecBytes = block.ErrorCorrectionBytes;
if (i < ecBytes.Length)
{
result.appendBits(ecBytes[i], 8);
}
}
}
if (numTotalBytes != result.SizeInBytes)
{ // Should be same.
throw new Exception("Interleaving error: " + numTotalBytes + " and " +
result.SizeInBytes + " differ.");
}
return result;
}
internal static byte[] generateECBytes(byte[] dataBytes, int numEcBytesInBlock)
{
int numDataBytes = dataBytes.Length;
int[] toEncode = new int[numDataBytes + numEcBytesInBlock];
for (int i = 0; i < numDataBytes; i++)
{
toEncode[i] = dataBytes[i] & 0xFF;
}
new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, numEcBytesInBlock);
byte[] ecBytes = new byte[numEcBytesInBlock];
for (int i = 0; i < numEcBytesInBlock; i++)
{
ecBytes[i] = (byte)toEncode[numDataBytes + i];
}
return ecBytes;
}
/// <summary>
/// Append mode info. On success, store the result in "bits".
/// </summary>
/// <param name="mode">The mode.</param>
/// <param name="bits">The bits.</param>
internal static void appendModeInfo(Mode mode, BitArray bits)
{
bits.appendBits(mode.Bits, 4);
}
/// <summary>
/// Append length info. On success, store the result in "bits".
/// </summary>
/// <param name="numLetters">The num letters.</param>
/// <param name="version">The version.</param>
/// <param name="mode">The mode.</param>
/// <param name="bits">The bits.</param>
internal static void appendLengthInfo(int numLetters, Version version, Mode mode, BitArray bits)
{
int numBits = mode.getCharacterCountBits(version);
if (numLetters >= (1 << numBits))
{
throw new Exception(numLetters + " is bigger than " + ((1 << numBits) - 1));
}
bits.appendBits(numLetters, numBits);
}
/// <summary>
/// Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
/// </summary>
/// <param name="content">The content.</param>
/// <param name="mode">The mode.</param>
/// <param name="bits">The bits.</param>
/// <param name="encoding">The encoding.</param>
internal static void appendBytes(String content,
Mode mode,
BitArray bits,
String encoding)
{
if (mode.Equals(Mode.NUMERIC))
appendNumericBytes(content, bits);
else
if (mode.Equals(Mode.ALPHANUMERIC))
appendAlphanumericBytes(content, bits);
else
if (mode.Equals(Mode.BYTE))
append8BitBytes(content, bits, encoding);
else
if (mode.Equals(Mode.KANJI))
appendKanjiBytes(content, bits);
else
throw new Exception("Invalid mode: " + mode);
}
internal static void appendNumericBytes(String content, BitArray bits)
{
int length = content.Length;
int i = 0;
while (i < length)
{
int num1 = content[i] - '0';
if (i + 2 < length)
{
// Encode three numeric letters in ten bits.
int num2 = content[i + 1] - '0';
int num3 = content[i + 2] - '0';
bits.appendBits(num1 * 100 + num2 * 10 + num3, 10);
i += 3;
}
else if (i + 1 < length)
{
// Encode two numeric letters in seven bits.
int num2 = content[i + 1] - '0';
bits.appendBits(num1 * 10 + num2, 7);
i += 2;
}
else
{
// Encode one numeric letter in four bits.
bits.appendBits(num1, 4);
i++;
}
}
}
internal static void appendAlphanumericBytes(String content, BitArray bits)
{
int length = content.Length;
int i = 0;
while (i < length)
{
int code1 = getAlphanumericCode(content[i]);
if (code1 == -1)
{
throw new Exception();
}
if (i + 1 < length)
{
int code2 = getAlphanumericCode(content[i + 1]);
if (code2 == -1)
{
throw new Exception();
}
// Encode two alphanumeric letters in 11 bits.
bits.appendBits(code1 * 45 + code2, 11);
i += 2;
}
else
{
// Encode one alphanumeric letter in six bits.
bits.appendBits(code1, 6);
i++;
}
}
}
internal static void append8BitBytes(String content, BitArray bits, String encoding)
{
byte[] bytes;
try
{
bytes = Encoding.GetEncoding(encoding).GetBytes(content);
}
#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")
{
bytes = Encoding.GetEncoding(1252).GetBytes(content);
}
else
{
bytes = Encoding.GetEncoding("UTF-8").GetBytes(content);
}
}
catch (Exception uee)
{
throw new WriterException(uee.Message, uee);
}
}
#endif
catch (Exception uee)
{
throw new Exception(uee.Message, uee);
}
foreach (byte b in bytes)
{
bits.appendBits(b, 8);
}
}
internal static void appendKanjiBytes(String content, BitArray bits)
{
byte[] bytes;
try
{
bytes = Encoding.GetEncoding("Shift_JIS").GetBytes(content);
}
catch (Exception uee)
{
throw new Exception(uee.Message, uee);
}
int length = bytes.Length;
for (int i = 0; i < length; i += 2)
{
int byte1 = bytes[i] & 0xFF;
int byte2 = bytes[i + 1] & 0xFF;
int code = (byte1 << 8) | byte2;
int subtracted = -1;
if (code >= 0x8140 && code <= 0x9ffc)
{
subtracted = code - 0x8140;
}
else if (code >= 0xe040 && code <= 0xebbf)
{
subtracted = code - 0xc140;
}
if (subtracted == -1)
{
throw new Exception("Invalid byte sequence");
}
int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
bits.appendBits(encoded, 13);
}
}
/*
private static void appendECI(CharacterSetECI eci, BitArray bits)
{
bits.appendBits(Mode.ECI.Bits, 4);
// This is correct for values up to 127, which is all we need now.
bits.appendBits(eci.Value, 8);
}
* */
}
}

+ 109
- 0
shadowsocks-csharp/3rd/zxing/ErrorCorrectionLevel.cs 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];
}
}
}

+ 197
- 0
shadowsocks-csharp/3rd/zxing/FormatInformation.cs 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;
}
}
}

+ 210
- 0
shadowsocks-csharp/3rd/zxing/GenericGF.cs View File

@@ -0,0 +1,210 @@
/*
* 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.Common.ReedSolomon
{
/// <summary>
/// <p>This class contains utility methods for performing mathematical operations over
/// the Galois Fields. Operations use a given primitive polynomial in calculations.</p>
/// <p>Throughout this package, elements of the GF are represented as an {@code int}
/// for convenience and speed (but at the cost of memory).
/// </p>
/// </summary>
/// <author>Sean Owen</author>
public sealed class GenericGF
{
public static GenericGF AZTEC_DATA_12 = new GenericGF(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1
public static GenericGF AZTEC_DATA_10 = new GenericGF(0x409, 1024, 1); // x^10 + x^3 + 1
public static GenericGF AZTEC_DATA_6 = new GenericGF(0x43, 64, 1); // x^6 + x + 1
public static GenericGF AZTEC_PARAM = new GenericGF(0x13, 16, 1); // x^4 + x + 1
public static GenericGF QR_CODE_FIELD_256 = new GenericGF(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1
public static GenericGF DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1
public static GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256;
public static GenericGF MAXICODE_FIELD_64 = AZTEC_DATA_6;
private int[] expTable;
private int[] logTable;
private GenericGFPoly zero;
private GenericGFPoly one;
private readonly int size;
private readonly int primitive;
private readonly int generatorBase;
/// <summary>
/// Create a representation of GF(size) using the given primitive polynomial.
/// </summary>
/// <param name="primitive">irreducible polynomial whose coefficients are represented by
/// * the bits of an int, where the least-significant bit represents the constant
/// * coefficient</param>
/// <param name="size">the size of the field</param>
/// <param name="genBase">the factor b in the generator polynomial can be 0- or 1-based
/// * (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))).
/// * In most cases it should be 1, but for QR code it is 0.</param>
public GenericGF(int primitive, int size, int genBase)
{
this.primitive = primitive;
this.size = size;
this.generatorBase = genBase;
expTable = new int[size];
logTable = new int[size];
int x = 1;
for (int i = 0; i < size; i++)
{
expTable[i] = x;
x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
if (x >= size)
{
x ^= primitive;
x &= size - 1;
}
}
for (int i = 0; i < size - 1; i++)
{
logTable[expTable[i]] = i;
}
// logTable[0] == 0 but this should never be used
zero = new GenericGFPoly(this, new int[] { 0 });
one = new GenericGFPoly(this, new int[] { 1 });
}
internal GenericGFPoly Zero
{
get
{
return zero;
}
}
internal GenericGFPoly One
{
get
{
return one;
}
}
/// <summary>
/// Builds the monomial.
/// </summary>
/// <param name="degree">The degree.</param>
/// <param name="coefficient">The coefficient.</param>
/// <returns>the monomial representing coefficient * x^degree</returns>
internal GenericGFPoly buildMonomial(int degree, int coefficient)
{
if (degree < 0)
{
throw new ArgumentException();
}
if (coefficient == 0)
{
return zero;
}
int[] coefficients = new int[degree + 1];
coefficients[0] = coefficient;
return new GenericGFPoly(this, coefficients);
}
/// <summary>
/// Implements both addition and subtraction -- they are the same in GF(size).
/// </summary>
/// <returns>sum/difference of a and b</returns>
static internal int addOrSubtract(int a, int b)
{
return a ^ b;
}
/// <summary>
/// Exps the specified a.
/// </summary>
/// <returns>2 to the power of a in GF(size)</returns>
internal int exp(int a)
{
return expTable[a];
}
/// <summary>
/// Logs the specified a.
/// </summary>
/// <param name="a">A.</param>
/// <returns>base 2 log of a in GF(size)</returns>
internal int log(int a)
{
if (a == 0)
{
throw new ArgumentException();
}
return logTable[a];
}
/// <summary>
/// Inverses the specified a.
/// </summary>
/// <returns>multiplicative inverse of a</returns>
internal int inverse(int a)
{
if (a == 0)
{
throw new ArithmeticException();
}
return expTable[size - logTable[a] - 1];
}
/// <summary>
/// Multiplies the specified a with b.
/// </summary>
/// <param name="a">A.</param>
/// <param name="b">The b.</param>
/// <returns>product of a and b in GF(size)</returns>
internal int multiply(int a, int b)
{
if (a == 0 || b == 0)
{
return 0;
}
return expTable[(logTable[a] + logTable[b]) % (size - 1)];
}
/// <summary>
/// Gets the size.
/// </summary>
public int Size
{
get { return size; }
}
/// <summary>
/// Gets the generator base.
/// </summary>
public int GeneratorBase
{
get { return generatorBase; }
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
override public String ToString()
{
return "GF(0x" + primitive.ToString("X") + ',' + size + ')';
}
}
}

+ 331
- 0
shadowsocks-csharp/3rd/zxing/GenericGFPoly.cs View File

@@ -0,0 +1,331 @@
/*
* 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.Text;
namespace ZXing.Common.ReedSolomon
{
/// <summary>
/// <p>Represents a polynomial whose coefficients are elements of a GF.
/// Instances of this class are immutable.</p>
/// <p>Much credit is due to William Rucklidge since portions of this code are an indirect
/// port of his C++ Reed-Solomon implementation.</p>
/// </summary>
/// <author>Sean Owen</author>
internal sealed class GenericGFPoly
{
private readonly GenericGF field;
private readonly int[] coefficients;
/// <summary>
/// Initializes a new instance of the <see cref="GenericGFPoly"/> class.
/// </summary>
/// <param name="field">the {@link GenericGF} instance representing the field to use
/// to perform computations</param>
/// <param name="coefficients">coefficients as ints representing elements of GF(size), arranged
/// from most significant (highest-power term) coefficient to least significant</param>
/// <exception cref="ArgumentException">if argument is null or empty,
/// or if leading coefficient is 0 and this is not a
/// constant polynomial (that is, it is not the monomial "0")</exception>
internal GenericGFPoly(GenericGF field, int[] coefficients)
{
if (coefficients.Length == 0)
{
throw new ArgumentException();
}
this.field = field;
int coefficientsLength = coefficients.Length;
if (coefficientsLength > 1 && coefficients[0] == 0)
{
// Leading term must be non-zero for anything except the constant polynomial "0"
int firstNonZero = 1;
while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0)
{
firstNonZero++;
}
if (firstNonZero == coefficientsLength)
{
this.coefficients = new int[]{0};
}
else
{
this.coefficients = new int[coefficientsLength - firstNonZero];
Array.Copy(coefficients,
firstNonZero,
this.coefficients,
0,
this.coefficients.Length);
}
}
else
{
this.coefficients = coefficients;
}
}
internal int[] Coefficients
{
get { return coefficients; }
}
/// <summary>
/// degree of this polynomial
/// </summary>
internal int Degree
{
get
{
return coefficients.Length - 1;
}
}
/// <summary>
/// Gets a value indicating whether this <see cref="GenericGFPoly"/> is zero.
/// </summary>
/// <value>true iff this polynomial is the monomial "0"</value>
internal bool isZero
{
get { return coefficients[0] == 0; }
}
/// <summary>
/// coefficient of x^degree term in this polynomial
/// </summary>
/// <param name="degree">The degree.</param>
/// <returns>coefficient of x^degree term in this polynomial</returns>
internal int getCoefficient(int degree)
{
return coefficients[coefficients.Length - 1 - degree];
}
/// <summary>
/// evaluation of this polynomial at a given point
/// </summary>
/// <param name="a">A.</param>
/// <returns>evaluation of this polynomial at a given point</returns>
internal int evaluateAt(int a)
{
int result = 0;
if (a == 0)
{
// Just return the x^0 coefficient
return getCoefficient(0);
}
int size = coefficients.Length;
if (a == 1)
{
// Just the sum of the coefficients
foreach (var coefficient in coefficients)
{
result = GenericGF.addOrSubtract(result, coefficient);
}
return result;
}
result = coefficients[0];
for (int i = 1; i < size; i++)
{
result = GenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]);
}
return result;
}
internal GenericGFPoly addOrSubtract(GenericGFPoly other)
{
if (!field.Equals(other.field))
{
throw new ArgumentException("GenericGFPolys do not have same GenericGF field");
}
if (isZero)
{
return other;
}
if (other.isZero)
{
return this;
}
int[] smallerCoefficients = this.coefficients;
int[] largerCoefficients = other.coefficients;
if (smallerCoefficients.Length > largerCoefficients.Length)
{
int[] temp = smallerCoefficients;
smallerCoefficients = largerCoefficients;
largerCoefficients = temp;
}
int[] sumDiff = new int[largerCoefficients.Length];
int lengthDiff = largerCoefficients.Length - smallerCoefficients.Length;
// Copy high-order terms only found in higher-degree polynomial's coefficients
Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
for (int i = lengthDiff; i < largerCoefficients.Length; i++)
{
sumDiff[i] = GenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
}
return new GenericGFPoly(field, sumDiff);
}
internal GenericGFPoly multiply(GenericGFPoly other)
{
if (!field.Equals(other.field))
{
throw new ArgumentException("GenericGFPolys do not have same GenericGF field");
}
if (isZero || other.isZero)
{
return field.Zero;
}
int[] aCoefficients = this.coefficients;
int aLength = aCoefficients.Length;
int[] bCoefficients = other.coefficients;
int bLength = bCoefficients.Length;
int[] product = new int[aLength + bLength - 1];
for (int i = 0; i < aLength; i++)
{
int aCoeff = aCoefficients[i];
for (int j = 0; j < bLength; j++)
{
product[i + j] = GenericGF.addOrSubtract(product[i + j],
field.multiply(aCoeff, bCoefficients[j]));
}
}
return new GenericGFPoly(field, product);
}
internal GenericGFPoly multiply(int scalar)
{
if (scalar == 0)
{
return field.Zero;
}
if (scalar == 1)
{
return this;
}
int size = coefficients.Length;
int[] product = new int[size];
for (int i = 0; i < size; i++)
{
product[i] = field.multiply(coefficients[i], scalar);
}
return new GenericGFPoly(field, product);
}
internal GenericGFPoly multiplyByMonomial(int degree, int coefficient)
{
if (degree < 0)
{
throw new ArgumentException();
}
if (coefficient == 0)
{
return field.Zero;
}
int size = coefficients.Length;
int[] product = new int[size + degree];
for (int i = 0; i < size; i++)
{
product[i] = field.multiply(coefficients[i], coefficient);
}
return new GenericGFPoly(field, product);
}
internal GenericGFPoly[] divide(GenericGFPoly other)
{
if (!field.Equals(other.field))
{
throw new ArgumentException("GenericGFPolys do not have same GenericGF field");
}
if (other.isZero)
{
throw new ArgumentException("Divide by 0");
}
GenericGFPoly quotient = field.Zero;
GenericGFPoly remainder = this;
int denominatorLeadingTerm = other.getCoefficient(other.Degree);
int inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm);
while (remainder.Degree >= other.Degree && !remainder.isZero)
{
int degreeDifference = remainder.Degree - other.Degree;
int scale = field.multiply(remainder.getCoefficient(remainder.Degree), inverseDenominatorLeadingTerm);
GenericGFPoly term = other.multiplyByMonomial(degreeDifference, scale);
GenericGFPoly iterationQuotient = field.buildMonomial(degreeDifference, scale);
quotient = quotient.addOrSubtract(iterationQuotient);
remainder = remainder.addOrSubtract(term);
}
return new GenericGFPoly[] { quotient, remainder };
}
public override String ToString()
{
StringBuilder result = new StringBuilder(8 * Degree);
for (int degree = Degree; degree >= 0; degree--)
{
int coefficient = getCoefficient(degree);
if (coefficient != 0)
{
if (coefficient < 0)
{
result.Append(" - ");
coefficient = -coefficient;
}
else
{
if (result.Length > 0)
{
result.Append(" + ");
}
}
if (degree == 0 || coefficient != 1)
{
int alphaPower = field.log(coefficient);
if (alphaPower == 0)
{
result.Append('1');
}
else if (alphaPower == 1)
{
result.Append('a');
}
else
{
result.Append("a^");
result.Append(alphaPower);
}
}
if (degree != 0)
{
if (degree == 1)
{
result.Append('x');
}
else
{
result.Append("x^");
result.Append(degree);
}
}
}
}
return result.ToString();
}
}
}

+ 271
- 0
shadowsocks-csharp/3rd/zxing/MaskUtil.cs View File

@@ -0,0 +1,271 @@
/*
* Copyright 2008 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>
///
/// </summary>
/// <author>Satoru Takabayashi</author>
/// <author>Daniel Switkin</author>
/// <author>Sean Owen</author>
public static class MaskUtil
{
// Penalty weights from section 6.8.2.1
private const int N1 = 3;
private const int N2 = 3;
private const int N3 = 40;
private const int N4 = 10;
/// <summary>
/// Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and
/// give penalty to them. Example: 00000 or 11111.
/// </summary>
/// <param name="matrix">The matrix.</param>
/// <returns></returns>
public static int applyMaskPenaltyRule1(ByteMatrix matrix)
{
return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false);
}
/// <summary>
/// Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give
/// penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a
/// penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block.
/// </summary>
/// <param name="matrix">The matrix.</param>
/// <returns></returns>
public static int applyMaskPenaltyRule2(ByteMatrix matrix)
{
int penalty = 0;
var array = matrix.Array;
int width = matrix.Width;
int height = matrix.Height;
for (int y = 0; y < height - 1; y++)
{
for (int x = 0; x < width - 1; x++)
{
int value = array[y][x];
if (value == array[y][x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1])
{
penalty++;
}
}
}
return N2 * penalty;
}
/// <summary>
/// Apply mask penalty rule 3 and return the penalty. Find consecutive cells of 00001011101 or
/// 10111010000, and give penalty to them. If we find patterns like 000010111010000, we give
/// penalties twice (i.e. 40 * 2).
/// </summary>
/// <param name="matrix">The matrix.</param>
/// <returns></returns>
public static int applyMaskPenaltyRule3(ByteMatrix matrix)
{
int numPenalties = 0;
byte[][] array = matrix.Array;
int width = matrix.Width;
int height = matrix.Height;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
byte[] arrayY = array[y]; // We can at least optimize this access
if (x + 6 < width &&
arrayY[x] == 1 &&
arrayY[x + 1] == 0 &&
arrayY[x + 2] == 1 &&
arrayY[x + 3] == 1 &&
arrayY[x + 4] == 1 &&
arrayY[x + 5] == 0 &&
arrayY[x + 6] == 1 &&
(isWhiteHorizontal(arrayY, x - 4, x) || isWhiteHorizontal(arrayY, x + 7, x + 11)))
{
numPenalties++;
}
if (y + 6 < height &&
array[y][x] == 1 &&
array[y + 1][x] == 0 &&
array[y + 2][x] == 1 &&
array[y + 3][x] == 1 &&
array[y + 4][x] == 1 &&
array[y + 5][x] == 0 &&
array[y + 6][x] == 1 &&
(isWhiteVertical(array, x, y - 4, y) || isWhiteVertical(array, x, y + 7, y + 11)))
{
numPenalties++;
}
}
}
return numPenalties * N3;
}
private static bool isWhiteHorizontal(byte[] rowArray, int from, int to)
{
for (int i = from; i < to; i++)
{
if (i >= 0 && i < rowArray.Length && rowArray[i] == 1)
{
return false;
}
}
return true;
}
private static bool isWhiteVertical(byte[][] array, int col, int from, int to)
{
for (int i = from; i < to; i++)
{
if (i >= 0 && i < array.Length && array[i][col] == 1)
{
return false;
}
}
return true;
}
/// <summary>
/// Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give
/// penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance.
/// </summary>
/// <param name="matrix">The matrix.</param>
/// <returns></returns>
public static int applyMaskPenaltyRule4(ByteMatrix matrix)
{
int numDarkCells = 0;
var array = matrix.Array;
int width = matrix.Width;
int height = matrix.Height;
for (int y = 0; y < height; y++)
{
var arrayY = array[y];
for (int x = 0; x < width; x++)
{
if (arrayY[x] == 1)
{
numDarkCells++;
}
}
}
var numTotalCells = matrix.Height * matrix.Width;
var darkRatio = (double)numDarkCells / numTotalCells;
var fivePercentVariances = (int)(Math.Abs(darkRatio - 0.5) * 20.0); // * 100.0 / 5.0
return fivePercentVariances * N4;
}
/// <summary>
/// Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask
/// pattern conditions.
/// </summary>
/// <param name="maskPattern">The mask pattern.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns></returns>
public static bool getDataMaskBit(int maskPattern, int x, int y)
{
int intermediate, temp;
switch (maskPattern)
{
case 0:
intermediate = (y + x) & 0x1;
break;
case 1:
intermediate = y & 0x1;
break;
case 2:
intermediate = x % 3;
break;
case 3:
intermediate = (y + x) % 3;
break;
case 4:
intermediate = (((int)((uint)y >> 1)) + (x / 3)) & 0x1;
break;
case 5:
temp = y * x;
intermediate = (temp & 0x1) + (temp % 3);
break;
case 6:
temp = y * x;
intermediate = (((temp & 0x1) + (temp % 3)) & 0x1);
break;
case 7:
temp = y * x;
intermediate = (((temp % 3) + ((y + x) & 0x1)) & 0x1);
break;
default:
throw new ArgumentException("Invalid mask pattern: " + maskPattern);
}
return intermediate == 0;
}
/// <summary>
/// Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both
/// vertical and horizontal orders respectively.
/// </summary>
/// <param name="matrix">The matrix.</param>
/// <param name="isHorizontal">if set to <c>true</c> [is horizontal].</param>
/// <returns></returns>
private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, bool isHorizontal)
{
int penalty = 0;
int iLimit = isHorizontal ? matrix.Height : matrix.Width;
int jLimit = isHorizontal ? matrix.Width : matrix.Height;
var array = matrix.Array;
for (int i = 0; i < iLimit; i++)
{
int numSameBitCells = 0;
int prevBit = -1;
for (int j = 0; j < jLimit; j++)
{
int bit = isHorizontal ? array[i][j] : array[j][i];
if (bit == prevBit)
{
numSameBitCells++;
}
else
{
if (numSameBitCells >= 5)
{
penalty += N1 + (numSameBitCells - 5);
}
numSameBitCells = 1; // Include the cell itself.
prevBit = bit;
}
}
if (numSameBitCells >= 5)
{
penalty += N1 + (numSameBitCells - 5);
}
}
return penalty;
}
}
}

+ 604
- 0
shadowsocks-csharp/3rd/zxing/MatrixUtil.cs View File

@@ -0,0 +1,604 @@
/*
* Copyright 2008 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>
///
/// </summary>
/// <author>
/// satorux@google.com (Satoru Takabayashi) - creator
/// </author>
public static class MatrixUtil
{
private static readonly int[][] POSITION_DETECTION_PATTERN = new int[][]
{
new int[] { 1, 1, 1, 1, 1, 1, 1 },
new int[] { 1, 0, 0, 0, 0, 0, 1 },
new int[] { 1, 0, 1, 1, 1, 0, 1 },
new int[] { 1, 0, 1, 1, 1, 0, 1 },
new int[] { 1, 0, 1, 1, 1, 0, 1 },
new int[] { 1, 0, 0, 0, 0, 0, 1 },
new int[] { 1, 1, 1, 1, 1, 1, 1 }
};
private static readonly int[][] POSITION_ADJUSTMENT_PATTERN = new int[][]
{
new int[] { 1, 1, 1, 1, 1 },
new int[] { 1, 0, 0, 0, 1 },
new int[] { 1, 0, 1, 0, 1 },
new int[] { 1, 0, 0, 0, 1 },
new int[] { 1, 1, 1, 1, 1 }
};
// From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu.
private static readonly int[][] POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE = new int[][]
{
new int[] { -1, -1, -1, -1, -1, -1, -1 },
new int[] { 6, 18, -1, -1, -1, -1, -1 },
new int[] { 6, 22, -1, -1, -1, -1, -1 },
new int[] { 6, 26, -1, -1, -1, -1, -1 },
new int[] { 6, 30, -1, -1, -1, -1, -1 },
new int[] { 6, 34, -1, -1, -1, -1, -1 },
new int[] { 6, 22, 38, -1, -1, -1, -1 },
new int[] { 6, 24, 42, -1, -1, -1, -1 },
new int[] { 6, 26, 46, -1, -1, -1, -1 },
new int[] { 6, 28, 50, -1, -1, -1, -1 },
new int[] { 6, 30, 54, -1, -1, -1, -1 },
new int[] { 6, 32, 58, -1, -1, -1, -1 },
new int[] { 6, 34, 62, -1, -1, -1, -1 },
new int[] { 6, 26, 46, 66, -1, -1, -1 },
new int[] { 6, 26, 48, 70, -1, -1, -1 },
new int[] { 6, 26, 50, 74, -1, -1, -1 },
new int[] { 6, 30, 54, 78, -1, -1, -1 },
new int[] { 6, 30, 56, 82, -1, -1, -1 },
new int[] { 6, 30, 58, 86, -1, -1, -1 },
new int[] { 6, 34, 62, 90, -1, -1, -1 },
new int[] { 6, 28, 50, 72, 94, -1, -1 },
new int[] { 6, 26, 50, 74, 98, -1, -1 },
new int[] { 6, 30, 54, 78, 102, -1, -1 },
new int[] { 6, 28, 54, 80, 106, -1, -1 },
new int[] { 6, 32, 58, 84, 110, -1, -1 },
new int[] { 6, 30, 58, 86, 114, -1, -1 },
new int[] { 6, 34, 62, 90, 118, -1, -1 },
new int[] { 6, 26, 50, 74, 98, 122, -1 },
new int[] { 6, 30, 54, 78, 102, 126, -1 },
new int[] { 6, 26, 52, 78, 104, 130, -1 },
new int[] { 6, 30, 56, 82, 108, 134, -1 },
new int[] { 6, 34, 60, 86, 112, 138, -1 },
new int[] { 6, 30, 58, 86, 114, 142, -1 },
new int[] { 6, 34, 62, 90, 118, 146, -1 },
new int[] { 6, 30, 54, 78, 102, 126, 150 },
new int[] { 6, 24, 50, 76, 102, 128, 154 },
new int[] { 6, 28, 54, 80, 106, 132, 158 },
new int[] { 6, 32, 58, 84, 110, 136, 162 },
new int[] { 6, 26, 54, 82, 110, 138, 166 },
new int[] { 6, 30, 58, 86, 114, 142, 170 }
};
// Type info cells at the left top corner.
private static readonly int[][] TYPE_INFO_COORDINATES = new int[][]
{
new int[] { 8, 0 },
new int[] { 8, 1 },
new int[] { 8, 2 },
new int[] { 8, 3 },
new int[] { 8, 4 },
new int[] { 8, 5 },
new int[] { 8, 7 },
new int[] { 8, 8 },
new int[] { 7, 8 },
new int[] { 5, 8 },
new int[] { 4, 8 },
new int[] { 3, 8 },
new int[] { 2, 8 },
new int[] { 1, 8 },
new int[] { 0, 8 }
};
// From Appendix D in JISX0510:2004 (p. 67)
private const int VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101
// From Appendix C in JISX0510:2004 (p.65).
private const int TYPE_INFO_POLY = 0x537;
private const int TYPE_INFO_MASK_PATTERN = 0x5412;
/// <summary>
/// Set all cells to 2. 2 means that the cell is empty (not set yet).
///
/// JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding
/// with the ByteMatrix initialized all to zero.
/// </summary>
/// <param name="matrix">The matrix.</param>
public static void clearMatrix(ByteMatrix matrix)
{
matrix.clear(2);
}
/// <summary>
/// Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On
/// success, store the result in "matrix" and return true.
/// </summary>
/// <param name="dataBits">The data bits.</param>
/// <param name="ecLevel">The ec level.</param>
/// <param name="version">The version.</param>
/// <param name="maskPattern">The mask pattern.</param>
/// <param name="matrix">The matrix.</param>
public static void buildMatrix(BitArray dataBits, ErrorCorrectionLevel ecLevel, Version version, int maskPattern, ByteMatrix matrix)
{
clearMatrix(matrix);
embedBasicPatterns(version, matrix);
// Type information appear with any version.
embedTypeInfo(ecLevel, maskPattern, matrix);
// Version info appear if version >= 7.
maybeEmbedVersionInfo(version, matrix);
// Data should be embedded at end.
embedDataBits(dataBits, maskPattern, matrix);
}
/// <summary>
/// Embed basic patterns. On success, modify the matrix and return true.
/// The basic patterns are:
/// - Position detection patterns
/// - Timing patterns
/// - Dark dot at the left bottom corner
/// - Position adjustment patterns, if need be
/// </summary>
/// <param name="version">The version.</param>
/// <param name="matrix">The matrix.</param>
public static void embedBasicPatterns(Version version, ByteMatrix matrix)
{
// Let's get started with embedding big squares at corners.
embedPositionDetectionPatternsAndSeparators(matrix);
// Then, embed the dark dot at the left bottom corner.
embedDarkDotAtLeftBottomCorner(matrix);
// Position adjustment patterns appear if version >= 2.
maybeEmbedPositionAdjustmentPatterns(version, matrix);
// Timing patterns should be embedded after position adj. patterns.
embedTimingPatterns(matrix);
}
/// <summary>
/// Embed type information. On success, modify the matrix.
/// </summary>
/// <param name="ecLevel">The ec level.</param>
/// <param name="maskPattern">The mask pattern.</param>
/// <param name="matrix">The matrix.</param>
public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix)
{
BitArray typeInfoBits = new BitArray();
makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits);
for (int i = 0; i < typeInfoBits.Size; ++i)
{
// Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
// "typeInfoBits".
int bit = typeInfoBits[typeInfoBits.Size - 1 - i] ? 1 : 0;
// Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
int x1 = TYPE_INFO_COORDINATES[i][0];
int y1 = TYPE_INFO_COORDINATES[i][1];
matrix[x1, y1] = bit;
if (i < 8)
{
// Right top corner.
int x2 = matrix.Width - i - 1;
int y2 = 8;
matrix[x2, y2] = bit;
}
else
{
// Left bottom corner.
int x2 = 8;
int y2 = matrix.Height - 7 + (i - 8);
matrix[x2, y2] = bit;
}
}
}
/// <summary>
/// Embed version information if need be. On success, modify the matrix and return true.
/// See 8.10 of JISX0510:2004 (p.47) for how to embed version information.
/// </summary>
/// <param name="version">The version.</param>
/// <param name="matrix">The matrix.</param>
public static void maybeEmbedVersionInfo(Version version, ByteMatrix matrix)
{
if (version.VersionNumber < 7)
{
// Version info is necessary if version >= 7.
return; // Don't need version info.
}
BitArray versionInfoBits = new BitArray();
makeVersionInfoBits(version, versionInfoBits);
int bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0.
for (int i = 0; i < 6; ++i)
{
for (int j = 0; j < 3; ++j)
{
// Place bits in LSB (least significant bit) to MSB order.
var bit = versionInfoBits[bitIndex] ? 1 : 0;
bitIndex--;
// Left bottom corner.
matrix[i, matrix.Height - 11 + j] = bit;
// Right bottom corner.
matrix[matrix.Height - 11 + j, i] = bit;
}
}
}
/// <summary>
/// Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true.
/// For debugging purposes, it skips masking process if "getMaskPattern" is -1.
/// See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.
/// </summary>
/// <param name="dataBits">The data bits.</param>
/// <param name="maskPattern">The mask pattern.</param>
/// <param name="matrix">The matrix.</param>
public static void embedDataBits(BitArray dataBits, int maskPattern, ByteMatrix matrix)
{
int bitIndex = 0;
int direction = -1;
// Start from the right bottom cell.
int x = matrix.Width - 1;
int y = matrix.Height - 1;
while (x > 0)
{
// Skip the vertical timing pattern.
if (x == 6)
{
x -= 1;
}
while (y >= 0 && y < matrix.Height)
{
for (int i = 0; i < 2; ++i)
{
int xx = x - i;
// Skip the cell if it's not empty.
if (!isEmpty(matrix[xx, y]))
{
continue;
}
int bit;
if (bitIndex < dataBits.Size)
{
bit = dataBits[bitIndex] ? 1 : 0;
++bitIndex;
}
else
{
// Padding bit. If there is no bit left, we'll fill the left cells with 0, as described
// in 8.4.9 of JISX0510:2004 (p. 24).
bit = 0;
}
// Skip masking if mask_pattern is -1.
if (maskPattern != -1)
{
if (MaskUtil.getDataMaskBit(maskPattern, xx, y))
{
bit ^= 0x1;
}
}
matrix[xx, y] = bit;
}
y += direction;
}
direction = -direction; // Reverse the direction.
y += direction;
x -= 2; // Move to the left.
}
// All bits should be consumed.
if (bitIndex != dataBits.Size)
{
throw new Exception("Not all bits consumed: " + bitIndex + '/' + dataBits.Size);
}
}
/// <summary>
/// Return the position of the most significant bit set (to one) in the "value". The most
/// significant bit is position 32. If there is no bit set, return 0. Examples:
/// - findMSBSet(0) => 0
/// - findMSBSet(1) => 1
/// - findMSBSet(255) => 8
/// </summary>
/// <param name="value_Renamed">The value_ renamed.</param>
/// <returns></returns>
public static int findMSBSet(int value_Renamed)
{
int numDigits = 0;
while (value_Renamed != 0)
{
value_Renamed = (int)((uint)value_Renamed >> 1);
++numDigits;
}
return numDigits;
}
/// <summary>
/// Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH
/// code is used for encoding type information and version information.
/// Example: Calculation of version information of 7.
/// f(x) is created from 7.
/// - 7 = 000111 in 6 bits
/// - f(x) = x^2 + x^2 + x^1
/// g(x) is given by the standard (p. 67)
/// - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1
/// Multiply f(x) by x^(18 - 6)
/// - f'(x) = f(x) * x^(18 - 6)
/// - f'(x) = x^14 + x^13 + x^12
/// Calculate the remainder of f'(x) / g(x)
/// x^2
/// __________________________________________________
/// g(x) )x^14 + x^13 + x^12
/// x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2
/// --------------------------------------------------
/// x^11 + x^10 + x^7 + x^4 + x^2
///
/// The remainder is x^11 + x^10 + x^7 + x^4 + x^2
/// Encode it in binary: 110010010100
/// The return value is 0xc94 (1100 1001 0100)
///
/// Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit
/// operations. We don't care if cofficients are positive or negative.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="poly">The poly.</param>
/// <returns></returns>
public static int calculateBCHCode(int value, int poly)
{
if (poly == 0)
throw new ArgumentException("0 polynominal", "poly");
// If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1
// from 13 to make it 12.
int msbSetInPoly = findMSBSet(poly);
value <<= msbSetInPoly - 1;
// Do the division business using exclusive-or operations.
while (findMSBSet(value) >= msbSetInPoly)
{
value ^= poly << (findMSBSet(value) - msbSetInPoly);
}
// Now the "value" is the remainder (i.e. the BCH code)
return value;
}
/// <summary>
/// Make bit vector of type information. On success, store the result in "bits" and return true.
/// Encode error correction level and mask pattern. See 8.9 of
/// JISX0510:2004 (p.45) for details.
/// </summary>
/// <param name="ecLevel">The ec level.</param>
/// <param name="maskPattern">The mask pattern.</param>
/// <param name="bits">The bits.</param>
public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitArray bits)
{
if (!QRCode.isValidMaskPattern(maskPattern))
{
throw new Exception("Invalid mask pattern");
}
int typeInfo = (ecLevel.Bits << 3) | maskPattern;
bits.appendBits(typeInfo, 5);
int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY);
bits.appendBits(bchCode, 10);
BitArray maskBits = new BitArray();
maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15);
bits.xor(maskBits);
if (bits.Size != 15)
{
// Just in case.
throw new Exception("should not happen but we got: " + bits.Size);
}
}
/// <summary>
/// Make bit vector of version information. On success, store the result in "bits" and return true.
/// See 8.10 of JISX0510:2004 (p.45) for details.
/// </summary>
/// <param name="version">The version.</param>
/// <param name="bits">The bits.</param>
public static void makeVersionInfoBits(Version version, BitArray bits)
{
bits.appendBits(version.VersionNumber, 6);
int bchCode = calculateBCHCode(version.VersionNumber, VERSION_INFO_POLY);
bits.appendBits(bchCode, 12);
if (bits.Size != 18)
{
// Just in case.
throw new Exception("should not happen but we got: " + bits.Size);
}
}
/// <summary>
/// Check if "value" is empty.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>
/// <c>true</c> if the specified value is empty; otherwise, <c>false</c>.
/// </returns>
private static bool isEmpty(int value)
{
return value == 2;
}
private static void embedTimingPatterns(ByteMatrix matrix)
{
// -8 is for skipping position detection patterns (size 7), and two horizontal/vertical
// separation patterns (size 1). Thus, 8 = 7 + 1.
for (int i = 8; i < matrix.Width - 8; ++i)
{
int bit = (i + 1) % 2;
// Horizontal line.
if (isEmpty(matrix[i, 6]))
{
matrix[i, 6] = bit;
}
// Vertical line.
if (isEmpty(matrix[6, i]))
{
matrix[6, i] = bit;
}
}
}
/// <summary>
/// Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46)
/// </summary>
/// <param name="matrix">The matrix.</param>
private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix)
{
if (matrix[8, matrix.Height - 8] == 0)
{
throw new Exception();
}
matrix[8, matrix.Height - 8] = 1;
}
private static void embedHorizontalSeparationPattern(int xStart, int yStart, ByteMatrix matrix)
{
for (int x = 0; x < 8; ++x)
{
if (!isEmpty(matrix[xStart + x, yStart]))
{
throw new Exception();
}
matrix[xStart + x, yStart] = 0;
}
}
private static void embedVerticalSeparationPattern(int xStart, int yStart, ByteMatrix matrix)
{
for (int y = 0; y < 7; ++y)
{
if (!isEmpty(matrix[xStart, yStart + y]))
{
throw new Exception();
}
matrix[xStart, yStart + y] = 0;
}
}
/// <summary>
/// Note that we cannot unify the function with embedPositionDetectionPattern() despite they are
/// almost identical, since we cannot write a function that takes 2D arrays in different sizes in
/// C/C++. We should live with the fact.
/// </summary>
/// <param name="xStart">The x start.</param>
/// <param name="yStart">The y start.</param>
/// <param name="matrix">The matrix.</param>
private static void embedPositionAdjustmentPattern(int xStart, int yStart, ByteMatrix matrix)
{
for (int y = 0; y < 5; ++y)
{
for (int x = 0; x < 5; ++x)
{
matrix[xStart + x, yStart + y] = POSITION_ADJUSTMENT_PATTERN[y][x];
}
}
}
private static void embedPositionDetectionPattern(int xStart, int yStart, ByteMatrix matrix)
{
for (int y = 0; y < 7; ++y)
{
for (int x = 0; x < 7; ++x)
{
matrix[xStart + x, yStart + y] = POSITION_DETECTION_PATTERN[y][x];
}
}
}
/// <summary>
/// Embed position detection patterns and surrounding vertical/horizontal separators.
/// </summary>
/// <param name="matrix">The matrix.</param>
private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix)
{
// Embed three big squares at corners.
int pdpWidth = POSITION_DETECTION_PATTERN[0].Length;
// Left top corner.
embedPositionDetectionPattern(0, 0, matrix);
// Right top corner.
embedPositionDetectionPattern(matrix.Width - pdpWidth, 0, matrix);
// Left bottom corner.
embedPositionDetectionPattern(0, matrix.Width - pdpWidth, matrix);
// Embed horizontal separation patterns around the squares.
const int hspWidth = 8;
// Left top corner.
embedHorizontalSeparationPattern(0, hspWidth - 1, matrix);
// Right top corner.
embedHorizontalSeparationPattern(matrix.Width - hspWidth, hspWidth - 1, matrix);
// Left bottom corner.
embedHorizontalSeparationPattern(0, matrix.Width - hspWidth, matrix);
// Embed vertical separation patterns around the squares.
const int vspSize = 7;
// Left top corner.
embedVerticalSeparationPattern(vspSize, 0, matrix);
// Right top corner.
embedVerticalSeparationPattern(matrix.Height - vspSize - 1, 0, matrix);
// Left bottom corner.
embedVerticalSeparationPattern(vspSize, matrix.Height - vspSize, matrix);
}
/// <summary>
/// Embed position adjustment patterns if need be.
/// </summary>
/// <param name="version">The version.</param>
/// <param name="matrix">The matrix.</param>
private static void maybeEmbedPositionAdjustmentPatterns(Version version, ByteMatrix matrix)
{
if (version.VersionNumber < 2)
{
// The patterns appear if version >= 2
return;
}
int index = version.VersionNumber - 1;
int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index];
int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].Length;
for (int i = 0; i < numCoordinates; ++i)
{
for (int j = 0; j < numCoordinates; ++j)
{
int y = coordinates[i];
int x = coordinates[j];
if (x == -1 || y == -1)
{
continue;
}
// If the cell is unset, we embed the position adjustment pattern here.
if (isEmpty(matrix[x, y]))
{
// -2 is necessary since the x/y coordinates point to the center of the pattern, not the
// left top corner.
embedPositionAdjustmentPattern(x - 2, y - 2, matrix);
}
}
}
}
}
}

+ 179
- 0
shadowsocks-csharp/3rd/zxing/Mode.cs 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;
}
}
}

+ 125
- 0
shadowsocks-csharp/3rd/zxing/QRCode.cs View File

@@ -0,0 +1,125 @@
/*
* Copyright 2008 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.Text;
namespace ZXing.QrCode.Internal
{
/// <author>satorux@google.com (Satoru Takabayashi) - creator</author>
/// <author>dswitkin@google.com (Daniel Switkin) - ported from C++</author>
public class QRCode
{
/// <summary>
///
/// </summary>
public static int NUM_MASK_PATTERNS = 8;
/// <summary>
/// Initializes a new instance of the <see cref="QRCode"/> class.
/// </summary>
public QRCode()
{
MaskPattern = -1;
}
/// <summary>
/// Gets or sets the mode.
/// </summary>
/// <value>
/// The mode.
/// </value>
public Mode Mode { get; set; }
/// <summary>
/// Gets or sets the EC level.
/// </summary>
/// <value>
/// The EC level.
/// </value>
public ErrorCorrectionLevel ECLevel { get; set; }
/// <summary>
/// Gets or sets the version.
/// </summary>
/// <value>
/// The version.
/// </value>
public Version Version { get; set; }
/// <summary>
/// Gets or sets the mask pattern.
/// </summary>
/// <value>
/// The mask pattern.
/// </value>
public int MaskPattern { get; set; }
/// <summary>
/// Gets or sets the matrix.
/// </summary>
/// <value>
/// The matrix.
/// </value>
public ByteMatrix Matrix { get; set; }
/// <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()
{
var result = new StringBuilder(200);
result.Append("<<\n");
result.Append(" mode: ");
result.Append(Mode);
result.Append("\n ecLevel: ");
result.Append(ECLevel);
result.Append("\n version: ");
if (Version == null)
result.Append("null");
else
result.Append(Version);
result.Append("\n maskPattern: ");
result.Append(MaskPattern);
if (Matrix == null)
{
result.Append("\n matrix: null\n");
}
else
{
result.Append("\n matrix:\n");
result.Append(Matrix.ToString());
}
result.Append(">>\n");
return result.ToString();
}
/// <summary>
/// Check if "mask_pattern" is valid.
/// </summary>
/// <param name="maskPattern">The mask pattern.</param>
/// <returns>
/// <c>true</c> if [is valid mask pattern] [the specified mask pattern]; otherwise, <c>false</c>.
/// </returns>
public static bool isValidMaskPattern(int maskPattern)
{
return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS;
}
}
}

+ 84
- 0
shadowsocks-csharp/3rd/zxing/ReedSolomonEncoder.cs View File

@@ -0,0 +1,84 @@
/*
* Copyright 2008 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;
namespace ZXing.Common.ReedSolomon
{
/// <summary>
/// Implements Reed-Solomon encoding, as the name implies.
/// </summary>
/// <author>Sean Owen</author>
/// <author>William Rucklidge</author>
public sealed class ReedSolomonEncoder
{
private readonly GenericGF field;
private readonly IList<GenericGFPoly> cachedGenerators;
public ReedSolomonEncoder(GenericGF field)
{
this.field = field;
this.cachedGenerators = new List<GenericGFPoly>();
cachedGenerators.Add(new GenericGFPoly(field, new int[] { 1 }));
}
private GenericGFPoly buildGenerator(int degree)
{
if (degree >= cachedGenerators.Count)
{
var lastGenerator = cachedGenerators[cachedGenerators.Count - 1];
for (int d = cachedGenerators.Count; d <= degree; d++)
{
var nextGenerator = lastGenerator.multiply(new GenericGFPoly(field, new int[] { 1, field.exp(d - 1 + field.GeneratorBase) }));
cachedGenerators.Add(nextGenerator);
lastGenerator = nextGenerator;
}
}
return cachedGenerators[degree];
}
public void encode(int[] toEncode, int ecBytes)
{
if (ecBytes == 0)
{
throw new ArgumentException("No error correction bytes");
}
var dataBytes = toEncode.Length - ecBytes;
if (dataBytes <= 0)
{
throw new ArgumentException("No data bytes provided");
}
var generator = buildGenerator(ecBytes);
var infoCoefficients = new int[dataBytes];
Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes);
var info = new GenericGFPoly(field, infoCoefficients);
info = info.multiplyByMonomial(ecBytes, 1);
var remainder = info.divide(generator)[1];
var coefficients = remainder.Coefficients;
var numZeroCoefficients = ecBytes - coefficients.Length;
for (var i = 0; i < numZeroCoefficients; i++)
{
toEncode[dataBytes + i] = 0;
}
Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.Length);
}
}
}

+ 685
- 0
shadowsocks-csharp/3rd/zxing/Version.cs 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)))
};
}
}
}

+ 8
- 36
shadowsocks-csharp/View/QRCodeForm.cs View File

@@ -1,4 +1,4 @@
using QRCode4CS;
using ZXing.QrCode.Internal;
using Shadowsocks.Controller;
using Shadowsocks.Properties;
using System;
@@ -28,48 +28,20 @@ namespace Shadowsocks.View
private void GenQR(string ssconfig)
{
string qrText = ssconfig;
QRCode4CS.Options options = new QRCode4CS.Options();
options.Text = qrText;
QRCode4CS.QRCode qrCoded = null;
bool success = false;
foreach (var level in new QRErrorCorrectLevel[]{QRErrorCorrectLevel.H, QRErrorCorrectLevel.Q, QRErrorCorrectLevel.M, QRErrorCorrectLevel.L})
{
for (int i = 3; i < 10; i++)
{
try
{
options.TypeNumber = i;
options.CorrectLevel = level;
qrCoded = new QRCode4CS.QRCode(options);
qrCoded.Make();
success = true;
break;
}
catch
{
qrCoded = null;
continue;
}
}
if (success)
break;
}
if (qrCoded == null)
{
return;
}
int blockSize = Math.Max(200 / qrCoded.GetModuleCount(), 1);
Bitmap drawArea = new Bitmap((qrCoded.GetModuleCount() * blockSize), (qrCoded.GetModuleCount() * blockSize));
QRCode code = ZXing.QrCode.Internal.Encoder.encode(qrText, ErrorCorrectionLevel.M);
ByteMatrix m = code.Matrix;
int blockSize = Math.Max(200 / m.Height, 1);
Bitmap drawArea = new Bitmap((m.Height * blockSize), (m.Height * blockSize));
using (Graphics g = Graphics.FromImage(drawArea))
{
g.Clear(Color.White);
using (Brush b = new SolidBrush(Color.Black))
{
for (int row = 0; row < qrCoded.GetModuleCount(); row++)
for (int row = 0; row < m.Height; row++)
{
for (int col = 0; col < qrCoded.GetModuleCount(); col++)
for (int col = 0; col < m.Height; col++)
{
if (qrCoded.IsDark(row, col))
if (m[row, col] != 0)
{
g.FillRectangle(b, blockSize * row, blockSize * col, blockSize, blockSize);
}


+ 16
- 1
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -69,8 +69,23 @@
<Reference Include="System.XML" />
</ItemGroup>
<ItemGroup>
<Compile Include="3rd\QRCodeCS.cs" />
<Compile Include="3rd\SimpleJson.cs" />
<Compile Include="3rd\zxing\BitArray.cs" />
<Compile Include="3rd\zxing\BitMatrix.cs" />
<Compile Include="3rd\zxing\BlockPair.cs" />
<Compile Include="3rd\zxing\ByteMatrix.cs" />
<Compile Include="3rd\zxing\EncodeHintType.cs" />
<Compile Include="3rd\zxing\Encoder.cs" />
<Compile Include="3rd\zxing\ErrorCorrectionLevel.cs" />
<Compile Include="3rd\zxing\FormatInformation.cs" />
<Compile Include="3rd\zxing\GenericGF.cs" />
<Compile Include="3rd\zxing\GenericGFPoly.cs" />
<Compile Include="3rd\zxing\MaskUtil.cs" />
<Compile Include="3rd\zxing\MatrixUtil.cs" />
<Compile Include="3rd\zxing\Mode.cs" />
<Compile Include="3rd\zxing\QRCode.cs" />
<Compile Include="3rd\zxing\ReedSolomonEncoder.cs" />
<Compile Include="3rd\zxing\Version.cs" />
<Compile Include="Controller\AutoStartup.cs" />
<Compile Include="Controller\FileManager.cs" />
<Compile Include="Controller\I18N.cs" />


Loading…
Cancel
Save