1 // Copyright 2021 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 import com.google.zxing.BarcodeFormat; 18 import com.google.zxing.MultiFormatWriter; 19 import com.google.zxing.MultiFormatReader; 20 import com.google.zxing.aztec.encoder.AztecCode; 21 import com.google.zxing.aztec.AztecReader; 22 import com.google.zxing.datamatrix.DataMatrixReader; 23 import com.google.zxing.maxicode.MaxiCodeReader; 24 import com.google.zxing.oned.MultiFormatOneDReader; 25 import com.google.zxing.pdf417.PDF417Reader; 26 import com.google.zxing.qrcode.QRCodeReader; 27 import com.google.zxing.oned.CodaBarReader; 28 import com.google.zxing.oned.Code128Reader; 29 import com.google.zxing.oned.Code39Reader; 30 import com.google.zxing.oned.Code93Reader; 31 import com.google.zxing.oned.EAN13Reader; 32 import com.google.zxing.oned.EAN8Reader; 33 import com.google.zxing.oned.ITFReader; 34 import com.google.zxing.oned.UPCAReader; 35 import com.google.zxing.oned.UPCEReader; 36 import com.google.zxing.pdf417.PDF417Reader; 37 import com.google.zxing.qrcode.QRCodeReader; 38 39 import java.util.EnumMap; 40 import java.util.Map; 41 42 import javax.naming.NameNotFoundException; 43 44 import com.google.zxing.Reader; 45 import com.google.zxing.Binarizer; 46 import com.google.zxing.BinaryBitmap; 47 import com.google.zxing.WriterException; 48 import com.google.zxing.BarcodeFormat; 49 import com.google.zxing.EncodeHintType; 50 import com.google.zxing.common.BitMatrix; 51 import com.google.zxing.common.BitArray; 52 import com.google.zxing.NotFoundException; 53 import com.google.zxing.FormatException; 54 import com.google.zxing.ChecksumException; 55 import com.google.zxing.LuminanceSource; 56 import com.google.zxing.Result; 57 import com.google.zxing.pdf417.PDF417Writer; 58 59 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 60 import com.google.zxing.qrcode.decoder.Mode; 61 import com.google.zxing.qrcode.encoder.QRCode; 62 63 import com.google.zxing.datamatrix.encoder.HighLevelEncoder; 64 65 import com.code_intelligence.jazzer.api.FuzzedDataProvider; 66 67 public final class MultiFormatEncodeFuzzer { 68 fuzzerTestOneInput(FuzzedDataProvider data)69 public static void fuzzerTestOneInput(FuzzedDataProvider data) { 70 int width = data.consumeInt(100, 200); 71 int height = data.consumeInt(100, 200); 72 BarcodeFormat format = data.pickValue(BarcodeFormat.values()); 73 String originalData = data.consumeRemainingAsAsciiString(); 74 75 BitMatrix matrix; 76 try { 77 matrix = new MultiFormatWriter().encode(originalData, format, width, height); 78 } catch (WriterException | IllegalArgumentException e) { 79 return; 80 } 81 82 BinaryBitmap bitmap = null; 83 Result result; 84 try { 85 bitmap = new BinaryBitmap(new TrivialBinarizer(matrix)); 86 result = getReader(format).decode(bitmap); 87 } catch (NotFoundException | ChecksumException | FormatException e) { 88 throw new IllegalStateException("Failed to recover\n" + originalData + "\nencoded with " + format + " in " 89 + width + "x" + height + "\n\n" + matrix.toString() + "\n\n" + bitmap.toString(), e); 90 } 91 String decodedData = result.getText(); 92 if (!decodedData.equals(originalData)) { 93 throw new IllegalStateException( 94 "Failed to recover\n" + originalData + "\nencoded with " + format + " in " + width + "x" + height 95 + ", got:\n" + decodedData + "\n\n" + matrix.toString() + "\n\n" + bitmap.toString()); 96 } 97 } 98 getReader(BarcodeFormat format)99 private static Reader getReader(BarcodeFormat format) { 100 switch (format) { 101 case EAN_8: 102 return new EAN8Reader(); 103 case UPC_E: 104 return new UPCEReader(); 105 case EAN_13: 106 return new EAN13Reader(); 107 case UPC_A: 108 return new UPCAReader(); 109 case QR_CODE: 110 return new QRCodeReader(); 111 case CODE_39: 112 return new Code39Reader(); 113 case CODE_93: 114 return new Code93Reader(); 115 case CODE_128: 116 return new Code128Reader(); 117 case ITF: 118 return new ITFReader(); 119 case PDF_417: 120 return new PDF417Reader(); 121 case CODABAR: 122 return new CodaBarReader(); 123 case DATA_MATRIX: 124 return new DataMatrixReader(); 125 case AZTEC: 126 return new AztecReader(); 127 default: 128 throw new IllegalArgumentException("No encoder available for format " + format); 129 } 130 } 131 132 private static final class TrivialBinarizer extends Binarizer { 133 private final BitMatrix matrix; 134 TrivialBinarizer(BitMatrix matrix)135 public TrivialBinarizer(BitMatrix matrix) { 136 super(new TrivialLuminanceSource(matrix)); 137 this.matrix = matrix; 138 } 139 getBlackRow(int y, BitArray row)140 public BitArray getBlackRow(int y, BitArray row) throws NotFoundException { 141 return matrix.getRow(y, row); 142 } 143 getBlackMatrix()144 public BitMatrix getBlackMatrix() throws NotFoundException { 145 return matrix; 146 } 147 createBinarizer(LuminanceSource source)148 public Binarizer createBinarizer(LuminanceSource source) { 149 return new TrivialBinarizer(matrix); 150 } 151 } 152 153 private static final class TrivialLuminanceSource extends LuminanceSource { 154 private final BitMatrix matrix; 155 TrivialLuminanceSource(BitMatrix matrix)156 public TrivialLuminanceSource(BitMatrix matrix) { 157 super(matrix.getWidth(), matrix.getHeight()); 158 this.matrix = matrix; 159 } 160 getRow(int y, byte[] row)161 public byte[] getRow(int y, byte[] row) { 162 if (row.length != matrix.getWidth()) { 163 row = new byte[matrix.getWidth()]; 164 } 165 BitArray bitRow = matrix.getRow(y, null); 166 for (int i = 0; i < matrix.getWidth(); i++) { 167 if (bitRow.get(i)) { 168 row[i] = 0; 169 } else { 170 row[i] = (byte) 255; 171 } 172 } 173 return row; 174 } 175 getMatrix()176 public byte[] getMatrix() { 177 byte[] bytes = new byte[matrix.getWidth() * matrix.getHeight()]; 178 for (int x = 0; x < matrix.getWidth(); x++) { 179 for (int y = 0; y < matrix.getHeight(); y++) { 180 if (!matrix.get(x, y)) 181 bytes[x + y * matrix.getWidth()] = (byte) 255; 182 } 183 } 184 return bytes; 185 } 186 } 187 } 188