JavaCharStream.java

/* Generated By:JavaCC: Do not edit this line. JavaCharStream.java Version 8.1.0 */
/*
 * Copyright (c) 2022, 2026 Eclipse Foundation
 * Copyright (C) 2004-2011
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.sun.tools.rngom.parse.compact;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;

/**
 * The implementation (but not declared as such) of the interface CharStream generated by Javacc/java
 *  (by JavaCodeGenerator.java and JavaTemplates.java with java/JavaCharStream.template) where the stream
 *  is assumed to contain only ASCII characters <b>with</b> java-like Unicode escape processing.
 */
public class JavaCharStream {

  /** Whether parser is static. */
  public static final boolean staticFlag = false;

  protected Reader inputStream;

  int bufsize;
  int available;
  int tokenBegin;
  public int bufpos = -1;

  protected char[] buffer;
  protected int    maxNextCharInd = 0;
  protected int    inBuf = 0;

  protected char[] nextCharBuf;
  protected int    nextCharInd = -1;

  //protected boolean trackLineColumn = true;
  protected int[]   bufline;
  protected int[]   bufcolumn;
  protected int     line = 1;
  protected int     column = 0;
  protected boolean prevCharIsCR = false;
  protected boolean prevCharIsLF = false;
  protected int     tabSize = 1;

  /** Get starting character for token. */
  // Don't know why this method is different than in SimpleCharStream. Makes EOF handling different.
  public char BeginToken() throws IOException {
    if (inBuf > 0) {
      --inBuf;
      if (++bufpos == bufsize) {
        bufpos = 0;
      }
      tokenBegin = bufpos;
      return buffer[bufpos];
    }
    tokenBegin = 0;
    bufpos = -1;
    return readChar();
  }

  /** Read a character. */
  public char readChar() throws IOException {
    if (inBuf > 0) {
      --inBuf;
      if (++bufpos == bufsize) {
        bufpos = 0;
      }
      return buffer[bufpos];
    }

    char c;
    if (++bufpos == available) {
      AdjustBuffSize();
    }
    if ((buffer[bufpos] = c = ReadByte()) == '\\') {
      UpdateLineColumn(c);
      int backSlashCnt = 1;

      for (;;) { // Read all the backslashes
        if (++bufpos == available) {
          AdjustBuffSize();
        }
        try {
          if ((buffer[bufpos] = c = ReadByte()) != '\\') {
            UpdateLineColumn(c);
            // found a non-backslash char.
            if ((c == 'u') && ((backSlashCnt & 1) == 1)) {
              if (--bufpos < 0) {
                bufpos = bufsize - 1;
              }
              break;
            }
            backup(backSlashCnt);
            return '\\';
          }
        } catch (IOException e) {
          // We are returning one backslash so we should only backup (count-1)
          if (backSlashCnt > 1) {
            backup(backSlashCnt - 1);
          }
          return '\\';
        }

        UpdateLineColumn(c);
        backSlashCnt++;
      }

      // Here, we have seen an odd number of backslash's followed by a 'u'
      try {
        while ((c = ReadByte()) == 'u') {
          ++column;
        }
        buffer[bufpos] = c = (char) ( hexval(c) << 12
                                    | hexval(ReadByte()) << 8
                                    | hexval(ReadByte()) << 4
                                    | hexval(ReadByte()) );
        column += 4;
      } catch (IOException e) {
        throw new Error(
                  "Invalid escape character at line " + line + " column " + column + ".");
      }

      if (backSlashCnt == 1) {
        return c;
      } else {
        backup(backSlashCnt - 1);
        return '\\';
      }
    } else {
      UpdateLineColumn(c);
      return c;
    }
  }

  protected void AdjustBuffSize() {
    if (available == bufsize) {
      if (tokenBegin > 2048) {
        bufpos = 0;
        available = tokenBegin;
      } else {
        ExpandBuff(false);
      }
    } else if (available > tokenBegin) {
      available = bufsize;
    } else if ((tokenBegin - available) < 2048) {
      ExpandBuff(true);
    } else {
      available = tokenBegin;
    }
  }

