diff --git a/shadowsocks-csharp/3rd/QRCodeCS.cs b/shadowsocks-csharp/3rd/QRCodeCS.cs deleted file mode 100644 index a380c978..00000000 --- a/shadowsocks-csharp/3rd/QRCodeCS.cs +++ /dev/null @@ -1,1209 +0,0 @@ -//--------------------------------------------------------------------- -// QRCode for C#4.0 Silverlight is translation of QRCode for JavaScript -// https://github.com/jeromeetienne/jquery-qrcode/ -// -// Copyright (c) 2009 Kazuhiko Arase -// -// URL: http://www.d-project.com/ -// -// Licensed under the MIT license: -// http://www.opensource.org/licenses/mit-license.php -// -// The word "QR Code" is registered trademark of -// DENSO WAVE INCORPORATED -// http://www.denso-wave.com/qrcode/faqpatent-e.html -// -//--------------------------------------------------------------------- -namespace QRCode4CS -{ - using System; - using System.Collections.Generic; - - - public class Error : Exception - { - public Error() { } - public Error(string message) : base(message) { } - public Error(string message, Exception inner) : base(message, inner) { } - } - - public enum QRMode : int - { - MODE_NUMBER = 1 << 0, - MODE_ALPHA_NUM = 1 << 1, - MODE_8BIT_BYTE = 1 << 2, - MODE_KANJI = 1 << 3 - } - - public enum QRErrorCorrectLevel : int - { - L = 1, - M = 0, - Q = 3, - H = 2 - } - - public enum QRMaskPattern : int - { - PATTERN000 = 0, - PATTERN001 = 1, - PATTERN010 = 2, - PATTERN011 = 3, - PATTERN100 = 4, - PATTERN101 = 5, - PATTERN110 = 6, - PATTERN111 = 7 - } - - public struct Options - { - public int Width { get; set; } - public int Height { get; set; } - public QRErrorCorrectLevel CorrectLevel { get; set; } - public int TypeNumber { get; set; } - public string Text { get; set; } - - public Options(string text) - : this() - { - Width = 256; - Height = 256; - TypeNumber = 4; - CorrectLevel = QRErrorCorrectLevel.H; - Text = text; - } - } - - internal static class QRUtil - { - internal const int G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); - internal const int G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); - internal const int G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1); - internal static readonly int[][] PATTERN_POSITION_TABLE = new int[][] { - new int[] {}, - new int [] {6, 18}, - new int [] {6, 22}, - new int [] {6, 26}, - new int [] {6, 30}, - new int [] {6, 34}, - new int [] {6, 22, 38}, - new int [] {6, 24, 42}, - new int [] {6, 26, 46}, - new int [] {6, 28, 50}, - new int [] {6, 30, 54}, - new int [] {6, 32, 58}, - new int [] {6, 34, 62}, - new int [] {6, 26, 46, 66}, - new int [] {6, 26, 48, 70}, - new int [] {6, 26, 50, 74}, - new int [] {6, 30, 54, 78}, - new int [] {6, 30, 56, 82}, - new int [] {6, 30, 58, 86}, - new int [] {6, 34, 62, 90}, - new int [] {6, 28, 50, 72, 94}, - new int [] {6, 26, 50, 74, 98}, - new int [] {6, 30, 54, 78, 102}, - new int [] {6, 28, 54, 80, 106}, - new int [] {6, 32, 58, 84, 110}, - new int [] {6, 30, 58, 86, 114}, - new int [] {6, 34, 62, 90, 118}, - new int [] {6, 26, 50, 74, 98, 122}, - new int [] {6, 30, 54, 78, 102, 126}, - new int [] {6, 26, 52, 78, 104, 130}, - new int [] {6, 30, 56, 82, 108, 134}, - new int [] {6, 34, 60, 86, 112, 138}, - - new int [] {6, 30, 58, 86, 114, 142}, - new int [] {6, 34, 62, 90, 118, 146}, - 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} - }; - internal static int GetLengthInBits(QRMode mode, int type) - { - - if (1 <= type && type < 10) - { - - // 1 - 9 - - switch (mode) - { - case QRMode.MODE_NUMBER: return 10; - case QRMode.MODE_ALPHA_NUM: return 9; - case QRMode.MODE_8BIT_BYTE: return 8; - case QRMode.MODE_KANJI: return 8; - default: - throw new Error("mode:" + mode); - } - - } - else if (type < 27) - { - - // 10 - 26 - - switch (mode) - { - case QRMode.MODE_NUMBER: return 12; - case QRMode.MODE_ALPHA_NUM: return 11; - case QRMode.MODE_8BIT_BYTE: return 16; - case QRMode.MODE_KANJI: return 10; - default: - throw new Error("mode:" + mode); - } - - } - else if (type < 41) - { - - // 27 - 40 - - switch (mode) - { - case QRMode.MODE_NUMBER: return 14; - case QRMode.MODE_ALPHA_NUM: return 13; - case QRMode.MODE_8BIT_BYTE: return 16; - case QRMode.MODE_KANJI: return 12; - default: - throw new Error("mode:" + mode); - } - - } - else - { - throw new Error("type:" + type); - } - } - - internal static double GetLostPoint(QRCode qrCode) - { - int moduleCount = qrCode.GetModuleCount(); - double lostPoint = 0; - for (int row = 0; row < moduleCount; row++) - { - - for (int col = 0; col < moduleCount; col++) - { - - var sameCount = 0; - var dark = qrCode.IsDark(row, col); - - for (var r = -1; r <= 1; r++) - { - - if (row + r < 0 || moduleCount <= row + r) - { - continue; - } - - for (var c = -1; c <= 1; c++) - { - - if (col + c < 0 || moduleCount <= col + c) - { - continue; - } - - if (r == 0 && c == 0) - { - continue; - } - - if (dark == qrCode.IsDark((int)((int)row + r), (int)((int)col + c))) - { - sameCount++; - } - } - } - - if (sameCount > 5) - { - lostPoint += (int)(3 + sameCount - 5); - } - } - } - - // LEVEL2 - - for (int row = 0; row < moduleCount - 1; row++) - { - for (int col = 0; col < moduleCount - 1; col++) - { - var count = 0; - if (qrCode.IsDark(row, col)) count++; - if (qrCode.IsDark(row + 1, col)) count++; - if (qrCode.IsDark(row, col + 1)) count++; - if (qrCode.IsDark(row + 1, col + 1)) count++; - if (count == 0 || count == 4) - { - lostPoint += 3; - } - } - } - - // LEVEL3 - - for (int row = 0; row < moduleCount; row++) - { - for (int col = 0; col < moduleCount - 6; col++) - { - if (qrCode.IsDark(row, col) - && !qrCode.IsDark(row, col + 1) - && qrCode.IsDark(row, col + 2) - && qrCode.IsDark(row, col + 3) - && qrCode.IsDark(row, col + 4) - && !qrCode.IsDark(row, col + 5) - && qrCode.IsDark(row, col + 6)) - { - lostPoint += 40; - } - } - } - - for (int col = 0; col < moduleCount; col++) - { - for (int row = 0; row < moduleCount - 6; row++) - { - if (qrCode.IsDark(row, col) - && !qrCode.IsDark(row + 1, col) - && qrCode.IsDark(row + 2, col) - && qrCode.IsDark(row + 3, col) - && qrCode.IsDark(row + 4, col) - && !qrCode.IsDark(row + 5, col) - && qrCode.IsDark(row + 6, col)) - { - lostPoint += 40; - } - } - } - - // LEVEL4 - - int darkCount = 0; - - for (int col = 0; col < moduleCount; col++) - { - for (int row = 0; row < moduleCount; row++) - { - if (qrCode.IsDark(row, col)) - { - darkCount++; - } - } - } - - double ratio = Math.Abs(100.0 * darkCount / moduleCount / moduleCount - 50) / 5; - lostPoint += ratio * 10; - - return lostPoint; - - } - - - - - internal static int GetBCHTypeInfo(int data) - { - int d = (data << 10); - int s = 0; - while ((s = (int)(QRUtil.GetBCHDigit(d) - QRUtil.GetBCHDigit(QRUtil.G15))) >= 0) - { - d ^= (Convert.ToInt32(QRUtil.G15) << s); - } - return (int)((data << 10) | d) ^ QRUtil.G15_MASK; - } - - internal static int GetBCHTypeNumber(int data) - { - int d = data << 12; - while (QRUtil.GetBCHDigit(d) - QRUtil.GetBCHDigit(QRUtil.G18) >= 0) - { - d ^= (QRUtil.G18 << (QRUtil.GetBCHDigit(d) - QRUtil.GetBCHDigit(QRUtil.G18))); - } - return (data << 12) | d; - } - - internal static int GetBCHDigit(int dataInt) - { - - int digit = 0; - uint data = Convert.ToUInt32(dataInt); - while (data != 0) - { - digit++; - data >>= 1; - } - - return digit; - } - - internal static int[] GetPatternPosition(int typeNumber) - { - return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]; - } - - internal static bool GetMask(QRMaskPattern maskPattern, int i, int j) - { - - switch (maskPattern) - { - - case QRMaskPattern.PATTERN000: return (i + j) % 2 == 0; - case QRMaskPattern.PATTERN001: return i % 2 == 0; - case QRMaskPattern.PATTERN010: return j % 3 == 0; - case QRMaskPattern.PATTERN011: return (i + j) % 3 == 0; - case QRMaskPattern.PATTERN100: return (Math.Floor((double) (i / 2)) + Math.Floor((double) (j / 3))) % 2 == 0; - case QRMaskPattern.PATTERN101: return (i * j) % 2 + (i * j) % 3 == 0; - case QRMaskPattern.PATTERN110: return ((i * j) % 2 + (i * j) % 3) % 2 == 0; - case QRMaskPattern.PATTERN111: return ((i * j) % 3 + (i + j) % 2) % 2 == 0; - - default: - throw new Error("bad maskPattern:" + maskPattern); - } - } - - - - internal static QRPolynomial GetErrorCorrectPolynomial(int errorCorrectLength) - { - QRPolynomial a = new QRPolynomial(new DataCache() { 1 }, 0); - - for (int i = 0; i < errorCorrectLength; i++) - { - a = a.Multiply(new QRPolynomial(new DataCache() { 1, QRMath.GExp(i) }, 0)); - } - - return a; - } - } - - internal struct QRPolynomial - { - private int[] m_num; - public QRPolynomial(DataCache num, int shift) - : this() - { - if (num == null) - { - throw new Error(); - } - - int offset = 0; - - while (offset < num.Count && num[offset] == 0) - { - offset++; - } - - this.m_num = new int[num.Count - offset + shift]; - for (int i = 0; i < num.Count - offset; i++) - { - this.m_num[i] = num[(int)(i + offset)]; - } - } - - public int Get(int index) - { - return this.m_num[(int)index]; - } - - public int GetLength() - { - return (int)this.m_num.Length; - } - - public QRPolynomial Multiply(QRPolynomial e) - { - - var num = new DataCache(this.GetLength() + e.GetLength() - 1); - - for (int i = 0; i < this.GetLength(); i++) - { - for (int j = 0; j < e.GetLength(); j++) - { - num[i + j] ^= QRMath.GExp(QRMath.GLog(this.Get(i)) + QRMath.GLog(e.Get(j))); - } - } - - return new QRPolynomial(num, 0); - } - - public QRPolynomial Mod(QRPolynomial e) - { - - if (Convert.ToInt64(this.GetLength()) - Convert.ToInt64(e.GetLength()) < 0) - { - return this; - } - - int ratio = QRMath.GLog(this.Get(0)) - QRMath.GLog(e.Get(0)); - - var num = new DataCache(this.GetLength()); - - for (int i = 0; i < this.GetLength(); i++) - { - num[i] = this.Get(i); - } - - for (int i = 0; i < e.GetLength(); i++) - { - num[i] ^= QRMath.GExp(QRMath.GLog(e.Get(i)) + ratio); - } - - // recursive call - return new QRPolynomial(num, 0).Mod(e); - } - } - - - internal static class QRMath - { - private static readonly int[] EXP_TABLE; - private static readonly int[] LOG_TABLE; - - static QRMath() - { - EXP_TABLE = new int[256]; - LOG_TABLE = new int[256]; - for (int i = 0; i < 8; i++) - { - QRMath.EXP_TABLE[i] = (int)(1 << (int)i); - } - for (int i = 8; i < 256; i++) - { - QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] - ^ QRMath.EXP_TABLE[i - 5] - ^ QRMath.EXP_TABLE[i - 6] - ^ QRMath.EXP_TABLE[i - 8]; - } - for (int i = 0; i < 255; i++) - { - QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i; - } - } - - internal static int GLog(int n) - { - if (n < 1) - { - throw new Error("glog(" + n + ")"); - } - return QRMath.LOG_TABLE[n]; - } - - internal static int GExp(int n) - { - while (n < 0) - { - n += 255; - } - while (n >= 256) - { - n -= 255; - } - return QRMath.EXP_TABLE[n]; - } - } - - public struct QR8bitByte - { - public QRMode Mode { get; private set; } - private string m_data { get; set; } - - public QR8bitByte(string data) - : this() - { - m_data = data; - Mode = QRMode.MODE_8BIT_BYTE; - } - - public int Length - { - get - { - return m_data.Length; - } - } - - public void Write(QRBitBuffer buffer) - { - for (int i = 0; i < m_data.Length; ++i) - { - //item - buffer.Put(m_data[i], 8); - } - ///buffer = Data; - } - - - } - - internal class DataCache : List - { - public DataCache(int capacity) - : base() - { - for (int i = 0; i < capacity; i++) - { - base.Add(0); - } - } - - public DataCache() - : base() - { - - } - - - } - - internal struct QRRSBlock - { - private static readonly int[][] RS_BLOCK_TABLE = new int[][] { - // L - // M - // Q - // H - - // 1 - new int [] {1, 26, 19}, - new int [] {1, 26, 16}, - new int [] {1, 26, 13}, - new int [] {1, 26, 9}, - - // 2 - new int [] {1, 44, 34}, - new int [] {1, 44, 28}, - new int [] {1, 44, 22}, - new int [] {1, 44, 16}, - - // 3 - new int [] {1, 70, 55}, - new int [] {1, 70, 44}, - new int [] {2, 35, 17}, - new int [] {2, 35, 13}, - - // 4 - new int [] {1, 100, 80}, - new int [] {2, 50, 32}, - new int [] {2, 50, 24}, - new int [] {4, 25, 9}, - - // 5 - new int [] {1, 134, 108}, - new int [] {2, 67, 43}, - new int [] {2, 33, 15, 2, 34, 16}, - new int [] {2, 33, 11, 2, 34, 12}, - - // 6 - new int [] {2, 86, 68}, - new int [] {4, 43, 27}, - new int [] {4, 43, 19}, - new int [] {4, 43, 15}, - - // 7 - new int [] {2, 98, 78}, - new int [] {4, 49, 31}, - new int [] {2, 32, 14, 4, 33, 15}, - new int [] {4, 39, 13, 1, 40, 14}, - - // 8 - new int [] {2, 121, 97}, - new int [] {2, 60, 38, 2, 61, 39}, - new int [] {4, 40, 18, 2, 41, 19}, - new int [] {4, 40, 14, 2, 41, 15}, - - // 9 - new int [] {2, 146, 116}, - new int [] {3, 58, 36, 2, 59, 37}, - new int [] {4, 36, 16, 4, 37, 17}, - new int [] {4, 36, 12, 4, 37, 13}, - - // 10 - new int [] {2, 86, 68, 2, 87, 69}, - new int [] {4, 69, 43, 1, 70, 44}, - new int [] {6, 43, 19, 2, 44, 20}, - new int [] {6, 43, 15, 2, 44, 16} - }; - - - public int DataCount { get; private set; } - public int TotalCount { get; set; } - - public QRRSBlock(int totalCount, int dataCount) - : this() - { - TotalCount = totalCount; - DataCount = dataCount; - } - public static List GetRSBlocks(int typeNumber, QRErrorCorrectLevel errorCorrectLevel) - { - - int[] rsBlock = GetRsBlockTable(typeNumber, errorCorrectLevel); - - if (rsBlock == null) - { - throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel); - } - - int length = (int)rsBlock.Length / 3; - - var list = new List(); - - for (int i = 0; i < length; i++) - { - - int count = rsBlock[i * 3 + 0]; - int totalCount = rsBlock[i * 3 + 1]; - int dataCount = rsBlock[i * 3 + 2]; - - for (int j = 0; j < count; j++) - { - list.Add(new QRRSBlock(totalCount, dataCount)); - } - } - - return list; - } - - private static int[] GetRsBlockTable(int typeNumber, QRErrorCorrectLevel errorCorrectLevel) - { - switch (errorCorrectLevel) - { - case QRErrorCorrectLevel.L: - return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; - case QRErrorCorrectLevel.M: - return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; - case QRErrorCorrectLevel.Q: - return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; - case QRErrorCorrectLevel.H: - return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; - default: - return null; - } - } - } - - public class QRCode - { - private const int PAD0 = 0xEC; - private const int PAD1 = 0x11; - private List m_dataList = new List(); - private int m_typeNumber; - private DataCache m_dataCache; - private int m_moduleCount; - private bool?[][] m_modules; - private QRErrorCorrectLevel m_errorCorrectLevel; - public QRCode(Options options) - : this(options.TypeNumber, options.CorrectLevel) - { - AddData(options.Text); - } - - public QRCode(int typeNumber, QRErrorCorrectLevel level) - { - m_typeNumber = typeNumber; - m_errorCorrectLevel = level; - m_dataCache = null; - } - - public void AddData(string data) - { - m_dataCache = null; - m_dataList.Add(new QR8bitByte(data)); - } - - public void Make() - { - MakeImpl(false, GetBestMaskPattern()); - } - - private QRMaskPattern GetBestMaskPattern() - { - double minLostPoint = 0; - QRMaskPattern pattern = 0; - for (int i = 0; i < 8; i++) - { - this.MakeImpl(true, (QRMaskPattern)i); - - double lostPoint = QRUtil.GetLostPoint(this); - - if (i == 0 || minLostPoint > lostPoint) - { - minLostPoint = lostPoint; - pattern = (QRMaskPattern)i; - } - } - - return pattern; - } - - - - private void MakeImpl(bool test, QRMaskPattern maskPattern) - { - m_moduleCount = this.m_typeNumber * 4 + 17; - m_modules = new bool?[m_moduleCount][]; - for (int row = 0; row < m_moduleCount; row++) - { - - m_modules[row] = new bool?[(m_moduleCount)]; - - for (var col = 0; col < m_moduleCount; col++) - { - m_modules[row][col] = null; //(col + row) % 3; - } - } - - this.SetupPositionProbePattern(0, 0); - this.SetupPositionProbePattern(m_moduleCount - 7, 0); - this.SetupPositionProbePattern(0, m_moduleCount - 7); - this.SetupPositionAdjustPattern(); - this.SetupTimingPattern(); - this.setupTypeInfo(test, maskPattern); - - if (m_typeNumber >= 7) - { - this.setupTypeNumber(test); - } - - if (this.m_dataCache == null) - { - this.m_dataCache = CreateData(this.m_typeNumber, this.m_errorCorrectLevel, this.m_dataList); - } - - MapData(this.m_dataCache, maskPattern); - - } - - public bool IsDark(int row, int col) - { - return m_modules[(int)row][(int)col].Value; - } - - private void SetupTimingPattern() - { - for (var r = 8; r < this.m_moduleCount - 8; r++) - { - if (this.m_modules[r][6] != null) - { - continue; - } - this.m_modules[r][6] = (r % 2 == 0); - } - - for (var c = 8; c < this.m_moduleCount - 8; c++) - { - if (this.m_modules[6][c] != null) - { - continue; - } - this.m_modules[6][c] = (c % 2 == 0); - } - } - - private void setupTypeNumber(bool test) - { - var bits = QRUtil.GetBCHTypeNumber(m_typeNumber); - - for (var i = 0; i < 18; i++) - { - var mod = (!test && ((bits >> i) & 1) == 1); - this.m_modules[(int)Math.Floor((double) (i / 3))][i % 3 + this.m_moduleCount - 8 - 3] = mod; - } - - for (var i = 0; i < 18; i++) - { - var mod = (!test && ((bits >> i) & 1) == 1); - this.m_modules[i % 3 + this.m_moduleCount - 8 - 3][(int)Math.Floor((double) (i / 3))] = mod; - } - } - private void SetupPositionAdjustPattern() - { - var pos = QRUtil.GetPatternPosition(m_typeNumber); - - for (var i = 0; i < pos.Length; i++) - { - - for (var j = 0; j < pos.Length; j++) - { - - var row = pos[i]; - var col = pos[j]; - - if (this.m_modules[row][col] != null) - { - continue; - } - - for (var r = -2; r <= 2; r++) - { - - for (var c = -2; c <= 2; c++) - { - - if (r == -2 || r == 2 || c == -2 || c == 2 - || (r == 0 && c == 0)) - { - this.m_modules[row + r][col + c] = true; - } - else - { - this.m_modules[row + r][col + c] = false; - } - } - } - } - } - } - - - private void setupTypeInfo(bool test, QRMaskPattern maskPattern) - { - - var data = ((int)this.m_errorCorrectLevel << 3) | (int)maskPattern; - var bits = QRUtil.GetBCHTypeInfo(data); - - // vertical - for (var i = 0; i < 15; i++) - { - - var mod = (!test && ((bits >> i) & 1) == 1); - - if (i < 6) - { - this.m_modules[i][8] = mod; - } - else if (i < 8) - { - this.m_modules[i + 1][8] = mod; - } - else - { - this.m_modules[this.m_moduleCount - 15 + i][8] = mod; - } - } - - // horizontal - for (var i = 0; i < 15; i++) - { - - var mod = (!test && ((bits >> i) & 1) == 1); - - if (i < 8) - { - this.m_modules[8][this.m_moduleCount - i - 1] = mod; - } - else if (i < 9) - { - this.m_modules[8][15 - i - 1 + 1] = mod; - } - else - { - this.m_modules[8][15 - i - 1] = mod; - } - } - - // fixed module - this.m_modules[this.m_moduleCount - 8][8] = (!test); - - } - - private void MapData(DataCache data, QRMaskPattern maskPattern) - { - - int inc = -1; - int row = (int)this.m_moduleCount - 1; - int bitIndex = 7; - int byteIndex = 0; - - for (var col = this.m_moduleCount - 1; col > 0; col -= 2) - { - - if (col == 6) col--; - - while (true) - { - - for (int c = 0; c < 2; c++) - { - - if (this.m_modules[row][col - c] == null) - { - - bool dark = false; - - if (byteIndex < data.Count) - { - dark = (((Convert.ToUInt32(data[byteIndex]) >> bitIndex) & 1) == 1); - } - - bool mask = QRUtil.GetMask(maskPattern, (int)row, col - c); - - if (mask) - { - dark = !dark; - } - - this.m_modules[row][col - c] = dark; - bitIndex--; - - if (bitIndex == -1) - { - byteIndex++; - bitIndex = 7; - } - } - } - - row += inc; - - if (row < 0 || this.m_moduleCount <= row) - { - row -= inc; - inc = -inc; - break; - } - } - } - - } - - private DataCache CreateData(int typeNumber, QRErrorCorrectLevel errorCorrectLevel, List dataList) - { - List rsBlocks = QRRSBlock.GetRSBlocks(typeNumber, errorCorrectLevel); - - var buffer = new QRBitBuffer(); - - for (int i = 0; i < dataList.Count; i++) - { - QR8bitByte data = dataList[i]; - - buffer.Put((int)data.Mode, 4); - buffer.Put(data.Length, QRUtil.GetLengthInBits(data.Mode, typeNumber)); - data.Write(buffer); - } - - // calc num max data. - int totalDataCount = 0; - for (var i = 0; i < rsBlocks.Count; i++) - { - totalDataCount += rsBlocks[i].DataCount; - } - - if (buffer.GetLengthInBits() > totalDataCount * 8) - { - throw new Error("code length overflow. (" - + buffer.GetLengthInBits() - + ">" - + totalDataCount * 8 - + ")"); - } - - // end code - if (buffer.GetLengthInBits() + 4 <= totalDataCount * 8) - { - buffer.Put(0, 4); - } - - // padding - while (buffer.GetLengthInBits() % 8 != 0) - { - buffer.PutBit(false); - } - - // padding - while (true) - { - - if (buffer.GetLengthInBits() >= totalDataCount * 8) - { - break; - } - buffer.Put(QRCode.PAD0, 8); - - if (buffer.GetLengthInBits() >= totalDataCount * 8) - { - break; - } - buffer.Put(QRCode.PAD1, 8); - } - - return CreateBytes(buffer, rsBlocks); - } - - private DataCache CreateBytes(QRBitBuffer buffer, List rsBlocks) - { - - int offset = 0; - - int maxDcCount = 0; - int maxEcCount = 0; - - var dcdata = new DataCache[(rsBlocks.Count)]; - var ecdata = new DataCache[(rsBlocks.Count)]; - - for (int r = 0; r < rsBlocks.Count; r++) - { - - int dcCount = rsBlocks[(int)r].DataCount; - int ecCount = rsBlocks[(int)r].TotalCount - dcCount; - - maxDcCount = Math.Max(maxDcCount, dcCount); - maxEcCount = Math.Max(maxEcCount, ecCount); - - dcdata[r] = new DataCache(dcCount); - - for (int i = 0; i < dcdata[r].Count; i++) - { - dcdata[r][i] = 0xff & buffer.m_buffer[(int)(i + offset)]; - } - offset += dcCount; - - QRPolynomial rsPoly = QRUtil.GetErrorCorrectPolynomial(ecCount); - QRPolynomial rawPoly = new QRPolynomial(dcdata[r], rsPoly.GetLength() - 1); - - var modPoly = rawPoly.Mod(rsPoly); - ecdata[r] = new DataCache(rsPoly.GetLength() - 1); - for (int i = 0; i < ecdata[r].Count; i++) - { - int modIndex = i + modPoly.GetLength() - (int)ecdata[r].Count; - ecdata[r][i] = (modIndex >= 0) ? modPoly.Get(modIndex) : 0; - } - - } - - int totalCodeCount = 0; - for (int i = 0; i < rsBlocks.Count; i++) - { - totalCodeCount += rsBlocks[(int)i].TotalCount; - } - - var data = new DataCache(totalCodeCount); - int index = 0; - - for (int i = 0; i < maxDcCount; i++) - { - for (int r = 0; r < rsBlocks.Count; r++) - { - if (i < dcdata[r].Count) - { - data[index++] = dcdata[r][i]; - } - } - } - - for (int i = 0; i < maxEcCount; i++) - { - for (int r = 0; r < rsBlocks.Count; r++) - { - if (i < ecdata[r].Count) - { - data[index++] = ecdata[r][i]; - } - } - } - - return data; - - } - private void SetupPositionProbePattern(int row, int col) - { - for (int r = -1; r <= 7; r++) - { - - if (row + r <= -1 || this.m_moduleCount <= row + r) continue; - - for (int c = -1; c <= 7; c++) - { - - if (col + c <= -1 || this.m_moduleCount <= col + c) continue; - - if ((0 <= r && r <= 6 && (c == 0 || c == 6)) - || (0 <= c && c <= 6 && (r == 0 || r == 6)) - || (2 <= r && r <= 4 && 2 <= c && c <= 4)) - { - this.m_modules[row + r][col + c] = true; - } - else - { - this.m_modules[row + r][col + c] = false; - } - } - } - } - - public int GetModuleCount() - { - return this.m_moduleCount; - } - - internal int getBestMaskPattern() - { - - double minLostPoint = 0; - int pattern = 0; - - for (int i = 0; i < 8; i++) - { - - this.MakeImpl(true, (QRMaskPattern)i); - - double lostPoint = QRUtil.GetLostPoint(this); - - if (i == 0 || minLostPoint > lostPoint) - { - minLostPoint = lostPoint; - pattern = i; - } - } - - return pattern; - } - } - - public class QRBitBuffer - { - internal List m_buffer = new List(); - private int m_length = 0; - public bool Get(int index) - { - int bufIndex = Convert.ToInt32(Math.Floor((double) (index / 8))); - return ((Convert.ToUInt32(this.m_buffer[bufIndex]) >> (7 - index % 8)) & 1) == 1; - } - - public void Put(int num, int length) - { - for (var i = 0; i < length; i++) - { - this.PutBit(((Convert.ToUInt32(num) >> (length - i - 1)) & 1) == 1); - } - } - - public int GetLengthInBits() - { - return m_length; - } - - public void PutBit(bool bit) - { - - int bufIndex = (int)Math.Floor((double) (this.m_length / 8)); - if (this.m_buffer.Count <= bufIndex) - { - this.m_buffer.Add(0); - } - - if (bit) - { - this.m_buffer[bufIndex] |= (int)(Convert.ToUInt32(0x80) >> (this.m_length % 8)); - } - this.m_length++; - } - } -} diff --git a/shadowsocks-csharp/3rd/zxing/BitArray.cs b/shadowsocks-csharp/3rd/zxing/BitArray.cs new file mode 100755 index 00000000..e0234e1a --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/BitArray.cs @@ -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 +{ + /// + /// A simple, fast array of bits, represented compactly by an array of ints internally. + /// + /// Sean Owen + 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; + } + } + + /// Flips bit i. + /// + /// + /// bit to set + /// + 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 + }; + + /// + /// Gets the next set. + /// + /// first bit to check + /// index of first bit that is set, starting from the given index, or size if none are set + /// at or beyond this given index + 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; + } + + /// + /// see getNextSet(int) + /// + /// index to start looking for unset bit + /// index of next unset bit, or if none are unset until the end + 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; + } + + /// Sets a block of 32 bits, starting at bit i. + /// + /// + /// first bit to set + /// + /// 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. + /// + public void setBulk(int i, int newBits) + { + bits[i >> 5] = newBits; + } + + /// + /// Sets a range of bits. + /// + /// start of range, inclusive. + /// end of range, exclusive + 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; + } + } + + /// Clears all bits (sets to false). + public void clear() + { + int max = bits.Length; + for (int i = 0; i < max; i++) + { + bits[i] = 0; + } + } + + /// Efficient method to check if a range of bits is set, or not set. + /// + /// + /// start of range, inclusive. + /// + /// end of range, exclusive + /// + /// if true, checks that bits in range are set, otherwise checks that they are not set + /// + /// true iff all bits are set or not set in range, according to value argument + /// + /// IllegalArgumentException if end is less than or equal to start + 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; + } + + /// + /// Appends the bit. + /// + /// The bit. + public void appendBit(bool bit) + { + ensureCapacity(size + 1); + if (bit) + { + bits[size >> 5] |= 1 << (size & 0x1F); + } + size++; + } + + /// underlying array of ints. The first element holds the first 32 bits, and the least + /// significant bit is bit 0. + /// + public int[] Array + { + get { return bits; } + } + + /// + /// 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. + /// + /// containing bits to append + /// bits from value to append + 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]; + } + } + + /// + /// Toes the bytes. + /// + /// first bit to start writing + /// array to write into. Bytes are written most-significant byte first. This is the opposite + /// of the internal representation, which is exposed by BitArray + /// position in array to start writing + /// how many bytes to write + 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; + } + } + + /// Reverses all bits in the array. + 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]; + } + + /// + /// Determines whether the specified is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + 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; + } + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() + { + var hash = size; + foreach (var bit in bits) + { + hash = 31 * hash + bit.GetHashCode(); + } + return hash; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + 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(); + } + + /// + /// Erstellt ein neues Objekt, das eine Kopie der aktuellen Instanz darstellt. + /// + /// + /// Ein neues Objekt, das eine Kopie dieser Instanz darstellt. + /// + public object Clone() + { + return new BitArray((int[])bits.Clone(), size); + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/BitMatrix.cs b/shadowsocks-csharp/3rd/zxing/BitMatrix.cs new file mode 100755 index 00000000..d0378d45 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/BitMatrix.cs @@ -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 +{ + /// + ///

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.

