initial commit
This commit is contained in:
467
reader/QRCodeDataBlockReader.cs
Normal file
467
reader/QRCodeDataBlockReader.cs
Normal file
@@ -0,0 +1,467 @@
|
||||
using System;
|
||||
using QRCodeDecoder = ThoughtWorks.QRCode.Codec.QRCodeDecoder;
|
||||
using InvalidDataBlockException = ThoughtWorks.QRCode.ExceptionHandler.InvalidDataBlockException;
|
||||
using DebugCanvas = ThoughtWorks.QRCode.Codec.Util.DebugCanvas;
|
||||
using SystemUtils = ThoughtWorks.QRCode.Codec.Util.SystemUtils;
|
||||
namespace ThoughtWorks.QRCode.Codec.Reader
|
||||
{
|
||||
|
||||
public class QRCodeDataBlockReader
|
||||
{
|
||||
virtual internal int NextMode
|
||||
{
|
||||
get
|
||||
{
|
||||
//canvas.println("data blocks:"+ (blocks.length - numErrorCorrectionCode));
|
||||
if ((blockPointer > blocks.Length - numErrorCorrectionCode - 2))
|
||||
return 0;
|
||||
else
|
||||
return getNextBits(4);
|
||||
}
|
||||
|
||||
}
|
||||
virtual public sbyte[] DataByte
|
||||
{
|
||||
get
|
||||
{
|
||||
canvas.println("Reading data blocks.");
|
||||
System.IO.MemoryStream output = new System.IO.MemoryStream();
|
||||
|
||||
try
|
||||
{
|
||||
do
|
||||
{
|
||||
int mode = NextMode;
|
||||
//canvas.println("mode: " + mode);
|
||||
if (mode == 0)
|
||||
{
|
||||
if (output.Length > 0)
|
||||
break;
|
||||
else
|
||||
throw new InvalidDataBlockException("Empty data block");
|
||||
}
|
||||
//if (mode != 1 && mode != 2 && mode != 4 && mode != 8)
|
||||
// break;
|
||||
//}
|
||||
if (mode != MODE_NUMBER && mode != MODE_ROMAN_AND_NUMBER && mode != MODE_8BIT_BYTE && mode != MODE_KANJI)
|
||||
{
|
||||
/* canvas.println("Invalid mode: " + mode);
|
||||
mode = guessMode(mode);
|
||||
canvas.println("Guessed mode: " + mode); */
|
||||
throw new InvalidDataBlockException("Invalid mode: " + mode + " in (block:" + blockPointer + " bit:" + bitPointer + ")");
|
||||
}
|
||||
dataLength = getDataLength(mode);
|
||||
if (dataLength < 1)
|
||||
throw new InvalidDataBlockException("Invalid data length: " + dataLength);
|
||||
//canvas.println("length: " + dataLength);
|
||||
switch (mode)
|
||||
{
|
||||
|
||||
case MODE_NUMBER:
|
||||
//canvas.println("Mode: Figure");
|
||||
sbyte[] temp_sbyteArray;
|
||||
temp_sbyteArray = SystemUtils.ToSByteArray(SystemUtils.ToByteArray(getFigureString(dataLength)));
|
||||
output.Write(SystemUtils.ToByteArray(temp_sbyteArray), 0, temp_sbyteArray.Length);
|
||||
break;
|
||||
|
||||
case MODE_ROMAN_AND_NUMBER:
|
||||
//canvas.println("Mode: Roman&Figure");
|
||||
sbyte[] temp_sbyteArray2;
|
||||
temp_sbyteArray2 = SystemUtils.ToSByteArray(SystemUtils.ToByteArray(getRomanAndFigureString(dataLength)));
|
||||
output.Write(SystemUtils.ToByteArray(temp_sbyteArray2), 0, temp_sbyteArray2.Length);
|
||||
break;
|
||||
|
||||
case MODE_8BIT_BYTE:
|
||||
//canvas.println("Mode: 8bit Byte");
|
||||
sbyte[] temp_sbyteArray3;
|
||||
temp_sbyteArray3 = get8bitByteArray(dataLength);
|
||||
output.Write(SystemUtils.ToByteArray(temp_sbyteArray3), 0, temp_sbyteArray3.Length);
|
||||
break;
|
||||
|
||||
case MODE_KANJI:
|
||||
//canvas.println("Mode: Kanji");
|
||||
sbyte[] temp_sbyteArray4;
|
||||
temp_sbyteArray4 = SystemUtils.ToSByteArray(SystemUtils.ToByteArray(getKanjiString(dataLength)));
|
||||
output.Write(SystemUtils.ToByteArray(temp_sbyteArray4), 0, temp_sbyteArray4.Length);
|
||||
break;
|
||||
}
|
||||
//
|
||||
//canvas.println("DataLength: " + dataLength);
|
||||
//Console.out.println(dataString);
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
catch (System.IndexOutOfRangeException e)
|
||||
{
|
||||
SystemUtils.WriteStackTrace(e, Console.Error);
|
||||
throw new InvalidDataBlockException("Data Block Error in (block:" + blockPointer + " bit:" + bitPointer + ")");
|
||||
}
|
||||
catch (System.IO.IOException e)
|
||||
{
|
||||
throw new InvalidDataBlockException(e.Message);
|
||||
}
|
||||
return SystemUtils.ToSByteArray(output.ToArray());
|
||||
}
|
||||
|
||||
}
|
||||
virtual public String DataString
|
||||
{
|
||||
get
|
||||
{
|
||||
canvas.println("Reading data blocks...");
|
||||
String dataString = "";
|
||||
do
|
||||
{
|
||||
int mode = NextMode;
|
||||
canvas.println("mode: " + mode);
|
||||
if (mode == 0)
|
||||
break;
|
||||
//if (mode != 1 && mode != 2 && mode != 4 && mode != 8)
|
||||
// break;
|
||||
//}
|
||||
if (mode != MODE_NUMBER && mode != MODE_ROMAN_AND_NUMBER && mode != MODE_8BIT_BYTE && mode != MODE_KANJI)
|
||||
{
|
||||
// mode = guessMode(mode);
|
||||
// do not guesswork
|
||||
//Console.out.println("guessed mode: " + mode);
|
||||
}
|
||||
|
||||
dataLength = getDataLength(mode);
|
||||
canvas.println(System.Convert.ToString(blocks[blockPointer]));
|
||||
System.Console.Out.WriteLine("length: " + dataLength);
|
||||
switch (mode)
|
||||
{
|
||||
|
||||
case MODE_NUMBER:
|
||||
//canvas.println("Mode: Figure");
|
||||
dataString += getFigureString(dataLength);
|
||||
break;
|
||||
|
||||
case MODE_ROMAN_AND_NUMBER:
|
||||
//canvas.println("Mode: Roman&Figure");
|
||||
dataString += getRomanAndFigureString(dataLength);
|
||||
break;
|
||||
|
||||
case MODE_8BIT_BYTE:
|
||||
//canvas.println("Mode: 8bit Byte");
|
||||
dataString += get8bitByteString(dataLength);
|
||||
break;
|
||||
|
||||
case MODE_KANJI:
|
||||
//canvas.println("Mode: Kanji");
|
||||
dataString += getKanjiString(dataLength);
|
||||
break;
|
||||
}
|
||||
//canvas.println("DataLength: " + dataLength);
|
||||
//Console.out.println(dataString);
|
||||
}
|
||||
while (true);
|
||||
System.Console.Out.WriteLine("");
|
||||
return dataString;
|
||||
}
|
||||
|
||||
}
|
||||
internal int[] blocks;
|
||||
internal int dataLengthMode;
|
||||
internal int blockPointer;
|
||||
internal int bitPointer;
|
||||
internal int dataLength;
|
||||
internal int numErrorCorrectionCode;
|
||||
internal DebugCanvas canvas;
|
||||
|
||||
const int MODE_NUMBER = 1;
|
||||
const int MODE_ROMAN_AND_NUMBER = 2;
|
||||
const int MODE_8BIT_BYTE = 4;
|
||||
const int MODE_KANJI = 8;
|
||||
int[][] sizeOfDataLengthInfo = new int[][] { new int[] { 10, 9, 8, 8 }, new int[] { 12, 11, 16, 10 }, new int[] { 14, 13, 16, 12 } };
|
||||
|
||||
public QRCodeDataBlockReader(int[] blocks, int version, int numErrorCorrectionCode)
|
||||
{
|
||||
blockPointer = 0;
|
||||
bitPointer = 7;
|
||||
dataLength = 0;
|
||||
this.blocks = blocks;
|
||||
this.numErrorCorrectionCode = numErrorCorrectionCode;
|
||||
if (version <= 9)
|
||||
dataLengthMode = 0;
|
||||
else if (version >= 10 && version <= 26)
|
||||
dataLengthMode = 1;
|
||||
else if (version >= 27 && version <= 40)
|
||||
dataLengthMode = 2;
|
||||
canvas = QRCodeDecoder.Canvas;
|
||||
}
|
||||
|
||||
internal virtual int getNextBits(int numBits)
|
||||
{
|
||||
int bits = 0;
|
||||
if (numBits < bitPointer + 1)
|
||||
{
|
||||
// next word fits into current data block
|
||||
int mask = 0;
|
||||
for (int i = 0; i < numBits; i++)
|
||||
{
|
||||
mask += (1 << i);
|
||||
}
|
||||
mask <<= (bitPointer - numBits + 1);
|
||||
|
||||
bits = (blocks[blockPointer] & mask) >> (bitPointer - numBits + 1);
|
||||
bitPointer -= numBits;
|
||||
return bits;
|
||||
}
|
||||
else if (numBits < bitPointer + 1 + 8)
|
||||
{
|
||||
// next word crosses 2 data blocks
|
||||
int mask1 = 0;
|
||||
for (int i = 0; i < bitPointer + 1; i++)
|
||||
{
|
||||
mask1 += (1 << i);
|
||||
}
|
||||
bits = (blocks[blockPointer] & mask1) << (numBits - (bitPointer + 1));
|
||||
blockPointer++;
|
||||
bits += ((blocks[blockPointer]) >> (8 - (numBits - (bitPointer + 1))));
|
||||
|
||||
bitPointer = bitPointer - numBits % 8;
|
||||
if (bitPointer < 0)
|
||||
{
|
||||
bitPointer = 8 + bitPointer;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
else if (numBits < bitPointer + 1 + 16)
|
||||
{
|
||||
// next word crosses 3 data blocks
|
||||
int mask1 = 0; // mask of first block
|
||||
int mask3 = 0; // mask of 3rd block
|
||||
//bitPointer + 1 : number of bits of the 1st block
|
||||
//8 : number of the 2nd block (note that use already 8bits because next word uses 3 data blocks)
|
||||
//numBits - (bitPointer + 1 + 8) : number of bits of the 3rd block
|
||||
for (int i = 0; i < bitPointer + 1; i++)
|
||||
{
|
||||
mask1 += (1 << i);
|
||||
}
|
||||
int bitsFirstBlock = (blocks[blockPointer] & mask1) << (numBits - (bitPointer + 1));
|
||||
blockPointer++;
|
||||
|
||||
int bitsSecondBlock = blocks[blockPointer] << (numBits - (bitPointer + 1 + 8));
|
||||
blockPointer++;
|
||||
|
||||
for (int i = 0; i < numBits - (bitPointer + 1 + 8); i++)
|
||||
{
|
||||
mask3 += (1 << i);
|
||||
}
|
||||
mask3 <<= 8 - (numBits - (bitPointer + 1 + 8));
|
||||
int bitsThirdBlock = (blocks[blockPointer] & mask3) >> (8 - (numBits - (bitPointer + 1 + 8)));
|
||||
|
||||
bits = bitsFirstBlock + bitsSecondBlock + bitsThirdBlock;
|
||||
bitPointer = bitPointer - (numBits - 8) % 8;
|
||||
if (bitPointer < 0)
|
||||
{
|
||||
bitPointer = 8 + bitPointer;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Console.Out.WriteLine("ERROR!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual int guessMode(int mode)
|
||||
{
|
||||
//correct modes: 0001 0010 0100 1000
|
||||
//possible data: 0000 0011 0101 1001 0110 1010 1100
|
||||
// 0111 1101 1011 1110 1111
|
||||
// MODE_NUMBER = 1;
|
||||
// MODE_ROMAN_AND_NUMBER = 2;
|
||||
// MODE_8BIT_BYTE = 4;
|
||||
// MODE_KANJI = 8;
|
||||
switch (mode)
|
||||
{
|
||||
|
||||
case 3:
|
||||
return MODE_NUMBER;
|
||||
|
||||
case 5:
|
||||
return MODE_8BIT_BYTE;
|
||||
|
||||
case 6:
|
||||
return MODE_8BIT_BYTE;
|
||||
|
||||
case 7:
|
||||
return MODE_8BIT_BYTE;
|
||||
|
||||
case 9:
|
||||
return MODE_KANJI;
|
||||
|
||||
case 10:
|
||||
return MODE_KANJI;
|
||||
|
||||
case 11:
|
||||
return MODE_KANJI;
|
||||
|
||||
case 12:
|
||||
return MODE_8BIT_BYTE;
|
||||
|
||||
case 13:
|
||||
return MODE_8BIT_BYTE;
|
||||
|
||||
case 14:
|
||||
return MODE_8BIT_BYTE;
|
||||
|
||||
case 15:
|
||||
return MODE_8BIT_BYTE;
|
||||
|
||||
default:
|
||||
return MODE_KANJI;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual int getDataLength(int modeIndicator)
|
||||
{
|
||||
int index = 0;
|
||||
while (true)
|
||||
{
|
||||
if ((modeIndicator >> index) == 1)
|
||||
break;
|
||||
index++;
|
||||
}
|
||||
|
||||
return getNextBits(sizeOfDataLengthInfo[dataLengthMode][index]);
|
||||
}
|
||||
|
||||
|
||||
internal virtual String getFigureString(int dataLength)
|
||||
{
|
||||
int length = dataLength;
|
||||
int intData = 0;
|
||||
String strData = "";
|
||||
do
|
||||
{
|
||||
if (length >= 3)
|
||||
{
|
||||
intData = getNextBits(10);
|
||||
if (intData < 100)
|
||||
strData += "0";
|
||||
if (intData < 10)
|
||||
strData += "0";
|
||||
length -= 3;
|
||||
}
|
||||
else if (length == 2)
|
||||
{
|
||||
intData = getNextBits(7);
|
||||
if (intData < 10)
|
||||
strData += "0";
|
||||
length -= 2;
|
||||
}
|
||||
else if (length == 1)
|
||||
{
|
||||
intData = getNextBits(4);
|
||||
length -= 1;
|
||||
}
|
||||
strData += System.Convert.ToString(intData);
|
||||
}
|
||||
while (length > 0);
|
||||
|
||||
return strData;
|
||||
}
|
||||
|
||||
internal virtual String getRomanAndFigureString(int dataLength)
|
||||
{
|
||||
int length = dataLength;
|
||||
int intData = 0;
|
||||
String strData = "";
|
||||
char[] tableRomanAndFigure = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':'};
|
||||
do
|
||||
{
|
||||
if (length > 1)
|
||||
{
|
||||
intData = getNextBits(11);
|
||||
int firstLetter = intData / 45;
|
||||
int secondLetter = intData % 45;
|
||||
strData += System.Convert.ToString(tableRomanAndFigure[firstLetter]);
|
||||
strData += System.Convert.ToString(tableRomanAndFigure[secondLetter]);
|
||||
length -= 2;
|
||||
}
|
||||
else if (length == 1)
|
||||
{
|
||||
intData = getNextBits(6);
|
||||
strData += System.Convert.ToString(tableRomanAndFigure[intData]);
|
||||
length -= 1;
|
||||
}
|
||||
}
|
||||
while (length > 0);
|
||||
|
||||
return strData;
|
||||
}
|
||||
|
||||
public virtual sbyte[] get8bitByteArray(int dataLength)
|
||||
{
|
||||
int length = dataLength;
|
||||
int intData = 0;
|
||||
System.IO.MemoryStream output = new System.IO.MemoryStream();
|
||||
|
||||
do
|
||||
{
|
||||
canvas.println("Length: " + length);
|
||||
intData = getNextBits(8);
|
||||
output.WriteByte((byte) intData);
|
||||
length--;
|
||||
}
|
||||
while (length > 0);
|
||||
return SystemUtils.ToSByteArray(output.ToArray());
|
||||
}
|
||||
|
||||
internal virtual String get8bitByteString(int dataLength)
|
||||
{
|
||||
int length = dataLength;
|
||||
int intData = 0;
|
||||
String strData = "";
|
||||
do
|
||||
{
|
||||
intData = getNextBits(8);
|
||||
strData += (char) intData;
|
||||
length--;
|
||||
}
|
||||
while (length > 0);
|
||||
return strData;
|
||||
}
|
||||
|
||||
internal virtual String getKanjiString(int dataLength)
|
||||
{
|
||||
int length = dataLength;
|
||||
int intData = 0;
|
||||
String unicodeString = "";
|
||||
do
|
||||
{
|
||||
intData = getNextBits(13);
|
||||
int lowerByte = intData % 0xC0;
|
||||
int higherByte = intData / 0xC0;
|
||||
|
||||
int tempWord = (higherByte << 8) + lowerByte;
|
||||
int shiftjisWord = 0;
|
||||
if (tempWord + 0x8140 <= 0x9FFC)
|
||||
{
|
||||
// between 8140 - 9FFC on Shift_JIS character set
|
||||
shiftjisWord = tempWord + 0x8140;
|
||||
}
|
||||
else
|
||||
{
|
||||
// between E040 - EBBF on Shift_JIS character set
|
||||
shiftjisWord = tempWord + 0xC140;
|
||||
}
|
||||
|
||||
sbyte[] tempByte = new sbyte[2];
|
||||
tempByte[0] = (sbyte) (shiftjisWord >> 8);
|
||||
tempByte[1] = (sbyte) (shiftjisWord & 0xFF);
|
||||
unicodeString += new String(SystemUtils.ToCharArray(SystemUtils.ToByteArray(tempByte)));
|
||||
length--;
|
||||
}
|
||||
while (length > 0);
|
||||
|
||||
|
||||
return unicodeString;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user