  protected void ExpandBuff(boolean wrapAround) {
    char[] newbuffer = new char[bufsize + 2048];
    int[] newbufline = new int[bufsize + 2048];
    int[] newbufcolumn = new int[bufsize + 2048];

    try {
      if (wrapAround) {
        System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
        System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
        buffer = newbuffer;
        System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
        System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
        bufline = newbufline;
        System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
        System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
        bufcolumn = newbufcolumn;
        bufpos += (bufsize - tokenBegin);
      } else {
        System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
        buffer = newbuffer;
        System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
        bufline = newbufline;

        System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
        bufcolumn = newbufcolumn;
        bufpos -= tokenBegin;
      }
    } catch (Throwable t) {
      throw new Error(t.getMessage());
    }

    available = (bufsize += 2048);
    tokenBegin = 0;
  }

  protected char ReadByte() throws IOException {
    if (++nextCharInd >= maxNextCharInd) {
      FillBuff();
    }
    return nextCharBuf[nextCharInd];
  }

  protected void FillBuff() throws IOException {
    int i;
    if (maxNextCharInd == 4096) {
      maxNextCharInd = nextCharInd = 0;
    }
    try {
      if ((i = inputStream.read(nextCharBuf, maxNextCharInd, 4096 - maxNextCharInd)) == -1) {
        inputStream.close();
        throw new IOException("End of file");
      } else {
        maxNextCharInd += i;
      }
    } catch (IOException e) {
      if (bufpos != 0) {
        --bufpos;
        backup(0);
      } else {
        bufline[bufpos] = line;
        bufcolumn[bufpos] = column;
      }
      throw e;
    }
  }

  protected void UpdateLineColumn(char c) {
    column++;

    if (prevCharIsLF) {
      prevCharIsLF = false;
      line += (column = 1);
    } else if (prevCharIsCR) {
      prevCharIsCR = false;
      if (c == '\n') {
        prevCharIsLF = true;
      } else {
        line += (column = 1);
      }
    }

    switch (c) {
      case '\r':
        prevCharIsCR = true;
        break;
      case '\n':
        prevCharIsLF = true;
        break;
      case '\t':
        column--;
        column += (tabSize - (column % tabSize));
        break;
      default:
        break;
    }

    bufline[bufpos] = line;
    bufcolumn[bufpos] = column;
  }

  static int hexval(char c) throws IOException {
    switch (c) {
      case '0':
        return 0;
      case '1':
        return 1;
      case '2':
        return 2;
      case '3':
        return 3;
      case '4':
        return 4;
      case '5':
        return 5;
      case '6':
        return 6;
      case '7':
        return 7;
      case '8':
        return 8;
      case '9':
        return 9;

      case 'a':
      case 'A':
        return 10;
      case 'b':
      case 'B':
        return 11;
      case 'c':
      case 'C':
        return 12;
      case 'd':
      case 'D':
        return 13;
      case 'e':
      case 'E':
        return 14;
      case 'f':
      case 'F':
        return 15;
      default:
        throw new IOException(); // Should never come here
    }
  }

  /** Backup a number of characters. */
  public void backup(int amount) {
    inBuf += amount;
    if ((bufpos -= amount) < 0) {
      bufpos += bufsize;
    }
  }

  /** Set buffers back to null when finished. */
  public void Done() {
    nextCharBuf = null;
    buffer = null;
    bufline = null;
    bufcolumn = null;
  }

  /**
   * Get the token image.
   *
   * @return the token image
   */
  public String GetImage() {
    if (bufpos >= tokenBegin) {
      return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
    } else {
      return new String(buffer, tokenBegin, bufsize - tokenBegin)
                              + new String(buffer, 0, bufpos + 1);
    }
  }

