<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.geronimo.mail.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.FilterInputStream;

/**
 * An implementation of a FilterInputStream that decodes the
 * stream data in BASE64 encoding format.  This version does the
 * decoding "on the fly" rather than decoding a single block of
 * data.  Since this version is intended for use by the MimeUtilty class,
 * it also handles line breaks in the encoded data.
 */
public class Base64DecoderStream extends FilterInputStream {

    static protected final String MAIL_BASE64_IGNOREERRORS = "mail.mime.base64.ignoreerrors";

    // number of decodeable units we'll try to process at one time.  We'll attempt to read that much
    // data from the input stream and decode in blocks.
    static protected final int BUFFERED_UNITS = 2000;

    // our decoder for processing the data
    protected Base64Encoder decoder = new Base64Encoder();

    // can be overridden by a system property.
    protected boolean ignoreErrors = false;

    // buffer for reading in chars for decoding (which can support larger bulk reads)
    protected byte[] encodedChars = new byte[BUFFERED_UNITS * 4];
    // a buffer for one decoding unit's worth of data (3 bytes).  This is the minimum amount we
    // can read at one time.
    protected byte[] decodedChars = new byte[BUFFERED_UNITS * 3];
    // count of characters in the buffer
    protected int decodedCount = 0;
    // index of the next decoded character
    protected int decodedIndex = 0;


    public Base64DecoderStream(InputStream in) {
        super(in);
        // make sure we get the ignore errors flag
        ignoreErrors = SessionUtil.getBooleanProperty(MAIL_BASE64_IGNOREERRORS, false);
    }

    /**
     * Test for the existance of decoded characters in our buffer
     * of decoded data.
     *
     * @return True if we currently have buffered characters.
     */
    private boolean dataAvailable() {
        return decodedCount != 0;
    }

    /**
     * Get the next buffered decoded character.
     *
     * @return The next decoded character in the buffer.
     */
    private byte getBufferedChar() {
        decodedCount--;
        return decodedChars[decodedIndex++];
    }

    /**
     * Decode a requested number of bytes of data into a buffer.
     *
     * @return true if we were able to obtain more data, false otherwise.
     */
    private boolean decodeStreamData() throws IOException {
        decodedIndex = 0;

        // fill up a data buffer with input data
        int readCharacters = fillEncodedBuffer();

        if (readCharacters > 0) {
            decodedCount =  decoder.decode(encodedChars, 0, readCharacters, decodedChars);
            return true;
        }
        return false;
    }


    /**
     * Retrieve a single byte from the decoded characters buffer.
     *
     * @return The decoded character or -1 if there was an EOF condition.
     */
    private int getByte() throws IOException {
        if (!dataAvailable()) {
            if (!decodeStreamData()) {
                return -1;
            }
        }
        decodedCount--;
        return decodedChars[decodedIndex++];
    }

    private int getBytes(byte[] data, int offset, int length) throws IOException {

        int readCharacters = 0;
        while (length > 0) {
            // need data?  Try to get some
            if (!dataAvailable()) {
                // if we can't get this, return a count of how much we did get (which may be -1).<commit_msg>GERONIMO-4307 Base64DecoderStream return int value between -128 and +127, should be between +0 and +255<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.geronimo.mail.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.FilterInputStream;

/**
 * An implementation of a FilterInputStream that decodes the
 * stream data in BASE64 encoding format.  This version does the
 * decoding "on the fly" rather than decoding a single block of
 * data.  Since this version is intended for use by the MimeUtilty class,
 * it also handles line breaks in the encoded data.
 */
public class Base64DecoderStream extends FilterInputStream {

    static protected final String MAIL_BASE64_IGNOREERRORS = "mail.mime.base64.ignoreerrors";

    // number of decodeable units we'll try to process at one time.  We'll attempt to read that much
    // data from the input stream and decode in blocks.
    static protected final int BUFFERED_UNITS = 2000;

    // our decoder for processing the data
    protected Base64Encoder decoder = new Base64Encoder();

    // can be overridden by a system property.
    protected boolean ignoreErrors = false;

    // buffer for reading in chars for decoding (which can support larger bulk reads)
    protected byte[] encodedChars = new byte[BUFFERED_UNITS * 4];
    // a buffer for one decoding unit's worth of data (3 bytes).  This is the minimum amount we
    // can read at one time.
    protected byte[] decodedChars = new byte[BUFFERED_UNITS * 3];
    // count of characters in the buffer
    protected int decodedCount = 0;
    // index of the next decoded character
    protected int decodedIndex = 0;


    public Base64DecoderStream(InputStream in) {
        super(in);
        // make sure we get the ignore errors flag
        ignoreErrors = SessionUtil.getBooleanProperty(MAIL_BASE64_IGNOREERRORS, false);
    }

    /**
     * Test for the existance of decoded characters in our buffer
     * of decoded data.
     *
     * @return True if we currently have buffered characters.
     */
    private boolean dataAvailable() {
        return decodedCount != 0;
    }

    /**
     * Get the next buffered decoded character.
     *
     * @return The next decoded character in the buffer.
     */
    private byte getBufferedChar() {
        decodedCount--;
        return decodedChars[decodedIndex++];
    }

    /**
     * Decode a requested number of bytes of data into a buffer.
     *
     * @return true if we were able to obtain more data, false otherwise.
     */
    private boolean decodeStreamData() throws IOException {
        decodedIndex = 0;

        // fill up a data buffer with input data
        int readCharacters = fillEncodedBuffer();

        if (readCharacters > 0) {
            decodedCount =  decoder.decode(encodedChars, 0, readCharacters, decodedChars);
            return true;
        }
        return false;
    }


    /**
     * Retrieve a single byte from the decoded characters buffer.
     *
     * @return The decoded character or -1 if there was an EOF condition.
     */
    private int getByte() throws IOException {
        if (!dataAvailable()) {
            if (!decodeStreamData()) {
                return -1;
            }
        }
        decodedCount--;
        // we need to ensure this doesn't get sign extended 
        return decodedChars[decodedIndex++] & 0xff;
    }

    private int getBytes(byte[] data, int offset, int length) throws IOException {

        int readCharacters = 0;
        while (length > 0) {
            // need data?  Try to get some
            if (!dataAvailable()) {
                // if we can't get this, return a count of how much we did get (which may be -1).
{'fraction_non_alphanumeric': 0.07163908410791203, 'fraction_numerical': 0.010541827250056677, 'mean_word_length': 2.630864197530864, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6546154', 'n_tokens_mistral': 2363, 'n_tokens_neox': 2193, 'n_words': 1013}