+ ///

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.

+ ///

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.

+ ///
+ /// Sean Owen + /// dswitkin@google.com (Daniel Switkin) + public sealed partial class BitMatrix + { + private readonly int width; + private readonly int height; + private readonly int rowSize; + private readonly int[] bits; + + /// The width of the matrix + /// + public int Width + { + get + { + return width; + } + + } + /// The height of the matrix + /// + public int Height + { + get + { + return height; + } + + } + /// 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. + /// + /// + /// row/column dimension of this matrix + /// + 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; + } + + ///

Gets the requested bit, where true means black.

+ /// + ///
+ /// The horizontal component (i.e. which column) + /// + /// The vertical component (i.e. which row) + /// + /// value of given bit in matrix + /// + 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); + } + } + } + + ///

Flips the given bit.

+ /// + ///
+ /// The horizontal component (i.e. which column) + /// + /// The vertical component (i.e. which row) + /// + public void flip(int x, int y) + { + int offset = y * rowSize + (x >> 5); + bits[offset] ^= 1 << (x & 0x1f); + } + + /// Clears all bits (sets to false). + public void clear() + { + int max = bits.Length; + for (int i = 0; i < max; i++) + { + bits[i] = 0; + } + } + + ///

Sets a square region of the bit matrix to true.

+ /// + ///
+ /// The horizontal position to begin at (inclusive) + /// + /// The vertical position to begin at (inclusive) + /// + /// The width of the region + /// + /// The height of the region + /// + 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); + } + } + } + + /// A fast method to retrieve one row of data from the matrix as a BitArray. + /// + /// + /// The row to retrieve + /// + /// An optional caller-allocated BitArray, will be allocated if null or too small + /// + /// The resulting BitArray - this reference should always be used even when passing + /// your own row + /// + 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; + } + + /// + /// Sets the row. + /// + /// row to set + /// {@link BitArray} to copy from + public void setRow(int y, BitArray row) + { + Array.Copy(row.Array, 0, bits, y * rowSize, rowSize); + } + + /// + /// Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees + /// + 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); + } + } + + /// + /// This is useful in detecting the enclosing rectangle of a 'pure' barcode. + /// + /// {left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white + 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 }; + } + + /// + /// This is useful in detecting a corner of a 'pure' barcode. + /// + /// {x,y} coordinate of top-left-most 1 bit, or null if it is all white + 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()); + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/BlockPair.cs b/shadowsocks-csharp/3rd/zxing/BlockPair.cs new file mode 100755 index 00000000..b1afff46 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/BlockPair.cs @@ -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; } + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/ByteMatrix.cs b/shadowsocks-csharp/3rd/zxing/ByteMatrix.cs new file mode 100755 index 00000000..e3d372fd --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/ByteMatrix.cs @@ -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 +{ + /// + /// 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. + /// + /// dswitkin@google.com (Daniel Switkin) + public sealed class ByteMatrix + { + private readonly byte[][] bytes; + private readonly int width; + private readonly int height; + + /// + /// Initializes a new instance of the class. + /// + /// The width. + /// The height. + 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; + } + + /// + /// Gets the height. + /// + public int Height + { + get { return height; } + } + + /// + /// Gets the width. + /// + public int Width + { + get { return width; } + } + + /// + /// Gets or sets the with the specified x. + /// + public int this[int x, int y] + { + get { return bytes[y][x]; } + set { bytes[y][x] = (byte)value; } + } + + /// + /// an internal representation as bytes, in row-major order. array[y][x] represents point (x,y) + /// + public byte[][] Array + { + get { return bytes; } + } + + /// + /// Sets the specified x. + /// + /// The x. + /// The y. + /// The value. + public void set(int x, int y, byte value) + { + bytes[y][x] = value; + } + + /// + /// Sets the specified x. + /// + /// The x. + /// The y. + /// if set to true [value]. + public void set(int x, int y, bool value) + { + bytes[y][x] = (byte)(value ? 1 : 0); + } + + /// + /// Clears the specified value. + /// + /// The value. + public void clear(byte value) + { + for (int y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + bytes[y][x] = value; + } + } + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + 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(); + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/EncodeHintType.cs b/shadowsocks-csharp/3rd/zxing/EncodeHintType.cs new file mode 100755 index 00000000..01b17f8c --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/EncodeHintType.cs @@ -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 +{ + /// + /// These are a set of hints that you may pass to Writers to specify their behavior. + /// + /// dswitkin@google.com (Daniel Switkin) + public enum EncodeHintType + { + /// + /// Specifies the width of the barcode image + /// type: + /// + WIDTH, + + /// + /// Specifies the height of the barcode image + /// type: + /// + HEIGHT, + + /// + /// Don't put the content string into the output image. + /// type: + /// + PURE_BARCODE, + + /// + /// 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 + /// + /// For Aztec it is of type , 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 or (between 0 and 8), + /// + ERROR_CORRECTION, + + /// + /// Specifies what character encoding to use where applicable. + /// type: + /// + CHARACTER_SET, + + /// + /// 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: + /// + MARGIN, + + /// + /// Specifies whether to use compact mode for PDF417. + /// type: + /// + PDF417_COMPACT, + + /// + /// Specifies what compaction mode to use for PDF417. + /// type: + /// + PDF417_COMPACTION, + + /// + /// Specifies the minimum and maximum number of rows and columns for PDF417. + /// type: + /// + PDF417_DIMENSIONS, + + /// + /// 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: + /// + DISABLE_ECI, + + /// + /// Specifies the matrix shape for Data Matrix (type ) + /// + DATA_MATRIX_SHAPE, + + /// + /// Specifies a minimum barcode size (type ). Only applicable to Data Matrix now. + /// + MIN_SIZE, + + /// + /// Specifies a maximum barcode size (type ). Only applicable to Data Matrix now. + /// + MAX_SIZE, + + /// + /// if true, don't switch to codeset C for numbers + /// + CODE128_FORCE_CODESET_B, + + /// + /// Specifies the default encodation for Data Matrix (type ) + /// Make sure that the content fits into the encodation value, otherwise there will be an exception thrown. + /// standard value: Encodation.ASCII + /// + DATA_MATRIX_DEFAULT_ENCODATION, + + /// + /// 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 + /// + AZTEC_LAYERS, + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/Encoder.cs b/shadowsocks-csharp/3rd/zxing/Encoder.cs new file mode 100755 index 00000000..694d6ca4 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/Encoder.cs @@ -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 +{ + /// + /// + /// satorux@google.com (Satoru Takabayashi) - creator + /// dswitkin@google.com (Daniel Switkin) - ported from C++ + 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); + } + + /// + /// 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. + /// + /// text to encode + /// error correction level to use + /// representing the encoded QR code + public static QRCode encode(String content, ErrorCorrectionLevel ecLevel) + { + return encode(content, ecLevel, null); + } + + /// + /// Encodes the specified content. + /// + /// The content. + /// The ec level. + /// The hints. + /// + public static QRCode encode(String content, + ErrorCorrectionLevel ecLevel, + IDictionary 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; + } + + /// + /// Gets the alphanumeric code. + /// + /// The code. + /// the code point of the table used in alphanumeric mode or + /// -1 if there is no corresponding code in the table. + internal static int getAlphanumericCode(int code) + { + if (code < ALPHANUMERIC_TABLE.Length) + { + return ALPHANUMERIC_TABLE[code]; + } + return -1; + } + + /// + /// Chooses the mode. + /// + /// The content. + /// + public static Mode chooseMode(String content) + { + return chooseMode(content, null); + } + + /// + /// 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}. + /// + /// The content. + /// The encoding. + /// + 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"); + } + + /// + /// Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). + /// + /// The num data bytes. + /// The bits. + 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"); + } + } + + /// + /// 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) + /// + /// The num total bytes. + /// The num data bytes. + /// The num RS blocks. + /// The block ID. + /// The num data bytes in block. + /// The num EC bytes in block. + 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; + } + } + + /// + /// 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. + /// + /// The bits. + /// The num total bytes. + /// The num data bytes. + /// The num RS blocks. + /// + 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(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; + } + + /// + /// Append mode info. On success, store the result in "bits". + /// + /// The mode. + /// The bits. + internal static void appendModeInfo(Mode mode, BitArray bits) + { + bits.appendBits(mode.Bits, 4); + } + + + /// + /// Append length info. On success, store the result in "bits". + /// + /// The num letters. + /// The version. + /// The mode. + /// The bits. + 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); + } + + /// + /// Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". + /// + /// The content. + /// The mode. + /// The bits. + /// The encoding. + 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); + } + * */ + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/ErrorCorrectionLevel.cs b/shadowsocks-csharp/3rd/zxing/ErrorCorrectionLevel.cs new file mode 100755 index 00000000..f3b49347 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/ErrorCorrectionLevel.cs @@ -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 +{ + /// + ///