  /**
   * Get the suffix.
   *
   * @param len - the length of the array to return.
   * @return the suffix
   */
  public char[] GetSuffix(int len) {
    char[] ret = new char[len];
    if ((bufpos + 1) >= len) {
      System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
    } else {
      System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, len - bufpos - 1);
      System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
    }
    return ret;
  }

  /** Constructor on Reader. */
  public JavaCharStream(Reader dstream, int startline, int startcolumn, int buffersize) {
    inputStream = dstream;
    line = startline;
    column = startcolumn - 1;
    available = bufsize = buffersize;
    buffer = new char[buffersize];
    bufline = new int[buffersize];
    bufcolumn = new int[buffersize];
    nextCharBuf = new char[4096];
  }

  /** Constructor on Reader. */
  public JavaCharStream(Reader dstream, int startline, int startcolumn) {
    this(dstream, startline, startcolumn, 4096);
  }

  /** Constructor on Reader. */
  public JavaCharStream(Reader dstream) {
    this(dstream, 1, 1, 4096);
  }

  /** Reinitialise on Reader. */
  public void ReInit(Reader dstream, int startline, int startcolumn, int buffersize) {
    inputStream = dstream;
    line = startline;
    column = startcolumn - 1;
    if (buffer == null || buffersize != buffer.length) {
      available = bufsize = buffersize;
      buffer = new char[buffersize];
      bufline = new int[buffersize];
      bufcolumn = new int[buffersize];
      nextCharBuf = new char[4096];
    }
    prevCharIsLF = prevCharIsCR = false;
    tokenBegin = inBuf = maxNextCharInd = 0;
    nextCharInd = bufpos = -1;
  }

  /** Reinitialise on Reader. */
  public void ReInit(Reader dstream, int startline, int startcolumn) {
    ReInit(dstream, startline, startcolumn, 4096);
  }

  /** Reinitialise on Reader. */
  public void ReInit(Reader dstream) {
    ReInit(dstream, 1, 1, 4096);
  }

  /**
   * Constructor on InputStream.
   *
   * @param dstream - the underlying data source
   * @param encoding - the character encoding of the data stream
   * @param startline - line number of the first character of the stream, mostly for error messages
   * @param startcolumn - column number of the first character of the stream
   * @param buffersize - size of the buffer
   * @throws UnsupportedEncodingException if encoding is invalid or unsupported
   */
  public JavaCharStream(InputStream dstream, String encoding,
                        int startline, int startcolumn, int buffersize)
      throws UnsupportedEncodingException {
    this(encoding == null ? new InputStreamReader(dstream)
        : new InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
  }

  /**
   * Constructor on InputStream.
   *
   * @param dstream - the underlying data source
   * @param startline - line number of the first character of the stream, mostly for error messages
   * @param startcolumn - column number of the first character of the stream
   * @param buffersize - size of the buffer
   */
  public JavaCharStream(InputStream dstream, int startline, int startcolumn, int buffersize) {
    this(new InputStreamReader(dstream), startline, startcolumn, buffersize);
  }

  /**
   * Constructor on InputStream.
   *
   * @param dstream - the underlying data source
   * @param encoding - the character encoding of the data stream
   * @param startline - line number of the first character of the stream, mostly for error messages
   * @param startcolumn - column number of the first character of the stream
   * @throws UnsupportedEncodingException if encoding is invalid or unsupported
   */
  public JavaCharStream(InputStream dstream, String encoding, int startline, int startcolumn)
                        throws UnsupportedEncodingException {
    this(dstream, encoding, startline, startcolumn, 4096);
  }

  /** Constructor on InputStream.
   *
   * @param dstream - the underlying data source
   * @param startline - line number of the first character of the stream, mostly for error messages
   * @param startcolumn - column number of the first character of the stream
   */
  public JavaCharStream(InputStream dstream, int startline, int startcolumn) {
    this(dstream, startline, startcolumn, 4096);
  }

  /** Constructor on InputStream.
   *
   * @param dstream - the underlying data source
   * @param encoding - the character encoding of the data stream
   * @throws UnsupportedEncodingException if encoding is invalid or unsupported
   */
  public JavaCharStream(InputStream dstream, String encoding)
      throws UnsupportedEncodingException {
    this(dstream, encoding, 1, 1, 4096);
  }

  /** Constructor on InputStream.
   *
   * @param dstream - the underlying data source
   */
  public JavaCharStream(InputStream dstream) {
    this(dstream, 1, 1, 4096);
  }

  /**
   * Reinitialise on InputStream.
   *
   * @param dstream - the underlying data source
   * @param encoding - the character encoding of the data stream
   * @param startline - line number of the first character of the stream, mostly for error messages
   * @param startcolumn - column number of the first character of the stream
   * @param buffersize - size of the buffer
   * @throws UnsupportedEncodingException if encoding is invalid or unsupported
   */
  public void ReInit(InputStream dstream, String encoding,
                    int startline, int startcolumn, int buffersize)
      throws UnsupportedEncodingException {
    ReInit(encoding == null
        ? new InputStreamReader(dstream)
        : new InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
  }

  /**
   * Reinitialise on InputStream.
   *
   * @param dstream - the underlying data source
   * @param startline - line number of the first character of the stream, mostly for error messages
   * @param startcolumn - column number of the first character of the stream
   * @param buffersize - size of the buffer
   */
  public void ReInit(InputStream dstream, int startline, int startcolumn, int buffersize) {
    ReInit(new InputStreamReader(dstream), startline, startcolumn, buffersize);
  }

  /**
   * Reinitialise on InputStream.
   *
   * @param dstream - the underlying data source
   * @param encoding - the character encoding of the data stream
   * @param startline - line number of the first character of the stream, mostly for error messages
   * @param startcolumn - column number of the first character of the stream
   * @throws UnsupportedEncodingException if encoding is invalid or unsupported
   */
  public void ReInit(InputStream dstream, String encoding, int startline, int startcolumn)
      throws UnsupportedEncodingException {
    ReInit(dstream, encoding, startline, startcolumn, 4096);
  }

  /**
   * Reinitialise on InputStream.
   *
   * @param dstream - the underlying data source
   * @param startline - line number of the first character of the stream, mostly for error messages
   * @param startcolumn - column number of the first character of the stream
   */
  public void ReInit(InputStream dstream, int startline, int startcolumn) {
    ReInit(dstream, startline, startcolumn, 4096);
  }

  /**
   * Reinitialise on InputStream.
   *
   * @param dstream - the underlying data source
   * @param encoding - the character encoding of the data stream
   * @throws UnsupportedEncodingException if encoding is invalid or unsupported
   */
  public void ReInit(InputStream dstream, String encoding)
      throws UnsupportedEncodingException {
    ReInit(dstream, encoding, 1, 1, 4096);
  }

  /**
   * Reinitialise on InputStream.
   *
   * @param dstream - the underlying data source
   */
  public void ReInit(InputStream dstream) {
    ReInit(dstream, 1, 1, 4096);
  }

  /** Get the token beginning character line number. */
  public int getBeginLine() {
    return bufline[tokenBegin];
  }

  /** Get the token beginning character column number. */
  public int getBeginColumn() {
    return bufcolumn[tokenBegin];
  }

  /** Get the token ending character line number. */
  public int getEndLine() {
    return bufline[bufpos];
  }

  /** Get the token ending character column number. */
  public int getEndColumn() {
    return bufcolumn[bufpos];
  }

  /**
   * Adjust line and column numbers for the start of a token.
   *
   * @param newLine - the new line number.
   * @param newCol - the new column number.
   */
  public void adjustBeginLineColumn(int newLine, int newCol) {
    int start = tokenBegin;
    int len;

    if (bufpos >= tokenBegin) {
      len = bufpos - tokenBegin + inBuf + 1;
    } else {
      len = bufsize - tokenBegin + bufpos + 1 + inBuf;
    }

    int i = 0, j = 0, k = 0;
    int nextColDiff = 0, columnDiff = 0;

    while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) {
      bufline[j] = newLine;
      nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
      bufcolumn[j] = newCol + columnDiff;
      columnDiff = nextColDiff;
      i++;
    }

    if (i < len) {
      bufline[j] = newLine++;
      bufcolumn[j] = newCol + columnDiff;

      while (i++ < len) {
        if (bufline[j = start % bufsize] != bufline[++start % bufsize]) {
          bufline[j] = newLine++;
        } else {
          bufline[j] = newLine;
        }
      }
    }

    line = bufline[j];
    column = bufcolumn[j];
  }

  //boolean getTrackLineColumn()         { return trackLineColumn; }

  //void setTrackLineColumn(boolean tlc) { trackLineColumn = tlc; }

  public int  getTabSize()      { return tabSize; }

  public void setTabSize(int i) { tabSize = i; }

}
/* JavaCC - OriginalChecksum=b31140e440bb555c811d2773cedf3d43 (do not edit this line) */