Skip to content

Commit 1cf9eaa

Browse files
authored
Support for platforms where SJIS is unavailable (#1747)
* Add support for embedded JREs where SJIS isn't available (cherry picked from commit 67896f9) * Add support for embedded JREs where EUC_JP isn't available (cherry picked from commit 979d3b6)
1 parent 956bbca commit 1cf9eaa

File tree

3 files changed

+50
-15
lines changed

3 files changed

+50
-15
lines changed

core/src/main/java/com/google/zxing/common/StringUtils.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,17 @@
3232
public final class StringUtils {
3333

3434
private static final Charset PLATFORM_DEFAULT_ENCODING = Charset.defaultCharset();
35-
public static final Charset SHIFT_JIS_CHARSET = Charset.forName("SJIS");
35+
public static final Charset SHIFT_JIS_CHARSET;
36+
static {
37+
Charset sjisCharset;
38+
try {
39+
sjisCharset = Charset.forName("SJIS");
40+
} catch (UnsupportedCharsetException ucee) {
41+
// Can happen on JREs without lib/charsets.jar
42+
sjisCharset = null;
43+
}
44+
SHIFT_JIS_CHARSET = sjisCharset;
45+
}
3646
public static final Charset GB2312_CHARSET;
3747
static {
3848
Charset gb2312Charset;
@@ -44,10 +54,20 @@ public final class StringUtils {
4454
}
4555
GB2312_CHARSET = gb2312Charset;
4656
}
47-
private static final Charset EUC_JP = Charset.forName("EUC_JP");
57+
private static final Charset EUC_JP;
58+
static {
59+
Charset eucJpCharset;
60+
try {
61+
eucJpCharset = Charset.forName("EUC_JP");
62+
} catch (UnsupportedCharsetException ucee) {
63+
// Can happen on JREs without lib/charsets.jar
64+
eucJpCharset = null;
65+
}
66+
EUC_JP = eucJpCharset;
67+
}
4868
private static final boolean ASSUME_SHIFT_JIS =
49-
SHIFT_JIS_CHARSET.equals(PLATFORM_DEFAULT_ENCODING) ||
50-
EUC_JP.equals(PLATFORM_DEFAULT_ENCODING);
69+
(SHIFT_JIS_CHARSET != null && SHIFT_JIS_CHARSET.equals(PLATFORM_DEFAULT_ENCODING)) ||
70+
(EUC_JP != null && EUC_JP.equals(PLATFORM_DEFAULT_ENCODING));
5171

5272
// Retained for ABI compatibility with earlier versions
5373
public static final String SHIFT_JIS = "SJIS";
@@ -101,7 +121,7 @@ public static Charset guessCharset(byte[] bytes, Map<DecodeHintType,?> hints) {
101121
// which should be by far the most common encodings.
102122
int length = bytes.length;
103123
boolean canBeISO88591 = true;
104-
boolean canBeShiftJIS = true;
124+
boolean canBeShiftJIS = SHIFT_JIS_CHARSET != null;
105125
boolean canBeUTF8 = true;
106126
int utf8BytesLeft = 0;
107127
int utf2BytesChars = 0;

core/src/main/java/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ private static void decodeHanziSegment(BitSource bits,
211211
private static void decodeKanjiSegment(BitSource bits,
212212
StringBuilder result,
213213
int count) throws FormatException {
214+
if (StringUtils.SHIFT_JIS_CHARSET == null) {
215+
// Not supported without charset support
216+
throw FormatException.getFormatInstance();
217+
}
214218
// Don't crash trying to read more bits than we have available.
215219
if (count * 13 > bits.available()) {
216220
throw FormatException.getFormatInstance();

core/src/main/java/com/google/zxing/qrcode/encoder/Encoder.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import java.nio.charset.Charset;
3131
import java.nio.charset.StandardCharsets;
32+
import java.nio.charset.UnsupportedCharsetException;
3233
import java.util.ArrayList;
3334
import java.util.Collection;
3435
import java.util.Map;
@@ -91,7 +92,11 @@ public static QRCode encode(String content,
9192
Charset encoding = DEFAULT_BYTE_MODE_ENCODING;
9293
boolean hasEncodingHint = hints != null && hints.containsKey(EncodeHintType.CHARACTER_SET);
9394
if (hasEncodingHint) {
94-
encoding = Charset.forName(hints.get(EncodeHintType.CHARACTER_SET).toString());
95+
try {
96+
encoding = Charset.forName(hints.get(EncodeHintType.CHARACTER_SET).toString());
97+
} catch (UnsupportedCharsetException ignore) {
98+
//ignore the encodingHint and use the DEFAULT_BYTE_MODE_ENCODING
99+
}
95100
}
96101

97102
if (hasCompactionHint) {
@@ -105,37 +110,37 @@ public static QRCode encode(String content,
105110
version = rn.getVersion();
106111

107112
} else {
108-
113+
109114
// Pick an encoding mode appropriate for the content. Note that this will not attempt to use
110115
// multiple modes / segments even if that were more efficient.
111116
mode = chooseMode(content, encoding);
112-
117+
113118
// This will store the header information, like mode and
114119
// length, as well as "header" segments like an ECI segment.
115120
BitArray headerBits = new BitArray();
116-
121+
117122
// Append ECI segment if applicable
118123
if (mode == Mode.BYTE && hasEncodingHint) {
119124
CharacterSetECI eci = CharacterSetECI.getCharacterSetECI(encoding);
120125
if (eci != null) {
121126
appendECI(eci, headerBits);
122127
}
123128
}
124-
129+
125130
// Append the FNC1 mode header for GS1 formatted data if applicable
126131
if (hasGS1FormatHint) {
127132
// GS1 formatted codes are prefixed with a FNC1 in first position mode header
128133
appendModeInfo(Mode.FNC1_FIRST_POSITION, headerBits);
129134
}
130-
135+
131136
// (With ECI in place,) Write the mode marker
132137
appendModeInfo(mode, headerBits);
133-
138+
134139
// Collect data within the main segment, separately, to count its size if needed. Don't add it to
135140
// main payload yet.
136141
BitArray dataBits = new BitArray();
137142
appendBytes(content, mode, dataBits, encoding);
138-
143+
139144
if (hints != null && hints.containsKey(EncodeHintType.QR_VERSION)) {
140145
int versionNumber = Integer.parseInt(hints.get(EncodeHintType.QR_VERSION).toString());
141146
version = Version.getVersionForNumber(versionNumber);
@@ -146,7 +151,7 @@ public static QRCode encode(String content,
146151
} else {
147152
version = recommendVersion(ecLevel, mode, headerBits, dataBits);
148153
}
149-
154+
150155
headerAndDataBits = new BitArray();
151156
headerAndDataBits.appendBitArray(headerBits);
152157
// Find "length" of main segment and write it
@@ -244,7 +249,9 @@ public static Mode chooseMode(String content) {
244249
* if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}.
245250
*/
246251
private static Mode chooseMode(String content, Charset encoding) {
247-
if (StringUtils.SHIFT_JIS_CHARSET.equals(encoding) && isOnlyDoubleByteKanji(content)) {
252+
if (StringUtils.SHIFT_JIS_CHARSET != null &&
253+
StringUtils.SHIFT_JIS_CHARSET.equals(encoding) &&
254+
isOnlyDoubleByteKanji(content)) {
248255
// Choose Kanji mode if all input are double-byte characters
249256
return Mode.KANJI;
250257
}
@@ -605,6 +612,10 @@ static void append8BitBytes(String content, BitArray bits, Charset encoding) {
605612
}
606613

607614
static void appendKanjiBytes(String content, BitArray bits) throws WriterException {
615+
if (StringUtils.SHIFT_JIS_CHARSET == null) {
616+
// Not supported without charset support
617+
throw new WriterException("SJIS Charset not supported on this platform");
618+
}
608619
byte[] bytes = content.getBytes(StringUtils.SHIFT_JIS_CHARSET);
609620
if (bytes.length % 2 != 0) {
610621
throw new WriterException("Kanji byte size not even");

0 commit comments

Comments
 (0)