See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels + /// defined by the QR code standard.

+ ///
+ /// Sean Owen + public sealed class ErrorCorrectionLevel + { + /// L = ~7% correction + public static readonly ErrorCorrectionLevel L = new ErrorCorrectionLevel(0, 0x01, "L"); + /// M = ~15% correction + public static readonly ErrorCorrectionLevel M = new ErrorCorrectionLevel(1, 0x00, "M"); + /// Q = ~25% correction + public static readonly ErrorCorrectionLevel Q = new ErrorCorrectionLevel(2, 0x03, "Q"); + /// H = ~30% correction + 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; + } + + /// + /// Gets the bits. + /// + public int Bits + { + get + { + return bits; + } + } + + /// + /// Gets the name. + /// + public String Name + { + get + { + return name; + } + } + + private readonly int ordinal_Renamed_Field; + private readonly String name; + + /// + /// Ordinals this instance. + /// + /// + public int ordinal() + { + return ordinal_Renamed_Field; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override String ToString() + { + return name; + } + + /// + /// Fors the bits. + /// + /// int containing the two bits encoding a QR Code's error correction level + /// + /// representing the encoded error correction level + /// + public static ErrorCorrectionLevel forBits(int bits) + { + if (bits < 0 || bits >= FOR_BITS.Length) + { + throw new ArgumentException(); + } + return FOR_BITS[bits]; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/FormatInformation.cs b/shadowsocks-csharp/3rd/zxing/FormatInformation.cs new file mode 100755 index 00000000..88b5045e --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/FormatInformation.cs @@ -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 +{ + + ///

