private static bool DecodeNumericSegment(BitSource bits, StringBuilder result, int count) { // Read three digits at a time while (count >= 3) { // Each 10 bits encodes three digits if (bits.Available() < 10) { return(false); } int threeDigitsBits = bits.ReadBits(10); if (threeDigitsBits >= 1000) { return(false); } result.Append(ToAlphaNumericChar(threeDigitsBits / 100)); result.Append(ToAlphaNumericChar((threeDigitsBits / 10) % 10)); result.Append(ToAlphaNumericChar(threeDigitsBits % 10)); count -= 3; } if (count == 2) { // Two digits left over to read, encoded in 7 bits if (bits.Available() < 7) { return(false); } int twoDigitsBits = bits.ReadBits(7); if (twoDigitsBits >= 100) { return(false); } result.Append(ToAlphaNumericChar(twoDigitsBits / 10)); result.Append(ToAlphaNumericChar(twoDigitsBits % 10)); } else if (count == 1) { // One digit left over to read if (bits.Available() < 4) { return(false); } int digitBits = bits.ReadBits(4); if (digitBits >= 10) { return(false); } result.Append(ToAlphaNumericChar(digitBits)); } return(true); }
private static bool DecodeAlphanumericSegment(BitSource bits, StringBuilder result, int count, bool fc1InEffect) { // Read two characters at a time int start = result.Length; while (count > 1) { if (bits.Available() < 11) { return(false); } int nextTwoCharsBits = bits.ReadBits(11); result.Append(ToAlphaNumericChar(nextTwoCharsBits / 45)); result.Append(ToAlphaNumericChar(nextTwoCharsBits % 45)); count -= 2; } if (count == 1) { // special case: one character left if (bits.Available() < 6) { return(false); } result.Append(ToAlphaNumericChar(bits.ReadBits(6))); } // See section 6.4.8.1, 6.4.8.2 if (fc1InEffect) { // We need to massage the result a bit if in an FNC1 mode: for (int i = start; i < result.Length; i++) { if (result[i] == '%') { if (i < result.Length - 1 && result[i + 1] == '%') { // %% is rendered as % result.Remove(i + 1, 1); } else { // In alpha mode, % should be converted to FNC1 separator 0x1D result.Remove(i, 1); result.Insert(i, new[] { (char)0x1D }); } } } } return(true); }
private static bool DecodeKanjiSegment(BitSource bits, StringBuilder result, int count) { // Don't crash trying to read more bits than we have available. if (count * 13 > bits.Available()) { return(false); } // Each character will require 2 bytes. Read the characters as 2-byte pairs // and decode as Shift_JIS afterwards byte[] buffer = new byte[2 * count]; int offset = 0; while (count > 0) { // Each 13 bits encodes a 2-byte character int twoBytes = bits.ReadBits(13); int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0); if (assembledTwoBytes < 0x01F00) { // In the 0x8140 to 0x9FFC range assembledTwoBytes += 0x08140; } else { // In the 0xE040 to 0xEBBF range assembledTwoBytes += 0x0C140; } buffer[offset] = (byte)(assembledTwoBytes >> 8); buffer[offset + 1] = (byte)assembledTwoBytes; offset += 2; count--; } // Shift_JIS may not be supported in some environments: try { result.Append(Encoding.GetEncoding(StringUtils.SHIFT_JIS).GetString(buffer, 0, buffer.Length)); } #if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH) catch (ArgumentException) { try { // Silverlight only supports a limited number of character sets, trying fallback to UTF-8 result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length)); } catch (Exception) { return(false); } } #endif catch (Exception) { return(false); } return(true); }
private static void DecodeByteSegment(BitSource bits, StringBuilder result, int count, CharacterSetECI currentCharacterSetECI, System.Collections.ArrayList byteSegments) { sbyte[] readBytes = new sbyte[count]; if (count << 3 > bits.Available()) { throw ReaderException.Instance; } for (int i = 0; i < count; i++) { readBytes[i] = (sbyte)bits.ReadBits(8); } // The spec isn't clear on this mode; see // section 6.4.5: t does not say which encoding to assuming // upon decoding. I have seen ISO-8859-1 used as well as // Shift_JIS -- without anything like an ECI designator to // give a hint. var encoding = currentCharacterSetECI == null?GuessEncoding(readBytes) : currentCharacterSetECI.EncodingName; try { //UPGRADE_TODO: The differences in the Format of parameters for constructor 'java.lang.String.String' may cause compilation errors. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'" result.Append(Encoding.GetEncoding(encoding).GetString(SupportClass.ToByteArray(readBytes))); } catch (IOException) { throw ReaderException.Instance; } byteSegments.Add(SupportClass.ToByteArray(readBytes)); }
/// <summary> /// See specification GBT 18284-2000 /// </summary> /// <param name="bits">The bits.</param> /// <param name="result">The result.</param> /// <param name="count">The count.</param> /// <returns></returns> private static bool DecodeHanziSegment(BitSource bits, StringBuilder result, int count) { // Don't crash trying to read more bits than we have available. if (count * 13 > bits.Available()) { return(false); } // Each character will require 2 bytes. Read the characters as 2-byte pairs // and decode as GB2312 afterwards byte[] buffer = new byte[2 * count]; int offset = 0; while (count > 0) { // Each 13 bits encodes a 2-byte character int twoBytes = bits.ReadBits(13); int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060); if (assembledTwoBytes < 0x003BF) { // In the 0xA1A1 to 0xAAFE range assembledTwoBytes += 0x0A1A1; } else { // In the 0xB0A1 to 0xFAFE range assembledTwoBytes += 0x0A6A1; } buffer[offset] = (byte)((assembledTwoBytes >> 8) & 0xFF); buffer[offset + 1] = (byte)(assembledTwoBytes & 0xFF); offset += 2; count--; } try { result.Append(Encoding.GetEncoding(StringUtils.GB2312).GetString(buffer, 0, buffer.Length)); } catch (ArgumentException) { try { // Silverlight only supports a limited number of character sets, trying fallback to UTF-8 result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length)); } catch (Exception) { return(false); } } catch (Exception) { return(false); } return(true); }
private static bool DecodeByteSegment(BitSource bits, StringBuilder result, int count, CharacterSetECI currentCharacterSetECI, IList <byte[]> byteSegments) { // Don't crash trying to read more bits than we have available. if (count << 3 > bits.Available()) { return(false); } byte[] readBytes = new byte[count]; for (int i = 0; i < count; i++) { readBytes[i] = (byte)bits.ReadBits(8); } String encoding; if (currentCharacterSetECI == null) { // The spec isn't clear on this mode; see // section 6.4.5: t does not say which encoding to assuming // upon decoding. I have seen ISO-8859-1 used as well as // Shift_JIS -- without anything like an ECI designator to // give a hint. encoding = StringUtils.GuessEncoding(readBytes); } else { encoding = currentCharacterSetECI.EncodingName; } try { result.Append(Encoding.GetEncoding(encoding).GetString(readBytes, 0, readBytes.Length)); } catch (ArgumentException) { try { // Silverlight only supports a limited number of character sets, trying fallback to UTF-8 result.Append(Encoding.GetEncoding("UTF-8").GetString(readBytes, 0, readBytes.Length)); } catch (Exception) { return(false); } } catch (Exception) { return(false); } byteSegments.Add(readBytes); return(true); }
internal static DecoderResult Decode(byte[] bytes, Version version, ErrorCorrectionLevel ecLevel) { var bits = new BitSource(bytes); var result = new StringBuilder(50); var byteSegments = new List <byte[]>(1); var symbolSequence = -1; var parityData = -1; try { CharacterSetECI currentCharacterSetECI = null; bool fc1InEffect = false; Mode mode; do { // While still another segment to read... if (bits.Available() < 4) { // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here mode = Mode.TERMINATOR; } else { try { mode = Mode.ForBits(bits.ReadBits(4)); // mode is encoded by 4 bits } catch (ArgumentException) { return(null); } } switch (mode.Name) { case Mode.Names.TERMINATOR: break; case Mode.Names.FNC1_FIRST_POSITION: case Mode.Names.FNC1_SECOND_POSITION: // We do little with FNC1 except alter the parsed result a bit according to the spec fc1InEffect = true; break; case Mode.Names.STRUCTURED_APPEND: if (bits.Available() < 16) { return(null); } // not really supported; but sequence number and parity is added later to the result metadata // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue symbolSequence = bits.ReadBits(8); parityData = bits.ReadBits(8); break; case Mode.Names.ECI: // Count doesn't apply to ECI int value = ParseECIValue(bits); currentCharacterSetECI = CharacterSetECI.GetCharacterSetECIByValue(value); if (currentCharacterSetECI == null) { return(null); } break; case Mode.Names.HANZI: // First handle Hanzi mode which does not start with character count //chinese mode contains a sub set indicator right after mode indicator int subset = bits.ReadBits(4); int countHanzi = bits.ReadBits(mode.GetCharacterCountBits(version)); if (subset == GB2312_SUBSET) { if (!DecodeHanziSegment(bits, result, countHanzi)) { return(null); } } break; default: // "Normal" QR code modes: // How many characters will follow, encoded in this mode? int count = bits.ReadBits(mode.GetCharacterCountBits(version)); switch (mode.Name) { case Mode.Names.NUMERIC: if (!DecodeNumericSegment(bits, result, count)) { return(null); } break; case Mode.Names.ALPHANUMERIC: if (!DecodeAlphanumericSegment(bits, result, count, fc1InEffect)) { return(null); } break; case Mode.Names.BYTE: if (!DecodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments)) { return(null); } break; case Mode.Names.KANJI: if (!DecodeKanjiSegment(bits, result, count)) { return(null); } break; default: return(null); } break; } } while (mode != Mode.TERMINATOR); } catch (ArgumentException) { // from readBits() calls return(null); } var resultString = result.ToString().Replace("\r\n", "\n").Replace("\n", Environment.NewLine); return(new DecoderResult(bytes, resultString)); }
internal static DecoderResult Decode(sbyte[] bytes, Version version, ErrorCorrectionLevel ecLevel) { BitSource bits = new BitSource(bytes); StringBuilder result = new StringBuilder(50); CharacterSetECI currentCharacterSetECI = null; bool fc1InEffect = false; System.Collections.ArrayList byteSegments = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(1)); Mode mode; do { // While still another segment to read... if (bits.Available() < 4) { // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here mode = Mode.TERMINATOR; } else { try { mode = Mode.ForBits(bits.ReadBits(4)); // mode is encoded by 4 bits } catch (ArgumentException) { throw ReaderException.Instance; } } if (!mode.Equals(Mode.TERMINATOR)) { if (mode.Equals(Mode.FNC1_FIRST_POSITION) || mode.Equals(Mode.FNC1_SECOND_POSITION)) { // We do little with FNC1 except alter the parsed result a bit according to the spec fc1InEffect = true; } else if (mode.Equals(Mode.STRUCTURED_APPEND)) { // not really supported; all we do is ignore it // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue bits.ReadBits(16); } else if (mode.Equals(Mode.ECI)) { // Count doesn't apply to ECI int value_Renamed = ParseECIValue(bits); currentCharacterSetECI = CharacterSetECI.GetCharacterSetECIByValue(value_Renamed); if (currentCharacterSetECI == null) { throw ReaderException.Instance; } } else { // How many characters will follow, encoded in this mode? int count = bits.ReadBits(mode.GetCharacterCountBits(version)); if (mode.Equals(Mode.NUMERIC)) { DecodeNumericSegment(bits, result, count); } else if (mode.Equals(Mode.ALPHANUMERIC)) { DecodeAlphanumericSegment(bits, result, count, fc1InEffect); } else if (mode.Equals(Mode.BYTE)) { DecodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments); } else if (mode.Equals(Mode.KANJI)) { DecodeKanjiSegment(bits, result, count); } else { throw ReaderException.Instance; } } } }while (!mode.Equals(Mode.TERMINATOR)); return(new DecoderResult(bytes, result.ToString(), (byteSegments.Count == 0)?null:byteSegments, ecLevel)); }