diff --git a/Cargo.toml b/Cargo.toml index 34291b2..aa951a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rxing" -version = "0.2.11" +version = "0.2.12" description="A rust port of the zxing barcode library." license="Apache-2.0" repository="https://github.com/hschimke/rxing" @@ -37,3 +37,4 @@ java-rand = "0.2.0" [features] default = ["image"] image = ["dep:image", "dep:imageproc"] +allow_forced_iso_ied_18004_compliance = [] diff --git a/src/decode_hints.rs b/src/decode_hints.rs index 0c1d65f..905fdb7 100644 --- a/src/decode_hints.rs +++ b/src/decode_hints.rs @@ -104,8 +104,19 @@ pub enum DecodeHintType { * second time with an inverted image. Doesn't matter what it maps to; use {@link Boolean#TRUE}. */ ALSO_INVERTED, - // End of enumeration values. + /** + * Specifies that the codes are expected to be in conformance with the specification + * ISO/IEC 18004 regading the interpretation of character encoding. Values encoded in BYTE mode + * or in KANJI mode are interpreted as ISO-8859-1 characters unless an ECI specified at a prior + * location in the input specified a different encoding. By default the encoding of BYTE encoded + * values is determinied by the {@link #CHARACTER_SET} hint or otherwise by a heuristic that + * examines the bytes. By default KANJI encoded values are interpreted as the bytes of Shift-JIS + * encoded characters (note that this is the case even if an ECI specifies a different + * encoding). + */ + #[cfg(feature = "allow_forced_iso_ied_18004_compliance")] + QR_ASSUME_SPEC_CONFORM_INPUT, /* * Data type the hint is expecting. * Among the possible values the {@link Void} stands out as being used for @@ -201,5 +212,17 @@ pub enum DecodeHintValue { * second time with an inverted image. Doesn't matter what it maps to; use {@link Boolean#TRUE}. */ AlsoInverted(bool), - // End of enumeration values. + + /** + * Specifies that the codes are expected to be in conformance with the specification + * ISO/IEC 18004 regading the interpretation of character encoding. Values encoded in BYTE mode + * or in KANJI mode are interpreted as ISO-8859-1 characters unless an ECI specified at a prior + * location in the input specified a different encoding. By default the encoding of BYTE encoded + * values is determinied by the {@link #CHARACTER_SET} hint or otherwise by a heuristic that + * examines the bytes. By default KANJI encoded values are interpreted as the bytes of Shift-JIS + * encoded characters (note that this is the case even if an ECI specifies a different + * encoding). + */ + #[cfg(feature = "allow_forced_iso_ied_18004_compliance")] + QrAssumeSpecConformInput(bool), } diff --git a/src/qrcode/decoder/decoded_bit_stream_parser.rs b/src/qrcode/decoder/decoded_bit_stream_parser.rs index c225043..805ff83 100644 --- a/src/qrcode/decoder/decoded_bit_stream_parser.rs +++ b/src/qrcode/decoder/decoded_bit_stream_parser.rs @@ -19,6 +19,9 @@ use crate::{ DecodingHintDictionary, Exceptions, }; +#[cfg(feature = "allow_forced_iso_ied_18004_compliance")] +use crate::{DecodeHintType, DecodeHintValue}; + use super::{ErrorCorrectionLevel, Mode, VersionRef}; /** @@ -125,7 +128,13 @@ pub fn decode( &mut byteSegments, hints, )?, - Mode::KANJI => decodeKanjiSegment(&mut bits, &mut result, count)?, + Mode::KANJI => decodeKanjiSegment( + &mut bits, + &mut result, + count, + currentCharacterSetECI, + hints, + )?, _ => return Err(Exceptions::FormatException(None)), } } @@ -217,6 +226,8 @@ fn decodeKanjiSegment( bits: &mut BitSource, result: &mut String, count: usize, + currentCharacterSetECI: Option, + hints: &DecodingHintDictionary, ) -> Result<(), Exceptions> { // Don't crash trying to read more bits than we have available. if count * 13 > bits.available() { @@ -245,10 +256,32 @@ fn decodeKanjiSegment( count -= 1; } - let sjs_encoder = encoding::label::encoding_from_whatwg_label("SJIS").unwrap(); - let encode_string = sjs_encoder + #[cfg(not(feature = "allow_forced_iso_ied_18004_compliance"))] + let encoder = { + let _ = currentCharacterSetECI; + let _ = hints; + encoding::label::encoding_from_whatwg_label("SJIS").unwrap() + }; + + #[cfg(feature = "allow_forced_iso_ied_18004_compliance")] + let encoder = if let Some(DecodeHintValue::QrAssumeSpecConformInput(true)) = + hints.get(&DecodeHintType::QR_ASSUME_SPEC_CONFORM_INPUT) + { + // if (hints != null && hints.containsKey(DecodeHintType.QR_ASSUME_SPEC_CONFORM_INPUT)) { + if let Some(ccse) = ¤tCharacterSetECI { + // if (currentCharacterSetECI == null) { + CharacterSetECI::getCharset(ccse) + } else { + encoding::all::ISO_8859_1 + } + } else { + encoding::label::encoding_from_whatwg_label("SJIS").unwrap() + }; + + let encode_string = encoder .decode(&buffer, encoding::DecoderTrap::Strict) .unwrap(); + result.push_str(&encode_string); Ok(()) @@ -280,7 +313,19 @@ fn decodeByteSegment( // upon decoding. I have seen ISO-8859-1 used as well as // Shift_JIS -- without anything like an ECI designator to // give a hint. - StringUtils::guessCharset(&readBytes, hints) + { + #[cfg(not(feature = "allow_forced_iso_ied_18004_compliance"))] + StringUtils::guessCharset(&readBytes, hints) + } + + #[cfg(feature = "allow_forced_iso_ied_18004_compliance")] + if let Some(DecodeHintValue::QrAssumeSpecConformInput(true)) = + hints.get(&DecodeHintType::QR_ASSUME_SPEC_CONFORM_INPUT) + { + encoding::all::ISO_8859_1 + } else { + StringUtils::guessCharset(&readBytes, hints) + } } else { CharacterSetECI::getCharset(currentCharacterSetECI.as_ref().unwrap()) };