// Copyright 2022 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.code_intelligence.jazzer.api.FuzzedDataProvider;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.*;

public class DataInputFuzzer {
  public static class MockFuzzDataInput implements DataInput
  {
    private final InputStream _input;

    public MockFuzzDataInput(byte[] data) {
        _input = new ByteArrayInputStream(data);
    }

    public MockFuzzDataInput(String utf8Data) throws IOException {
        _input = new ByteArrayInputStream(utf8Data.getBytes("UTF-8"));
    }

    public MockFuzzDataInput(InputStream in) {
        _input = in;
    }

    @Override
    public void readFully(byte[] b) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public void readFully(byte[] b, int off, int len) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public int skipBytes(int n) throws IOException {
        return (int) _input.skip(n);
    }

    @Override
    public boolean readBoolean() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public byte readByte() throws IOException {
        int ch = _input.read();
        if (ch < 0) {
            throw new EOFException("End-of-input for readByte()");
        }
        return (byte) ch;
    }

    @Override
    public int readUnsignedByte() throws IOException {
        return readByte() & 0xFF;
    }

    @Override
    public short readShort() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public int readUnsignedShort() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public char readChar() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public int readInt() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public long readLong() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public float readFloat() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public double readDouble() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public String readLine() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public String readUTF() throws IOException {
        throw new UnsupportedOperationException();
    }
  }


  public static void fuzzerTestOneInput(FuzzedDataProvider data) {
    JsonFactory jf = new JsonFactory();
    try {
      int typeOfNext = data.consumeInt();
      JsonParser jp = jf.createParser(new MockFuzzDataInput(data.consumeRemainingAsString()));
      switch (typeOfNext%4) {
      case 0:
        while (jp.nextToken() != null) {
              ;
        }
      case 1:
        while (jp.nextTextValue() != null) {
              ;
        }
      case 2:
        while (jp.nextBooleanValue() != null) {
              ;
        }
      case 3:
        while (jp.nextFieldName() != null) {
              ;
        }
      }      
    } catch (IOException ignored) {
    }
  }
}


@@ -852,29 +852,189 @@
 son.
-databind.ObjectMapper
+core.Base64Variants;%0Aimport com.fasterxml.jackson.databind.ObjectMapper;%0Aimport com.fasterxml.jackson.core.json.JsonReadFeature;%0Aimport com.fasterxml.jackson.core.JsonParser.Feature
 ;%0A%0Ai
@@ -3532,53 +3532,1100 @@
     
-JsonFactory jf = new JsonFactory();%0A    try %7B
+Feature%5B%5D features = new Feature%5B%5D%7B%0A        Feature.AUTO_CLOSE_SOURCE,%0A        Feature.ALLOW_COMMENTS,%0A        Feature.ALLOW_YAML_COMMENTS,%0A        Feature.ALLOW_UNQUOTED_FIELD_NAMES,%0A        Feature.ALLOW_SINGLE_QUOTES,%0A        Feature.ALLOW_UNQUOTED_CONTROL_CHARS,%0A        Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER,%0A        Feature.ALLOW_NUMERIC_LEADING_ZEROS,%0A        Feature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS,%0A        Feature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS,%0A        Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS,%0A        Feature.ALLOW_NON_NUMERIC_NUMBERS,%0A        Feature.ALLOW_MISSING_VALUES,%0A        Feature.ALLOW_TRAILING_COMMA,%0A        Feature.STRICT_DUPLICATE_DETECTION,%0A        Feature.IGNORE_UNDEFINED,%0A        Feature.INCLUDE_SOURCE_IN_LOCATION,%0A        Feature.USE_FAST_DOUBLE_PARSER,%0A    %7D;%0A    JsonFactory jf = new JsonFactory();%0A    try %7B%0A        for (int i = 0; i %3C features.length; i++) %7B%0A            if (data.consumeBoolean()) %7B%0A                jf.enable(features%5Bi%5D);%0A            %7D else %7B%0A                jf.disable(features%5Bi%5D);%0A            %7D%0A        %7D
 %0A   
@@ -4783,17 +4783,17 @@
 eOfNext%25
-4
+5
 ) %7B%0A    
@@ -5137,31 +5137,253 @@
     
-%7D      %0A    %7D catch (IO
+case 4:%0A        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();%0A        Base64Variants b64vs = new Base64Variants();%0A        jp.readBinaryValue(b64vs.MIME, outputStream);%0A      %7D      %0A    %7D catch (IOException %7C IllegalArgument
 Exce
@@ -5412,8 +5412,9 @@
 %0A  %7D%0A%7D%0A%0A
+%0A

improve DataInput fuzzer (#8162)