/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2006 - 2013 Pentaho Corporation and Contributors. All rights reserved. */ package org.pentaho.reporting.libraries.formula.parser; /** * An implementation of interface CharStream, where the stream is assumed to contain only ASCII characters (with * java-like unicode escape processing). */ public class JavaCharStream { public static final boolean staticFlag = false; static int hexval( final char c ) throws java.io.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; } throw new java.io.IOException(); // Should never come here } public int bufpos = -1; int bufsize; int available; int tokenBegin; protected int[] bufline; protected int[] bufcolumn; protected int column = 0; protected int line = 1; protected boolean prevCharIsCR = false; protected boolean prevCharIsLF = false; protected java.io.Reader inputStream; protected char[] nextCharBuf; protected char[] buffer; protected int maxNextCharInd = 0; protected int nextCharInd = -1; protected int inBuf = 0; protected void ExpandBuff( final boolean wrapAround ) { final char[] newbuffer = new char[ bufsize + 2048 ]; final int[] newbufline = new int[ bufsize + 2048 ]; final 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 void FillBuff() throws java.io.IOException { if ( maxNextCharInd == 4096 ) { maxNextCharInd = nextCharInd = 0; } try { final int i; if ( ( i = inputStream.read( nextCharBuf, maxNextCharInd, 4096 - maxNextCharInd ) ) == -1 ) { inputStream.close(); throw new java.io.IOException(); } maxNextCharInd += i; return; } catch ( java.io.IOException e ) { if ( bufpos != 0 ) { --bufpos; backup( 0 ); } else { bufline[ bufpos ] = line; bufcolumn[ bufpos ] = column; } throw e; } } protected char ReadByte() throws java.io.IOException { if ( ++nextCharInd >= maxNextCharInd ) { FillBuff(); } return nextCharBuf[ nextCharInd ]; } public char BeginToken() throws java.io.IOException { if ( inBuf > 0 ) { --inBuf; if ( ++bufpos == bufsize ) { bufpos = 0; } tokenBegin = bufpos; return buffer[ bufpos ]; } tokenBegin = 0; bufpos = -1; return readChar(); } 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 UpdateLineColumn( final 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 += ( 8 - ( column & 07 ) ); break; default: break; } bufline[ bufpos ] = line; bufcolumn[ bufpos ] = column; } public char readChar() throws java.io.IOException { if ( inBuf > 0 ) { --inBuf; if ( ++bufpos == bufsize ) { bufpos = 0; } return buffer[ bufpos ]; } if ( ++bufpos == available ) { AdjustBuffSize(); } char c; 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 ( java.io.IOException e ) { if ( backSlashCnt > 1 ) { backup( backSlashCnt ); } 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 ( java.io.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 ); } } /** * @see #getEndColumn * @deprecated */ public int getColumn() { return bufcolumn[ bufpos ]; } /** * @see #getEndLine * @deprecated */ public int getLine() { return bufline[ bufpos ]; } public int getEndColumn() { return bufcolumn[ bufpos ]; } public int getEndLine() { return bufline[ bufpos ]; } public int getBeginColumn() { return bufcolumn[ tokenBegin ]; } public int getBeginLine() { return bufline[ tokenBegin ]; } public void backup( final int amount ) { inBuf += amount; if ( ( bufpos -= amount ) < 0 ) { bufpos += bufsize; } } public JavaCharStream( final java.io.Reader dstream, final int startline, final int startcolumn, final 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 ]; } public JavaCharStream( final java.io.Reader dstream, final int startline, final int startcolumn ) { this( dstream, startline, startcolumn, 4096 ); } public JavaCharStream( final java.io.Reader dstream ) { this( dstream, 1, 1, 4096 ); } public void ReInit( final java.io.Reader dstream, final int startline, final int startcolumn, final 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; } public void ReInit( final java.io.Reader dstream, final int startline, final int startcolumn ) { ReInit( dstream, startline, startcolumn, 4096 ); } public void ReInit( final java.io.Reader dstream ) { ReInit( dstream, 1, 1, 4096 ); } public JavaCharStream( final java.io.InputStream dstream, final int startline, final int startcolumn, final int buffersize ) { this( new java.io.InputStreamReader( dstream ), startline, startcolumn, 4096 ); } public JavaCharStream( final java.io.InputStream dstream, final int startline, final int startcolumn ) { this( dstream, startline, startcolumn, 4096 ); } public JavaCharStream( final java.io.InputStream dstream ) { this( dstream, 1, 1, 4096 ); } public void ReInit( final java.io.InputStream dstream, final int startline, final int startcolumn, final int buffersize ) { ReInit( new java.io.InputStreamReader( dstream ), startline, startcolumn, 4096 ); } public void ReInit( final java.io.InputStream dstream, final int startline, final int startcolumn ) { ReInit( dstream, startline, startcolumn, 4096 ); } public void ReInit( final java.io.InputStream dstream ) { ReInit( dstream, 1, 1, 4096 ); } 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 ); } } public char[] GetSuffix( final int len ) { final 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; } public void Done() { nextCharBuf = null; buffer = null; bufline = null; bufcolumn = null; } /** * Method to adjust line and column numbers for the start of a token. */ public void adjustBeginLineColumn( int newLine, final int newCol ) { int start = tokenBegin; final int len; if ( bufpos >= tokenBegin ) { len = bufpos - tokenBegin + inBuf + 1; } else { len = bufsize - tokenBegin + bufpos + 1 + inBuf; } int i = 0; int j = 0; int k; int nextColDiff; int 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 ]; } }