Encapsulates a QR Code's format information, including the data mask used and + /// error correction level.

+ /// + ///
+ /// Sean Owen + /// + /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source + /// + /// + /// + /// + /// + sealed class FormatInformation + { + private const int FORMAT_INFO_MASK_QR = 0x5412; + + /// See ISO 18004:2006, Annex C, Table C.1 + 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 } + }; + + /// Offset i holds the number of 1 bits in the binary representation of i + 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)]; + } + + /// + /// Decodes the format information. + /// + /// format info indicator, with mask still applied + /// The masked format info2. + /// + /// information about the format it specifies, or null + /// if doesn't seem to match any known pattern + /// + 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; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/GenericGF.cs b/shadowsocks-csharp/3rd/zxing/GenericGF.cs new file mode 100755 index 00000000..8a2835ea --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/GenericGF.cs @@ -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 +{ + /// + ///

This class contains utility methods for performing mathematical operations over + /// the Galois Fields. Operations use a given primitive polynomial in calculations.

+ ///

Throughout this package, elements of the GF are represented as an {@code int} + /// for convenience and speed (but at the cost of memory). + ///

+ ///
+ /// Sean Owen + 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; + + /// + /// Create a representation of GF(size) using the given primitive polynomial. + /// + /// irreducible polynomial whose coefficients are represented by + /// * the bits of an int, where the least-significant bit represents the constant + /// * coefficient + /// the size of the field + /// 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. + 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; + } + } + + /// + /// Builds the monomial. + /// + /// The degree. + /// The coefficient. + /// the monomial representing coefficient * x^degree + 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); + } + + /// + /// Implements both addition and subtraction -- they are the same in GF(size). + /// + /// sum/difference of a and b + static internal int addOrSubtract(int a, int b) + { + return a ^ b; + } + + /// + /// Exps the specified a. + /// + /// 2 to the power of a in GF(size) + internal int exp(int a) + { + return expTable[a]; + } + + /// + /// Logs the specified a. + /// + /// A. + /// base 2 log of a in GF(size) + internal int log(int a) + { + if (a == 0) + { + throw new ArgumentException(); + } + return logTable[a]; + } + + /// + /// Inverses the specified a. + /// + /// multiplicative inverse of a + internal int inverse(int a) + { + if (a == 0) + { + throw new ArithmeticException(); + } + return expTable[size - logTable[a] - 1]; + } + + /// + /// Multiplies the specified a with b. + /// + /// A. + /// The b. + /// product of a and b in GF(size) + internal int multiply(int a, int b) + { + if (a == 0 || b == 0) + { + return 0; + } + return expTable[(logTable[a] + logTable[b]) % (size - 1)]; + } + + /// + /// Gets the size. + /// + public int Size + { + get { return size; } + } + + /// + /// Gets the generator base. + /// + public int GeneratorBase + { + get { return generatorBase; } + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + override public String ToString() + { + return "GF(0x" + primitive.ToString("X") + ',' + size + ')'; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/GenericGFPoly.cs b/shadowsocks-csharp/3rd/zxing/GenericGFPoly.cs new file mode 100755 index 00000000..8307a1dd --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/GenericGFPoly.cs @@ -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 +{ + /// + ///

Represents a polynomial whose coefficients are elements of a GF. + /// Instances of this class are immutable.

+ ///

Much credit is due to William Rucklidge since portions of this code are an indirect + /// port of his C++ Reed-Solomon implementation.

+ ///
+ /// Sean Owen + internal sealed class GenericGFPoly + { + private readonly GenericGF field; + private readonly int[] coefficients; + + /// + /// Initializes a new instance of the class. + /// + /// the {@link GenericGF} instance representing the field to use + /// to perform computations + /// coefficients as ints representing elements of GF(size), arranged + /// from most significant (highest-power term) coefficient to least significant + /// 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") + 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; } + } + + /// + /// degree of this polynomial + /// + internal int Degree + { + get + { + return coefficients.Length - 1; + } + } + + /// + /// Gets a value indicating whether this is zero. + /// + /// true iff this polynomial is the monomial "0" + internal bool isZero + { + get { return coefficients[0] == 0; } + } + + /// + /// coefficient of x^degree term in this polynomial + /// + /// The degree. + /// coefficient of x^degree term in this polynomial + internal int getCoefficient(int degree) + { + return coefficients[coefficients.Length - 1 - degree]; + } + + /// + /// evaluation of this polynomial at a given point + /// + /// A. + /// evaluation of this polynomial at a given point + 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(); + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/MaskUtil.cs b/shadowsocks-csharp/3rd/zxing/MaskUtil.cs new file mode 100755 index 00000000..24e85cc1 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/MaskUtil.cs @@ -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 +{ + /// + /// + /// + /// Satoru Takabayashi + /// Daniel Switkin + /// Sean Owen + 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; + + /// + /// 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. + /// + /// The matrix. + /// + public static int applyMaskPenaltyRule1(ByteMatrix matrix) + { + return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false); + } + + /// + /// 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. + /// + /// The matrix. + /// + 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; + } + + /// + /// 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). + /// + /// The matrix. + /// + 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; + } + + /// + /// 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. + /// + /// The matrix. + /// + 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; + } + + /// + /// Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask + /// pattern conditions. + /// + /// The mask pattern. + /// The x. + /// The y. + /// + 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; + } + + /// + /// Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both + /// vertical and horizontal orders respectively. + /// + /// The matrix. + /// if set to true [is horizontal]. + /// + 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; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/MatrixUtil.cs b/shadowsocks-csharp/3rd/zxing/MatrixUtil.cs new file mode 100755 index 00000000..ffd9c7b4 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/MatrixUtil.cs @@ -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 +{ + /// + /// + /// + /// + /// satorux@google.com (Satoru Takabayashi) - creator + /// + 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; + + /// + /// 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. + /// + /// The matrix. + public static void clearMatrix(ByteMatrix matrix) + { + matrix.clear(2); + } + + /// + /// Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On + /// success, store the result in "matrix" and return true. + /// + /// The data bits. + /// The ec level. + /// The version. + /// The mask pattern. + /// The matrix. + 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); + } + + /// + /// 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 + /// + /// The version. + /// The matrix. + 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); + } + + /// + /// Embed type information. On success, modify the matrix. + /// + /// The ec level. + /// The mask pattern. + /// The matrix. + 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; + } + } + } + + /// + /// 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. + /// + /// The version. + /// The matrix. + 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; + } + } + } + + /// + /// 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. + /// + /// The data bits. + /// The mask pattern. + /// The matrix. + 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); + } + } + + /// + /// 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 + /// + /// The value_ renamed. + /// + public static int findMSBSet(int value_Renamed) + { + int numDigits = 0; + while (value_Renamed != 0) + { + value_Renamed = (int)((uint)value_Renamed >> 1); + ++numDigits; + } + return numDigits; + } + + /// + /// 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. + /// + /// The value. + /// The poly. + /// + 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; + } + + /// + /// 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. + /// + /// The ec level. + /// The mask pattern. + /// The bits. + 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); + } + } + + /// + /// 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. + /// + /// The version. + /// The bits. + 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); + } + } + + /// + /// Check if "value" is empty. + /// + /// The value. + /// + /// true if the specified value is empty; otherwise, false. + /// + 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; + } + } + } + + /// + /// Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) + /// + /// The matrix. + 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; + } + } + + /// + /// 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. + /// + /// The x start. + /// The y start. + /// The matrix. + 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]; + } + } + } + + /// + /// Embed position detection patterns and surrounding vertical/horizontal separators. + /// + /// The matrix. + 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); + } + + /// + /// Embed position adjustment patterns if need be. + /// + /// The version. + /// The matrix. + 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); + } + } + } + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/Mode.cs b/shadowsocks-csharp/3rd/zxing/Mode.cs new file mode 100755 index 00000000..548ea6d7 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/Mode.cs @@ -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 +{ + /// + ///

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.

