All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fernice.flare.cssparser.Reader.kt Maven / Gradle / Ivy

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package org.fernice.flare.cssparser

class Reader internal constructor(buffer: CharArray, private val bufLen: Int) {

    private val buffer: CharArray

    /**
     * The current position of the reader within the buffer.
     */
    // package-private to prevent external manipulation
    @JvmField
    internal var bp: Int = 0

    /**
     * The current char. If the end of file has been reached, this char will always be \u001a and [.isEoF] will
     * return true.
     */
    @JvmField
    var c: Char = ' '

    /**
     * The current line in the text starting at 0. This can be used for error reporting.
     */
    @JvmField
    var line: Int = 0

    /**
     * The current column or position in the current line starting at 0. This can be used for error reporting.
     */
    @JvmField
    var column = -1

    private var word: CharArray
    private var wordPos: Int = 0

    /**
     * Returns if the reader reached end of file. If true, the current char will always be \u001a.
     *
     * @return true if end of file, otherwise false
     */
    val isEoF: Boolean
        get() = bp >= bufLen

    internal constructor(text: String) : this(text.toCharArray(), text.length) {}

    init {
        var buffer = buffer
        if (bufLen == buffer.size) {
            val newBuffer = CharArray(bufLen + 1)
            System.arraycopy(buffer, 0, newBuffer, 0, buffer.size)
            buffer = newBuffer
        }

        this.word = CharArray(128)
        this.buffer = buffer
        this.bp = -1
        this.buffer[bufLen] = 26.toChar()
        nextChar()
    }

    /**
     * Advances the char stream virtually by one char. Automatically converts all line break into \n. If end of file is
     * reached, the next char will always \u001a
     */
    fun nextChar() {
        if (bp < bufLen) {
            c = buffer[++bp]
            column++

            if (c == '\r') {
                if (peekChar() == '\n') {
                    bp++
                    column++
                }
                c = '\n'
            } else if (c == '\u000C') {
                c = '\n'
            }

            if (c == '\n') {
                line++
                column = 0
            }
        }
    }

    /**
     * Advances the char stream virtually by the amount of chars specified. Automatically converts all line break into \n.
     *
     * @param count chars to advance
     * @see .nextChar
     */
    fun nextChar(count: Int) {
        for (i in 0 until count) {
            nextChar()
        }
    }

    /**
     * Returns the nth next char with advancing the char stream.
     *
     * @param nth the relative index of the next char
     * @return the nth next char
     */
    @JvmOverloads
    fun peekChar(nth: Int = 1): Char {
        return if (bp + nth >= bufLen) {
            buffer[bufLen]
        } else buffer[bp + nth]
    }

    /**
     * Puts the nth next chars into the text buffer and advances the char stream.
     *
     * @param nth the n next chars
     */
    fun putChar(nth: Int) {
        for (i in 0 until nth) {
            putChar()
        }
    }

    /**
     * Puts the current char into the text buffer and optionally advances the char stream.
     *
     * @param read whether to advance the char stream
     */
    @JvmOverloads
    fun putChar(read: Boolean = true) {
        putChar(c, read)
    }

    /**
     * Puts the specified char into the text buffer and optionally advances the char stream.
     *
     * @param c    the char to put into the text buffer
     * @param read whether to advances the char stream
     */
    fun putChar(c: Char, read: Boolean) {
        word = ensureCapacity(word, wordPos)

        word[wordPos++] = c

        if (read) {
            nextChar()
        }
    }

    /**
     * Returns the string composed in the text buffer and clear the text buffer.
     *
     * @return the string of the text buffer
     */
    fun text(): String {
        val text = String(word, 0, wordPos)
        wordPos = 0
        return text
    }

    private fun ensureCapacity(buffer: CharArray, position: Int): CharArray {
        if (position >= buffer.size) {
            var length = buffer.size

            while (length < position + 1) {
                length *= 2
            }

            val newBuffer = CharArray(length)
            System.arraycopy(buffer, 0, newBuffer, 0, buffer.size)
            return newBuffer
        }
        return buffer
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy