Wrote a new ByteArray class to replace StringPiece and fixed all uses of it. Also converted all uses of stl::string (which was being used as vector<unsigned char>) to ByteArray. Everything in the Encoder but the Reed Solomon related code compiles now.

ByteArray could certainly move up to the common package, although it currently has a dependency on BitVector. We'll have to figure out what to do with the latter first.

This is the first set of changes I've made which are error prone. They involved a lot of pointer conversion, signed/unsigned semantics, etc. These diffs may have clues for later bugs.

git-svn-id: https://zxing.googlecode.com/svn/trunk@705 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
dswitkin 2008-11-14 21:51:26 +00:00
parent fabdd40edf
commit aea12b5286
5 changed files with 236 additions and 159 deletions

View file

@ -95,15 +95,6 @@ public final class BitVector {
}
}
// Append "bytes".
//
// JAVAPORT: Uncomment and implement when a substitute for StringPiece is chosen.
// public void AppendBytes(final StringPiece stringPiece) {
// for (int i = 0; i < stringPiece.size(); ++i) {
// AppendBits(stringPiece[i], 8);
// }
// }
// Append "bits".
public void AppendBitVector(final BitVector bits) {
int size = bits.size();

View file

@ -0,0 +1,91 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.encoder;
/**
* This class implements an array of unsigned bytes.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ByteArray {
private static final int INITIAL_SIZE = 32;
private byte[] bytes;
private int size;
public ByteArray() {
bytes = null;
size = 0;
}
public ByteArray(String string) {
bytes = string.getBytes();
size = bytes.length;
}
public ByteArray(byte[] byteArray) {
bytes = byteArray;
size = bytes.length;
}
/**
* Access an unsigned byte at location index.
* @param index The index in the array to access.
* @return The unsigned value of the byte as an int.
*/
public int at(int index) {
return bytes[index] & 0xff;
}
public int size() {
return size;
}
public boolean empty() {
return size == 0;
}
public void appendByte(int value) {
if (size == 0 || size >= bytes.length) {
int newSize = Math.max(INITIAL_SIZE, size * 2);
reserve(newSize);
}
bytes[size] = (byte) value;
size++;
}
public void reserve(int capacity) {
if (bytes == null || bytes.length < capacity) {
byte[] newArray = new byte[capacity];
if (bytes != null) {
System.arraycopy(bytes, 0, newArray, 0, bytes.length);
}
bytes = newArray;
}
}
// This could probably be generalized to take a byte[] instead of a BitVector.
public void set(BitVector bits, int offset, int count) {
bytes = new byte[count];
size = count;
for (int x = 0; x < count; x++) {
bytes[x] = (byte) bits.at(x + offset);
}
}
}

View file