+ ///
+ /// Sean Owen + public sealed class Mode + { + /// + /// Gets the name. + /// + public String Name + { + get + { + return name; + } + } + + // No, we can't use an enum here. J2ME doesn't support it. + + /// + /// + /// + public static readonly Mode TERMINATOR = new Mode(new int[] { 0, 0, 0 }, 0x00, "TERMINATOR"); // Not really a mode... + /// + /// + /// + public static readonly Mode NUMERIC = new Mode(new int[] { 10, 12, 14 }, 0x01, "NUMERIC"); + /// + /// + /// + public static readonly Mode ALPHANUMERIC = new Mode(new int[] { 9, 11, 13 }, 0x02, "ALPHANUMERIC"); + /// + /// + /// + public static readonly Mode STRUCTURED_APPEND = new Mode(new int[] { 0, 0, 0 }, 0x03, "STRUCTURED_APPEND"); // Not supported + /// + /// + /// + public static readonly Mode BYTE = new Mode(new int[] { 8, 16, 16 }, 0x04, "BYTE"); + /// + /// + /// + public static readonly Mode ECI = new Mode(null, 0x07, "ECI"); // character counts don't apply + /// + /// + /// + public static readonly Mode KANJI = new Mode(new int[] { 8, 10, 12 }, 0x08, "KANJI"); + /// + /// + /// + public static readonly Mode FNC1_FIRST_POSITION = new Mode(null, 0x05, "FNC1_FIRST_POSITION"); + /// + /// + /// + public static readonly Mode FNC1_SECOND_POSITION = new Mode(null, 0x09, "FNC1_SECOND_POSITION"); + /// See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. + 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; + } + + /// + /// Fors the bits. + /// + /// four bits encoding a QR Code data mode + /// + /// encoded by these bits + /// + /// if bits do not correspond to a known mode + 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(); + } + } + + /// version in question + /// + /// 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} + /// + 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]; + } + + /// + /// Gets the bits. + /// + public int Bits + { + get + { + return bits; + } + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override String ToString() + { + return name; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/QRCode.cs b/shadowsocks-csharp/3rd/zxing/QRCode.cs new file mode 100755 index 00000000..312f94ef --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/QRCode.cs @@ -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 +{ + /// satorux@google.com (Satoru Takabayashi) - creator + /// dswitkin@google.com (Daniel Switkin) - ported from C++ + public class QRCode + { + /// + /// + /// + public static int NUM_MASK_PATTERNS = 8; + + /// + /// Initializes a new instance of the class. + /// + public QRCode() + { + MaskPattern = -1; + } + + /// + /// Gets or sets the mode. + /// + /// + /// The mode. + /// + public Mode Mode { get; set; } + + /// + /// Gets or sets the EC level. + /// + /// + /// The EC level. + /// + public ErrorCorrectionLevel ECLevel { get; set; } + + /// + /// Gets or sets the version. + /// + /// + /// The version. + /// + public Version Version { get; set; } + + /// + /// Gets or sets the mask pattern. + /// + /// + /// The mask pattern. + /// + public int MaskPattern { get; set; } + + /// + /// Gets or sets the matrix. + /// + /// + /// The matrix. + /// + public ByteMatrix Matrix { get; set; } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + 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(); + } + + /// + /// Check if "mask_pattern" is valid. + /// + /// The mask pattern. + /// + /// true if [is valid mask pattern] [the specified mask pattern]; otherwise, false. + /// + public static bool isValidMaskPattern(int maskPattern) + { + return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/ReedSolomonEncoder.cs b/shadowsocks-csharp/3rd/zxing/ReedSolomonEncoder.cs new file mode 100755 index 00000000..78aca71d --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/ReedSolomonEncoder.cs @@ -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 +{ + /// + /// Implements Reed-Solomon encoding, as the name implies. + /// + /// Sean Owen + /// William Rucklidge + public sealed class ReedSolomonEncoder + { + private readonly GenericGF field; + private readonly IList cachedGenerators; + + public ReedSolomonEncoder(GenericGF field) + { + this.field = field; + this.cachedGenerators = new List(); + 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); + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/Version.cs b/shadowsocks-csharp/3rd/zxing/Version.cs new file mode 100755 index 00000000..1404a709 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/Version.cs @@ -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 +{ + /// + /// See ISO 18004:2006 Annex D + /// + /// Sean Owen + public sealed class Version + { + /// See ISO 18004:2006 Annex D. + /// Element i represents the raw version bits that specify version i + 7 + /// + 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; + } + + /// + /// Gets the version number. + /// + public int VersionNumber + { + get + { + return versionNumber; + } + + } + + /// + /// Gets the alignment pattern centers. + /// + public int[] AlignmentPatternCenters + { + get + { + return alignmentPatternCenters; + } + + } + + /// + /// Gets the total codewords. + /// + public int TotalCodewords + { + get + { + return totalCodewords; + } + + } + + /// + /// Gets the dimension for version. + /// + public int DimensionForVersion + { + get + { + return 17 + 4 * versionNumber; + } + + } + + /// + /// Gets the EC blocks for level. + /// + /// The ec level. + /// + public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) + { + return ecBlocks[ecLevel.ordinal()]; + } + + ///

