// Copyright 2021 Google LLC // // 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. // //////////////////////////////////////////////////////////////////////////////// import com.google.zxing.BarcodeFormat; import com.google.zxing.MultiFormatWriter; import com.google.zxing.MultiFormatReader; import com.google.zxing.aztec.encoder.AztecCode; import com.google.zxing.aztec.AztecReader; import com.google.zxing.datamatrix.DataMatrixReader; import com.google.zxing.maxicode.MaxiCodeReader; import com.google.zxing.oned.MultiFormatOneDReader; import com.google.zxing.pdf417.PDF417Reader; import com.google.zxing.qrcode.QRCodeReader; import com.google.zxing.oned.CodaBarReader; import com.google.zxing.oned.Code128Reader; import com.google.zxing.oned.Code39Reader; import com.google.zxing.oned.Code93Reader; import com.google.zxing.oned.EAN13Reader; import com.google.zxing.oned.EAN8Reader; import com.google.zxing.oned.ITFReader; import com.google.zxing.oned.UPCAReader; import com.google.zxing.oned.UPCEReader; import com.google.zxing.pdf417.PDF417Reader; import com.google.zxing.qrcode.QRCodeReader; import java.util.EnumMap; import java.util.Map; import javax.naming.NameNotFoundException; import com.google.zxing.Reader; import com.google.zxing.Binarizer; import com.google.zxing.BinaryBitmap; import com.google.zxing.WriterException; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.BitArray; import com.google.zxing.NotFoundException; import com.google.zxing.FormatException; import com.google.zxing.ChecksumException; import com.google.zxing.LuminanceSource; import com.google.zxing.Result; import com.google.zxing.pdf417.PDF417Writer; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.google.zxing.qrcode.decoder.Mode; import com.google.zxing.qrcode.encoder.QRCode; import com.google.zxing.datamatrix.encoder.HighLevelEncoder; import com.code_intelligence.jazzer.api.FuzzedDataProvider; public final class MultiFormatEncodeFuzzer { public static void fuzzerTestOneInput(FuzzedDataProvider data) { int width = data.consumeInt(100, 200); int height = data.consumeInt(100, 200); BarcodeFormat format = data.pickValue(BarcodeFormat.values()); String originalData = data.consumeRemainingAsAsciiString(); BitMatrix matrix; try { matrix = new MultiFormatWriter().encode(originalData, format, width, height); } catch (WriterException | IllegalArgumentException e) { return; } BinaryBitmap bitmap = null; Result result; try { bitmap = new BinaryBitmap(new TrivialBinarizer(matrix)); result = getReader(format).decode(bitmap); } catch (NotFoundException | ChecksumException | FormatException e) { throw new IllegalStateException("Failed to recover\n" + originalData + "\nencoded with " + format + " in " + width + "x" + height + "\n\n" + matrix.toString() + "\n\n" + bitmap.toString(), e); } String decodedData = result.getText(); if (!decodedData.equals(originalData)) { throw new IllegalStateException( "Failed to recover\n" + originalData + "\nencoded with " + format + " in " + width + "x" + height + ", got:\n" + decodedData + "\n\n" + matrix.toString() + "\n\n" + bitmap.toString()); } } private static Reader getReader(BarcodeFormat format) { switch (format) { case EAN_8: return new EAN8Reader(); case UPC_E: return new UPCEReader(); case EAN_13: return new EAN13Reader(); case UPC_A: return new UPCAReader(); case QR_CODE: return new QRCodeReader(); case CODE_39: return new Code39Reader(); case CODE_93: return new Code93Reader(); case CODE_128: return new Code128Reader(); case ITF: return new ITFReader(); case PDF_417: return new PDF417Reader(); case CODABAR: return new CodaBarReader(); case DATA_MATRIX: return new DataMatrixReader(); case AZTEC: return new AztecReader(); default: throw new IllegalArgumentException("No encoder available for format " + format); } } private static final class TrivialBinarizer extends Binarizer { private final BitMatrix matrix; public TrivialBinarizer(BitMatrix matrix) { super(new TrivialLuminanceSource(matrix)); this.matrix = matrix; } public BitArray getBlackRow(int y, BitArray row) throws NotFoundException { return matrix.getRow(y, row); } public BitMatrix getBlackMatrix() throws NotFoundException { return matrix; } public Binarizer createBinarizer(LuminanceSource source) { return new TrivialBinarizer(matrix); } } private static final class TrivialLuminanceSource extends LuminanceSource { private final BitMatrix matrix; public TrivialLuminanceSource(BitMatrix matrix) { super(matrix.getWidth(), matrix.getHeight()); this.matrix = matrix; } public byte[] getRow(int y, byte[] row) { if (row.length != matrix.getWidth()) { row = new byte[matrix.getWidth()]; } BitArray bitRow = matrix.getRow(y, null); for (int i = 0; i < matrix.getWidth(); i++) { if (bitRow.get(i)) { row[i] = 0; } else { row[i] = (byte) 255; } } return row; } public byte[] getMatrix() { byte[] bytes = new byte[matrix.getWidth() * matrix.getHeight()]; for (int x = 0; x < matrix.getWidth(); x++) { for (int y = 0; y < matrix.getHeight(); y++) { if (!matrix.get(x, y)) bytes[x + y * matrix.getWidth()] = (byte) 255; } } return bytes; } } }