@ -16,8 +16,9 @@
package com.google.zxing.qrcode.encoder;
import java.util.Vector;
// class GF_Poly;
// #include "strings/stringpiece.h"
// #include "util/reedsolomon/galois_field.h"
// #include "util/reedsolomon/galois_poly.h"
@ -280,18 +281,35 @@ private static final ECPolyInfo kECPolynomials[] = {
private static final int kFieldSize = 8;
private static GF_Poly[] g_ec_polynomials = new GF_Poly[kMaxNumECBytes + 1];
// Encode "bytes" with the error correction level "ec_level". The
// encoding mode will be chosen internally by ChooseMode().
// On success, store the result in "qr_code" and return true. On
// error, return false. We recommend you to use QRCode.EC_LEVEL_L
// (the lowest level) for "ec_level" since our primary use is to
// show QR code on desktop screens. We don't need very strong error
// correction for this purpose.
private static final class BlockPair {
private ByteArray dataBytes;
private ByteArray errorCorrectionBytes;
public BlockPair(ByteArray data, ByteArray errorCorrection) {
dataBytes = data;
errorCorrectionBytes = errorCorrection;
}
public ByteArray getDataBytes() {
return dataBytes;
}
public ByteArray getErrorCorrectionBytes() {
return errorCorrectionBytes;
}
}
// Encode "bytes" with the error correction level "ec_level". The encoding mode will be chosen
// internally by ChooseMode(). On success, store the result in "qr_code" and return true. On
// error, return false. We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for
// "ec_level" since our primary use is to show QR code on desktop screens. We don't need very
// strong error correction for this purpose.
//
// Note that there is no way to encode bytes in MODE_KANJI. We might
// want to add EncodeWithMode() with which clients can specify the
// encoding mode. For now, we don't need the functionality.
public static boolean Encode(final StringPiece bytes, int ec_level, QRCode qr_code) {
// Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode()
// with which clients can specify the encoding mode. For now, we don't need the functionality.
public static boolean Encode(final ByteArray bytes, int ec_level, QRCode qr_code) {
// Step 1: Choose the mode (encoding).
final int mode = ChooseMode(bytes);
@ -311,8 +329,7 @@ private static final ECPolyInfo kECPolynomials[] = {
if (!AppendModeInfo(qr_code.mode(), header_and_data_bits)) {
return false;
}
if (!AppendLengthInfo(bytes.size(), qr_code.version(), qr_code.mode(),
header_and_data_bits)) {
if (!AppendLengthInfo(bytes.size(), qr_code.version(), qr_code.mode(), header_and_data_bits)) {
return false;
}
header_and_data_bits.AppendBitVector(data_bits);
@ -324,17 +341,12 @@ private static final ECPolyInfo kECPolynomials[] = {
// Step 6: Interleave data bits with error correction code.
BitVector final_bits = new BitVector();
InterleaveWithECBytes(header_and_data_bits,
qr_code.num_total_bytes(),
qr_code.num_data_bytes(),
qr_code.num_rs_blocks(),
final_bits);
InterleaveWithECBytes(header_and_data_bits, qr_code.num_total_bytes(), qr_code.num_data_bytes(),
qr_code.num_rs_blocks(), final_bits);
// Step 7: Choose the mask pattern and set to "qr_code".
Matrix matrix = new Matrix(qr_code.matrix_width(), qr_code.matrix_width());
qr_code.set_mask_pattern(ChooseMaskPattern(final_bits,
qr_code.ec_level(),
qr_code.version(),
qr_code.set_mask_pattern(ChooseMaskPattern(final_bits, qr_code.ec_level(), qr_code.version(),
matrix));
if (qr_code.mask_pattern() == -1) {
// There was an error.
@ -342,14 +354,12 @@ private static final ECPolyInfo kECPolynomials[] = {
}
// Step 8. Build the matrix and set it to "qr_code".
MatrixUtil.BuildMatrix(final_bits,
qr_code.ec_level(),
qr_code.version(),
MatrixUtil.BuildMatrix(final_bits, qr_code.ec_level(), qr_code.version(),
qr_code.mask_pattern(), matrix);
qr_code.set_matrix(matrix);
// Step 9. Make sure we have a valid QR Code.
if (!qr_code.IsValid()) {
Debug.LOG_ERROR("Invalid QR code: " + qr_code.DebugString());
Debug.LOG_ERROR("Invalid QR code: " + qr_code.toString());
return false;
}
return true;
@ -364,22 +374,23 @@ private static final ECPolyInfo kECPolynomials[] = {
return -1;
}
// Choose the best mode from the content of "bytes".
// The function is guaranteed to return valid mode.
// Choose the best mode by examining the content of "bytes". The function is guaranteed to return
// a valid mode.
//
// Note that the function does not return MODE_KANJI, as we cannot
// distinguish Shift_JIS from other encodings such as ISO-8859-1, from
// data bytes alone. For example "\xE0\xE0" can be interpreted as one
// character in Shift_JIS, but also two characters in ISO-8859-1.
public static int ChooseMode(final StringPiece bytes) {
// Note that this function does not return MODE_KANJI, as we cannot distinguish Shift_JIS from
// other encodings such as ISO-8859-1, from data bytes alone. For example "\xE0\xE0" can be
// interpreted as one character in Shift_JIS, but also two characters in ISO-8859-1.
//
// JAVAPORT: This MODE_KANJI limitation sounds like a problem for us.
public static int ChooseMode(final ByteArray bytes) {
boolean has_numeric = false;
boolean has_alphanumeric = false;
boolean has_other = false;
for (int i = 0; i < bytes.size(); ++i) {
final int byte = bytes[i];
if (byte >= '0' && byte <= '9') {
final int oneByte = bytes.at(i);
if (oneByte >= '0' && oneByte <= '9') {
has_numeric = true;
} else if (GetAlphanumericCode(byte) != -1) {
} else if (GetAlphanumericCode(oneByte) != -1) {
has_alphanumeric = true;
} else {
has_other = true;
@ -445,9 +456,8 @@ private static final ECPolyInfo kECPolynomials[] = {
final int num_rs_blocks = row.block_info[ec_level][1];
// num_data_bytes = 196 - 130 = 66
final int num_data_bytes = num_bytes - num_ec_bytes;
// We want to choose the smallest version which can contain data
// of "num_input_bytes" + some extra bits for the header (mode
// info and length info). The header can be three bytes
// We want to choose the smallest version which can contain data of "num_input_bytes" + some
// extra bits for the header (mode info and length info). The header can be three bytes
// (precisely 4 + 16 bits) at most. Hence we do +3 here.
if (num_data_bytes >= num_input_bytes + 3) {
// Yay, we found the proper rs block info!
@ -546,50 +556,40 @@ private static final ECPolyInfo kECPolynomials[] = {
}
}
// Interleave "bits" with corresponding error correction bytes. On
// success, store the result in "result" and return true. On error,
// return false.
// The interleave rule is complicated. See 8.6 of JISX0510:2004
// (p.37) for details.
static boolean InterleaveWithECBytes(final BitVector bits,
int num_total_bytes,
int num_data_bytes,
int num_rc_blocks,
BitVector result) {
// Interleave "bits" with corresponding error correction bytes. On success, store the result in
// "result" and return true. On error, return false. The interleave rule is complicated. See 8.6
// of JISX0510:2004 (p.37) for details.
static boolean InterleaveWithECBytes(final BitVector bits, int num_total_bytes,
int num_data_bytes, int num_rs_blocks, BitVector result) {
// "bits" must have "num_data_bytes" bytes of data.
Debug.DCHECK(bits.num_bytes() == num_data_bytes);
// Step 1. Divide data bytes into blocks and generate error
// correction bytes for them. We'll store the divided data bytes
// blocks and error correction bytes blocks into "blocks".
typedef pair<StringPiece, String> BlockPair;
// Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
// store the divided data bytes blocks and error correction bytes blocks into "blocks".
int data_bytes_offset = 0;
// JAVAPORT: This is not a String, it's really a byte[]
final String &encoded_bytes = bits.ToString();
int max_num_data_bytes = 0; // StringPiece's size is "int".
size_t max_num_ec_bytes = 0; // STL String's size is "size_t".
vector<BlockPair> blocks;
// Since, we know the number of reedsolmon blocks, we can initialize
// the vector with the number.
blocks.resize(num_rs_blocks);
int max_num_data_bytes = 0;
int max_num_ec_bytes = 0;
// Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
Vector<BlockPair> blocks = new Vector<BlockPair>(num_rs_blocks);
for (int i = 0; i < num_rs_blocks; ++i) {
int num_data_bytes_in_block, num_ec_bytes_in_block;
Integer num_data_bytes_in_block = new Integer(0);
Integer num_ec_bytes_in_block = new Integer(0);
GetNumDataBytesAndNumECBytesForBlockID(
num_total_bytes, num_data_bytes, num_rs_blocks, i,
&num_data_bytes_in_block, &num_ec_bytes_in_block);
// We modify the objects in the vector instead of copying new
// objects to the vector. In particular, we want to avoid String
// copies.
StringPiece *data_bytes = &(blocks[i].first);
String *ec_bytes = &(blocks[i].second);
num_data_bytes_in_block, num_ec_bytes_in_block);
data_bytes.set(encoded_bytes.data() + data_bytes_offset,
num_data_bytes_in_block);
GenerateECBytes(*data_bytes, num_ec_bytes_in_block, ec_bytes);
ByteArray data_bytes = new ByteArray();
ByteArray ec_bytes = new ByteArray();
blocks.addElement(new BlockPair(data_bytes, ec_bytes));
max_num_data_bytes = max(max_num_data_bytes, data_bytes.size());
max_num_ec_bytes = max(max_num_ec_bytes, ec_bytes.size());
data_bytes.set(bits, data_bytes_offset, num_data_bytes_in_block);
GenerateECBytes(data_bytes, num_ec_bytes_in_block, ec_bytes);
max_num_data_bytes = Math.max(max_num_data_bytes, data_bytes.size());
max_num_ec_bytes = Math.max(max_num_ec_bytes, ec_bytes.size());
data_bytes_offset += num_data_bytes_in_block;
}
Debug.DCHECK_EQ(num_data_bytes, data_bytes_offset);
@ -597,18 +597,18 @@ private static final ECPolyInfo kECPolynomials[] = {
// First, place data blocks.
for (int i = 0; i < max_num_data_bytes; ++i) {
for (int j = 0; j < blocks.size(); ++j) {
final StringPiece &data_bytes = blocks[j].first;
final ByteArray data_bytes = blocks.elementAt(j).getDataBytes();
if (i < data_bytes.size()) {
result.AppendBits(data_bytes[i], 8);
result.AppendBits(data_bytes.at(i), 8);
}
}
}
// Then, place error correction blocks.
for (int i = 0; i < max_num_ec_bytes; ++i) {
for (int j = 0; j < blocks.size(); ++j) {
final String &ec_bytes = blocks[j].second;
final ByteArray ec_bytes = blocks.elementAt(j).getErrorCorrectionBytes();
if (i < ec_bytes.size()) {
result.AppendBits(ec_bytes[i], 8);
result.AppendBits(ec_bytes.at(i), 8);
}
}
}
@ -620,8 +620,8 @@ private static final ECPolyInfo kECPolynomials[] = {
return false;
}
// Append mode info. On success, store the result in "bits" and
// return true. On error, return false.
// Append mode info. On success, store the result in "bits" and return true. On error, return
// false.
static boolean AppendModeInfo(int mode, BitVector bits) {
final int code = QRCode.GetModeCode(mode);
if (code == -1) {
@ -633,8 +633,8 @@ private static final ECPolyInfo kECPolynomials[] = {
}
// Append length info. On success, store the result in "bits" and
// return true. On error, return false.
// Append length info. On success, store the result in "bits" and return true. On error, return
// false.
static boolean AppendLengthInfo(int num_bytes, int version, int mode, BitVector bits) {
int num_letters = num_bytes;
// In Kanji mode, a letter is represented in two bytes.
@ -658,7 +658,7 @@ private static final ECPolyInfo kECPolynomials[] = {
// Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits"
// and return true. On error, return false.
static boolean AppendBytes(final StringPiece bytes, int mode, BitVector bits) {
static boolean AppendBytes(final ByteArray bytes, int mode, BitVector bits) {
switch (mode) {
case QRCode.MODE_NUMERIC:
return AppendNumericBytes(bytes, bits);
@ -677,24 +677,25 @@ private static final ECPolyInfo kECPolynomials[] = {
// Append "bytes" to "bits" using QRCode.MODE_NUMERIC mode. On success, store the result in "bits"
// and return true. On error, return false.
static boolean AppendNumericBytes(final StringPiece bytes, BitVector bits) {
static boolean AppendNumericBytes(final ByteArray bytes, BitVector bits) {
// Validate all the bytes first.
for (int i = 0; i < bytes.size(); ++i) {
if (!isdigit(bytes[i])) {
int oneByte = bytes.at(i);
if (oneByte < '0' || oneByte > '9') {
return false;
}
}
for (int i = 0; i < bytes.size();) {
final int num1 = bytes[i] - '0';
final int num1 = bytes.at(i) - '0';
if (i + 2 < bytes.size()) {
// Encode three numeric letters in ten bits.
final int num2 = bytes[i + 1] - '0';
final int num3 = bytes[i + 2] - '0';
final int num2 = bytes.at(i + 1) - '0';
final int num3 = bytes.at(i + 2) - '0';
bits.AppendBits(num1 * 100 + num2 * 10 + num3, 10);
i += 3;
} else if (i + 1 < bytes.size()) {
// Encode two numeric letters in seven bits.
final int num2 = bytes[i + 1] - '0';
final int num2 = bytes.at(i + 1) - '0';
bits.AppendBits(num1 * 10 + num2, 7);
i += 2;
} else {
@ -706,17 +707,16 @@ private static final ECPolyInfo kECPolynomials[] = {
return true;
}
// Append "bytes" to "bits" using QRCode.MODE_ALPHANUMERIC mode.
// On success, store the result in "bits" and return true. On error,
// return false.
static boolean AppendAlphanumericBytes(final StringPiece bytes, BitVector bits) {
// Append "bytes" to "bits" using QRCode.MODE_ALPHANUMERIC mode. On success, store the result in
// "bits" and return true. On error, return false.
static boolean AppendAlphanumericBytes(final ByteArray bytes, BitVector bits) {
for (int i = 0; i < bytes.size();) {
final int code1 = GetAlphanumericCode(bytes[i]);
final int code1 = GetAlphanumericCode(bytes.at(i));
if (code1 == -1) {
return false;
}
if (i + 1 < bytes.size()) {
final int code2 = GetAlphanumericCode(bytes[i + 1]);
final int code2 = GetAlphanumericCode(bytes.at(i + 1));
if (code2 == -1) {
return false;
}
@ -732,28 +732,26 @@ private static final ECPolyInfo kECPolynomials[] = {
return true;
}
// Append "bytes" to "bits" using QRCode.MODE_8BIT_BYTE mode.
// On success, store the result in "bits" and return true. On error,
// return false.
static boolean Append8BitBytes(final StringPiece bytes, BitVector bits) {
// Append "bytes" to "bits" using QRCode.MODE_8BIT_BYTE mode. On success, store the result in
// "bits" and return true. On error, return false.
static boolean Append8BitBytes(final ByteArray bytes, BitVector bits) {
for (int i = 0; i < bytes.size(); ++i) {
bits.AppendBits(bytes[i], 8);
bits.AppendBits(bytes.at(i), 8);
}
return true;
}
// Append "bytes" to "bits" using QRCode.MODE_KANJI mode.
// On success, store the result in "bits" and return true. On error,
// return false.
// See 8.4.5 of JISX0510:2004 (p.21) for how to encode Kanji bytes.
static boolean AppendKanjiBytes(final StringPiece bytes, BitVector bits) {
// Append "bytes" to "bits" using QRCode.MODE_KANJI mode. On success, store the result in "bits"
// and return true. On error, return false. See 8.4.5 of JISX0510:2004 (p.21) for how to encode
// Kanji bytes.
static boolean AppendKanjiBytes(final ByteArray bytes, BitVector bits) {
if (bytes.size() % 2 != 0) {
Debug.LOG_ERROR("Invalid byte sequence: " + bytes);
return false;
}
for (int i = 0; i < bytes.size(); i += 2) {
Debug.DCHECK(IsValidKanji(bytes[i], bytes[i + 1]));
final int code = (static_cast<int>(bytes[i]) << 8 | bytes[i + 1]);
Debug.DCHECK(IsValidKanji(bytes.at(i), bytes.at(i + 1)));
final int code = (bytes.at(i) << 8) | bytes.at(i + 1);
int subtracted = -1;
if (code >= 0x8140 && code <= 0x9ffc) {
subtracted = code - 0x8140;
@ -777,32 +775,31 @@ private static final ECPolyInfo kECPolynomials[] = {
// Initialize "g_ec_polynomials" with numbers in kECPolynomials.
private static void InitECPolynomials() {
final GaloisField &field = GaloisField.GetField(kFieldSize);
for (int i = 0; i < arraysize(kECPolynomials); ++i) {
final ECPolyInfo& ec_poly_info = kECPolynomials[i];
final GaloisField field = GaloisField.GetField(kFieldSize);
for (int i = 0; i < kECPolynomials.length; ++i) {
final ECPolyInfo ec_poly_info = kECPolynomials[i];
final int ec_length = ec_poly_info.ec_length;
vector<GF_Element> *coeffs = new vector<GF_Element>;
// The number of coefficients is one more than "ec_length".
// That's why the termination condition is <= instead of <.
// The number of coefficients is one more than "ec_length". That's why the termination
// condition is <= instead of <.
for (int j = 0; j <= ec_length; ++j) {
// We need exp'ed numbers for later use.
final int coeff = field.Exp(ec_poly_info.coeffs[j]);
coeffs.push_back(coeff);
}
// Reverse the coefficients since the numbers in kECPolynomials
// are ordered in reverse order to the order GF_Poly expects.
// Reverse the coefficients since the numbers in kECPolynomials are ordered in reverse order
// to the order GF_Poly expects.
reverse(coeffs.begin(), coeffs.end());
GF_Poly *ec_poly = new GF_Poly(coeffs, GaloisField.GetField(kFieldSize));
GF_Poly ec_poly = new GF_Poly(coeffs, GaloisField.GetField(kFieldSize));
g_ec_polynomials[ec_length] = ec_poly;
}
}
// Get error correction polynomials. The polynomials are
// defined in Appendix A of JISX0510 2004 (p. 59). In the appendix,
// they use exponential notations for the polynomials. We need to
// apply GaloisField.Log() to all coefficients generated by the
// function to compare numbers with the ones in the appendix.
// Get error correction polynomials. The polynomials are defined in Appendix A of JISX0510 2004
// (p. 59). In the appendix, they use exponential notations for the polynomials. We need to apply
// GaloisField.Log() to all coefficients generated by the function to compare numbers with the
// ones in the appendix.
//
// Example:
// - Input: 17
@ -822,9 +819,8 @@ private static final ECPolyInfo kECPolynomials[] = {
// Example:
// - Input: {32,65,205,69,41,220,46,128,236}, ec_length = 17
// - Output: {42,159,74,221,244,169,239,150,138,70,237,85,224,96,74,219,61}
private static void GenerateECBytes(final StringPiece data_bytes, int ec_length, String ec_bytes) {
// First, fill the vector with "ec_length" copies of 0.
// They are low-order zero coefficients.
private static void GenerateECBytes(final ByteArray data_bytes, int ec_length, ByteArray ec_bytes) {
// First, fill the vector with "ec_length" copies of 0. They are low-order zero coefficients.
vector<GF_Element> *coeffs = new vector<GF_Element>(ec_length, 0);
// Then copy data_bytes backward.
copy(data_bytes.rbegin(), data_bytes.rend(), back_inserter(*coeffs));
@ -835,27 +831,25 @@ private static final ECPolyInfo kECPolynomials[] = {
final GF_Poly &ec_poly = GetECPoly(ec_length);
pair<GF_Poly*, GF_Poly*> divrem = GF_Poly.DivRem(data_poly, ec_poly);
// Basically, the coefficients in the remainder polynomial are the
// error correction bytes.
// Basically, the coefficients in the remainder polynomial are the error correction bytes.
GF_Poly *remainder = divrem.second;
ec_bytes.reserve(ec_length);
// However, high-order zero cofficients in the remainder polynomial
// are ommited. We should add zero by ourselvs.
// However, high-order zero cofficients in the remainder polynomial are ommited. We should add
// zero by ourselvs.
final int num_pruned_zero_coeffs = ec_length - (remainder.degree() + 1);
for (int i = 0; i < num_pruned_zero_coeffs; ++i) {
ec_bytes.push_back(0);
ec_bytes.appendByte(0);
}
// Copy the remainder numbers to "ec_bytes".
for (int i = remainder.degree(); i >= 0; --i) {
ec_bytes.push_back(remainder.coeff(i));
ec_bytes.appendByte(remainder.coeff(i));
}
Debug.DCHECK_EQ(ec_length, ec_bytes.size());
}
// Check if "byte1" and "byte2" can compose a valid Kanji letter
// (2-byte Shift_JIS letter).
// The numbers are from http://ja.wikipedia.org/wiki/Shift_JIS.
private static boolean IsValidKanji(final char byte1, final char byte2) {
// Check if "byte1" and "byte2" can compose a valid Kanji letter (2-byte Shift_JIS letter). The
// numbers are from http://ja.wikipedia.org/wiki/Shift_JIS.
private static boolean IsValidKanji(final int byte1, final int byte2) {
return (byte2 != 0x7f &&
((byte1 >= 0x81 && byte1 <= 0x9f &&
byte2 >= 0x40 && byte2 <= 0xfc) ||
@ -864,13 +858,15 @@ private static final ECPolyInfo kECPolynomials[] = {
}
// Check if "bytes" is a valid Kanji sequence.
private static boolean IsValidKanjiSequence(final StringPiece bytes) {
//
// JAVAPORT - Remove if not used by the unit tests.
private static boolean IsValidKanjiSequence(final ByteArray bytes) {
if (bytes.size() % 2 != 0) {
return false;
}
int i = 0;
for (; i < bytes.size(); i += 2) {
if (!IsValidKanji(bytes[i], bytes[i + 1])) {
if (!IsValidKanji(bytes.at(i), bytes.at(i + 1))) {
break;
}
}

View file

@ -161,7 +161,7 @@ public final class QRCode {
}
// Return debug String.
public String DebugString() {
public String toString() {
StringBuffer result = new StringBuffer();
result.append("<<QRCode\n");
result.append(" mode: ");

View file

@ -16,7 +16,6 @@
package com.google.zxing.qrcode.encoder;
//class StringPiece;
// #include "third_party/png/png.h"
/**
@ -119,7 +118,7 @@ public final class Renderer {
// Similar to RenderAsPNG but it renders QR code from data in
// "bytes" with error correction level "ec_level". This is the
// friendliest function in the QR code library.
public static boolean RenderAsPNGFromData(final StringPiece& bytes, int ec_level, int cell_size,
public static boolean RenderAsPNGFromData(final ByteArray& bytes, int ec_level, int cell_size,
String *result) {
QRCode qr_code;
if (!Encoder.Encode(bytes, ec_level, &qr_code)) {