Deduces version information purely from QR Code dimensions.

+ /// + ///
+ /// dimension in modules + /// + /// for a QR Code of that dimension or null + public static Version getProvisionalVersionForDimension(int dimension) + { + if (dimension % 4 != 1) + { + return null; + } + try + { + return getVersionForNumber((dimension - 17) >> 2); + } + catch (ArgumentException) + { + return null; + } + } + + /// + /// Gets the version for number. + /// + /// The version number. + /// + 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; + } + + /// See ISO 18004:2006 Annex E + 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; + } + + ///

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.

+ ///
+ 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; + } + + /// + /// Gets the EC codewords per block. + /// + public int ECCodewordsPerBlock + { + get + { + return ecCodewordsPerBlock; + } + } + + /// + /// Gets the num blocks. + /// + public int NumBlocks + { + get + { + int total = 0; + foreach (var ecBlock in ecBlocks) + { + total += ecBlock.Count; + } + return total; + } + } + + /// + /// Gets the total EC codewords. + /// + public int TotalECCodewords + { + get + { + return ecCodewordsPerBlock * NumBlocks; + } + } + + /// + /// Gets the EC blocks. + /// + /// + public ECB[] getECBlocks() + { + return ecBlocks; + } + } + + ///

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.

+ ///
+ public sealed class ECB + { + private readonly int count; + private readonly int dataCodewords; + + internal ECB(int count, int dataCodewords) + { + this.count = count; + this.dataCodewords = dataCodewords; + } + + /// + /// Gets the count. + /// + public int Count + { + get + { + return count; + } + + } + /// + /// Gets the data codewords. + /// + public int DataCodewords + { + get + { + return dataCodewords; + } + + } + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override String ToString() + { + return Convert.ToString(versionNumber); + } + + /// See ISO 18004:2006 6.5.1 Table 9 + 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))) + }; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/View/QRCodeForm.cs b/shadowsocks-csharp/View/QRCodeForm.cs index 3cde5f63..27a3ab92 100755 --- a/shadowsocks-csharp/View/QRCodeForm.cs +++ b/shadowsocks-csharp/View/QRCodeForm.cs @@ -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); } diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 1444ca66..ccbf8cc2 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -69,8 +69,23 @@ - + + + + + + + + + + + + + + + +