repurpose CharacterSetECI as encoding abstraction

This commit is contained in:
Henry Schimke
2023-03-02 15:50:56 -06:00
parent c4fec7d2ee
commit a0b8b68869
29 changed files with 304 additions and 337 deletions

View File

@@ -204,9 +204,9 @@ fn decodeHanziSegment(bits: &mut BitSource, result: &mut String, count: usize) -
}
let gb_encoder =
encoding::label::encoding_from_whatwg_label("GBK").ok_or(Exceptions::ILLEGAL_STATE)?;
CharacterSetECI::GB18030;
let encode_string = gb_encoder
.decode(&buffer, encoding::DecoderTrap::Strict)
.decode(&buffer)
.map_err(|e| Exceptions::parse_with(format!("unable to decode buffer {buffer:?}: {e}")))?;
result.push_str(&encode_string);
Ok(())
@@ -250,7 +250,7 @@ fn decodeKanjiSegment(
let encoder = {
let _ = currentCharacterSetECI;
let _ = hints;
encoding::label::encoding_from_whatwg_label("SJIS").ok_or(Exceptions::FORMAT)?
CharacterSetECI::SJIS
};
#[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
@@ -258,16 +258,16 @@ fn decodeKanjiSegment(
hints.get(&DecodeHintType::QR_ASSUME_SPEC_CONFORM_INPUT)
{
if let Some(ccse) = &currentCharacterSetECI {
CharacterSetECI::getCharset(ccse)
CharacterSetECI::getCharacterSetECIByName(ccse)
} else {
encoding::all::ISO_8859_1
CharacterSetECI::ISO8859_1
}
} else {
encoding::label::encoding_from_whatwg_label("SJIS").ok_or(Exceptions::FORMAT)?
CharacterSetECI::SJIS
};
let encode_string = encoder
.decode(&buffer, encoding::DecoderTrap::Strict)
.decode(&buffer)
.map_err(|e| Exceptions::parse_with(format!("unable to decode buffer {buffer:?}: {e}")))?;
result.push_str(&encode_string);
@@ -308,37 +308,26 @@ fn decodeByteSegment(
if let Some(DecodeHintValue::QrAssumeSpecConformInput(true)) =
hints.get(&DecodeHintType::QR_ASSUME_SPEC_CONFORM_INPUT)
{
encoding::all::ISO_8859_1
CharacterSetECI::ISO8859_1
} else {
StringUtils::guessCharset(&readBytes, hints).ok_or(Exceptions::ILLEGAL_STATE)?
}
} else {
CharacterSetECI::getCharset(
currentCharacterSetECI
.as_ref()
.ok_or(Exceptions::ILLEGAL_STATE)?,
)
currentCharacterSetECI.ok_or(Exceptions::ILLEGAL_STATE)?
// CharacterSetECI::getCharset(
// currentCharacterSetECI
// .as_ref()
// .ok_or(Exceptions::ILLEGAL_STATE)?,
// )
};
let encode_string = if currentCharacterSetECI.is_some()
&& currentCharacterSetECI
.as_ref()
.ok_or(Exceptions::ILLEGAL_STATE)?
== &CharacterSetECI::Cp437
{
{
use codepage_437::BorrowFromCp437;
use codepage_437::CP437_CONTROL;
String::borrow_from_cp437(&readBytes, &CP437_CONTROL)
}
} else {
let encode_string =
encoding
.decode(&readBytes, encoding::DecoderTrap::Strict)
.decode(&readBytes)
.map_err(|e| {
Exceptions::parse_with(format!("unable to decode buffer {readBytes:?}: {e}"))
})?
};
;
result.push_str(&encode_string);
byteSegments.push(readBytes);

View File

@@ -17,20 +17,19 @@
use std::collections::HashMap;
use crate::{
common::BitArray,
common::{BitArray, CharacterSetECI},
qrcode::{
decoder::{ErrorCorrectionLevel, Mode, Version},
encoder::{qrcode_encoder, MinimalEncoder},
},
EncodeHintType, EncodeHintValue,
};
use encoding::EncodingRef;
use once_cell::sync::Lazy;
use super::QRCode;
static SHIFT_JIS_CHARSET: Lazy<EncodingRef> =
Lazy::new(|| encoding::label::encoding_from_whatwg_label("SJIS").unwrap());
static SHIFT_JIS_CHARSET: Lazy<CharacterSetECI> =
Lazy::new(|| CharacterSetECI::SJIS);
/**
* @author satorux@google.com (Satoru Takabayashi) - creator
@@ -1075,10 +1074,9 @@ fn testMinimalEncoder41() {
#[test]
fn testMinimalEncoder42() {
// test halfwidth Katakana character (they are single byte encoded in Shift_JIS)
// NOTE: Changed to windows-31j because that is what is supported in encoding crate
verifyMinimalEncoding(
"Katakana:\u{FF66}\u{FF66}\u{FF66}\u{FF66}\u{FF66}\u{FF66}",
"ECI(windows-31j),BYTE(Katakana:......)",
"ECI(shift_jis),BYTE(Katakana:......)",
None,
false,
);
@@ -1100,10 +1098,9 @@ fn testMinimalEncoder44() {
// The character \u30A2 encodes as double byte in Shift_JIS but KANJI is not more compact in this case because
// KANJI is only more compact when it encodes pairs of characters. In the case of mixed text it can however be
// that Shift_JIS encoding is more compact as in this example
// NOTE: Changed to windows-31j because that is what is supported in encoding crate
verifyMinimalEncoding(
"Katakana:\u{30A2}a\u{30A2}a\u{30A2}a\u{30A2}a\u{30A2}a\u{30A2}",
"ECI(windows-31j),BYTE(Katakana:.a.a.a.a.a.)",
"ECI(shift_jis),BYTE(Katakana:.a.a.a.a.a.)",
None,
false,
);
@@ -1112,7 +1109,7 @@ fn testMinimalEncoder44() {
fn verifyMinimalEncoding(
input: &str,
expectedRXingResult: &str,
priorityCharset: Option<EncodingRef>,
priorityCharset: Option<CharacterSetECI>,
isGS1: bool,
) {
let result = MinimalEncoder::encode_with_details(
@@ -1198,7 +1195,7 @@ fn verifyNotGS1EncodedData(qrCode: &QRCode) {
fn shiftJISString(bytes: &[u8]) -> String {
SHIFT_JIS_CHARSET
.decode(bytes, encoding::DecoderTrap::Strict)
.decode(bytes)
.expect("decode should be ok")
// return new String(bytes, StringUtils.SHIFT_JIS_CHARSET);
}

View File

@@ -16,10 +16,8 @@
use std::{fmt, rc::Rc};
use encoding::EncodingRef;
use crate::{
common::{BitArray, ECIEncoderSet, Result},
common::{BitArray, ECIEncoderSet, Result, CharacterSetECI},
qrcode::decoder::{ErrorCorrectionLevel, Mode, Version, VersionRef},
Exceptions,
};
@@ -107,7 +105,7 @@ impl MinimalEncoder {
*/
pub fn new(
stringToEncode: &str,
priorityCharset: Option<EncodingRef>,
priorityCharset: Option<CharacterSetECI>,
isGS1: bool,
ecLevel: ErrorCorrectionLevel,
) -> Self {
@@ -142,7 +140,7 @@ impl MinimalEncoder {
pub fn encode_with_details(
stringToEncode: &str,
version: Option<VersionRef>,
priorityCharset: Option<EncodingRef>,
priorityCharset: Option<CharacterSetECI>,
isGS1: bool,
ecLevel: ErrorCorrectionLevel,
) -> Result<RXingResultList> {
@@ -1044,10 +1042,10 @@ impl fmt::Display for RXingResultNode {
result.push('(');
if self.mode == Mode::ECI {
result.push_str(
self.encoders
&self.encoders
.getCharset(self.charsetEncoderIndex)
.ok_or(fmt::Error)?
.name(),
.getCharsetName(),
);
} else {
let sub_string: String = self

View File

@@ -19,9 +19,6 @@
*/
use std::collections::HashMap;
use encoding::EncodingRef;
use once_cell::sync::Lazy;
use unicode_segmentation::UnicodeSegmentation;
use crate::{
@@ -35,8 +32,8 @@ use crate::{
use super::{mask_util, matrix_util, BlockPair, ByteMatrix, MinimalEncoder, QRCode};
static SHIFT_JIS_CHARSET: Lazy<EncodingRef> =
Lazy::new(|| encoding::label::encoding_from_whatwg_label("SJIS").unwrap());
static SHIFT_JIS_CHARSET: CharacterSetECI =
CharacterSetECI::SJIS;
// The original table is defined in the table 5 of JISX0510:2004 (p.19).
const ALPHANUMERIC_TABLE: [i8; 96] = [
@@ -48,7 +45,7 @@ const ALPHANUMERIC_TABLE: [i8; 96] = [
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f
];
pub const DEFAULT_BYTE_MODE_ENCODING: EncodingRef = encoding::all::ISO_8859_1;
pub const DEFAULT_BYTE_MODE_ENCODING: CharacterSetECI = CharacterSetECI::ISO8859_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.
@@ -101,7 +98,7 @@ pub fn encode_with_hints(
if has_encoding_hint {
if let Some(EncodeHintValue::CharacterSet(v)) = hints.get(&EncodeHintType::CHARACTER_SET) {
encoding =
Some(encoding::label::encoding_from_whatwg_label(v).ok_or(Exceptions::WRITER)?)
Some(CharacterSetECI::getCharacterSetECIByName(v).ok_or(Exceptions::WRITER)?)
}
}
@@ -126,12 +123,12 @@ pub fn encode_with_hints(
let encoding = if let Some(encoding) = encoding {
encoding
} else if let Ok(_encs) =
DEFAULT_BYTE_MODE_ENCODING.encode(content, encoding::EncoderTrap::Strict)
DEFAULT_BYTE_MODE_ENCODING.encode(content)
{
DEFAULT_BYTE_MODE_ENCODING
} else {
has_encoding_hint = true;
encoding::all::UTF_8
CharacterSetECI::UTF8
};
// Pick an encoding mode appropriate for the content. Note that this will not attempt to use
@@ -144,9 +141,7 @@ pub fn encode_with_hints(
// Append ECI segment if applicable
if mode == Mode::BYTE && has_encoding_hint {
if let Some(eci) = CharacterSetECI::getCharacterSetECI(encoding) {
appendECI(&eci, &mut header_bits)?;
}
appendECI(&encoding, &mut header_bits)?;
}
// Append the FNC1 mode header for GS1 formatted data if applicable
@@ -304,15 +299,15 @@ pub fn getAlphanumericCode(code: u32) -> i8 {
}
pub fn chooseMode(content: &str) -> Mode {
chooseModeWithEncoding(content, encoding::all::ISO_8859_1)
chooseModeWithEncoding(content, CharacterSetECI::ISO8859_1)
}
/**
* 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}.
*/
fn chooseModeWithEncoding(content: &str, encoding: EncodingRef) -> Mode {
if SHIFT_JIS_CHARSET.name() == encoding.name() && isOnlyDoubleByteKanji(content) {
fn chooseModeWithEncoding(content: &str, encoding: CharacterSetECI) -> Mode {
if SHIFT_JIS_CHARSET == encoding && isOnlyDoubleByteKanji(content) {
// Choose Kanji mode if all input are double-byte characters
return Mode::KANJI;
}
@@ -337,7 +332,7 @@ fn chooseModeWithEncoding(content: &str, encoding: EncodingRef) -> Mode {
}
pub fn isOnlyDoubleByteKanji(content: &str) -> bool {
let bytes = if let Ok(byt) = SHIFT_JIS_CHARSET.encode(content, encoding::EncoderTrap::Strict) {
let bytes = if let Ok(byt) = SHIFT_JIS_CHARSET.encode(content) {
byt
} else {
return false;
@@ -638,7 +633,7 @@ pub fn appendBytes(
content: &str,
mode: Mode,
bits: &mut BitArray,
encoding: EncodingRef,
encoding: CharacterSetECI,
) -> Result<()> {
match mode {
Mode::NUMERIC => appendNumericBytes(content, bits),
@@ -725,9 +720,9 @@ pub fn appendAlphanumericBytes(content: &str, bits: &mut BitArray) -> Result<()>
Ok(())
}
pub fn append8BitBytes(content: &str, bits: &mut BitArray, encoding: EncodingRef) -> Result<()> {
pub fn append8BitBytes(content: &str, bits: &mut BitArray, encoding: CharacterSetECI) -> Result<()> {
let bytes = encoding
.encode(content, encoding::EncoderTrap::Strict)
.encode(content)
.map_err(|e| Exceptions::writer_with(format!("error {e}")))?;
for b in bytes {
bits.appendBits(b as u32, 8)?;
@@ -739,7 +734,7 @@ pub fn appendKanjiBytes(content: &str, bits: &mut BitArray) -> Result<()> {
let sjis = &SHIFT_JIS_CHARSET;
let bytes = sjis
.encode(content, encoding::EncoderTrap::Strict)
.encode(content)
.map_err(|e| Exceptions::writer_with(format!("error {e}")))?;
if bytes.len() % 2 != 0 {
return Err(Exceptions::writer_with("Kanji byte size not even"));