com.phloc.css.parser.CSSCharStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of phloc-css-jdk5 Show documentation
Show all versions of phloc-css-jdk5 Show documentation
phloc CSS parser an other components
/**
* Copyright (C) 2006-2014 phloc systems
* http://www.phloc.com
* office[at]phloc[dot]com
*
* 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.
*/
package com.phloc.css.parser;
import java.io.IOException;
import java.io.Reader;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import com.phloc.commons.ValueEnforcer;
import com.phloc.commons.io.streams.StreamUtils;
import com.phloc.commons.string.StringHelper;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* This class is only used internally as the source for the generated parsers.
* An implementation of interface {@link CharStream}, where the stream is
* assumed to contain only ASCII characters (with java-like unicode escape
* processing).
*
* @author Philip Helger
*/
@SuppressFBWarnings ("NM_METHOD_NAMING_CONVENTION")
public final class CSSCharStream implements CharStream
{
private static final int DEFAULT_BUF_SIZE = 4096;
private final Reader m_aReader;
private int m_nLine;
private int m_nColumn;
private int m_nAvailable;
private int m_nBufsize;
private char [] m_aBuffer;
private int [] m_aBufLine;
private int [] m_aBufColumn;
private char [] m_aNextCharBuf;
private boolean m_bPrevCharIsCR = false;
private boolean m_bPrevCharIsLF = false;
private int m_nTokenBegin = 0;
private int m_nInBuf = 0;
private int m_nMaxNextCharInd = 0;
private int m_nNextCharInd = -1;
/** Position in buffer. */
private int m_nBufpos = -1;
private int m_nTabSize = 8;
private boolean m_bTrackLineColumn = true;
public CSSCharStream (@Nonnull final Reader aReader)
{
this (aReader, 1, 1, DEFAULT_BUF_SIZE);
}
private CSSCharStream (@Nonnull final Reader aReader,
@Nonnegative final int nStartLine,
@Nonnegative final int nStartColumn,
@Nonnegative final int nBufferSize)
{
ValueEnforcer.isGE0 (nBufferSize, "BufferSize");
// Using a buffered reader gives a minimal speedup
m_aReader = StreamUtils.getBuffered (ValueEnforcer.notNull (aReader, "Reader"));
m_nLine = ValueEnforcer.isGE0 (nStartLine, "StartLine");
m_nColumn = ValueEnforcer.isGE0 (nStartColumn, "StartColumn") - 1;
m_nAvailable = nBufferSize;
m_nBufsize = nBufferSize;
m_aBuffer = new char [nBufferSize];
m_aBufLine = new int [nBufferSize];
m_aBufColumn = new int [nBufferSize];
m_aNextCharBuf = new char [DEFAULT_BUF_SIZE];
}
public void setTabSize (final int i)
{
m_nTabSize = i;
}
public int getTabSize ()
{
return m_nTabSize;
}
private void _expandBuff (final boolean bWrapAround)
{
final char [] aNewBuffer = new char [m_nBufsize + 2048];
final int [] aNewBufLine = new int [m_nBufsize + 2048];
final int [] newbufcolumn = new int [m_nBufsize + 2048];
try
{
if (bWrapAround)
{
System.arraycopy (m_aBuffer, m_nTokenBegin, aNewBuffer, 0, m_nBufsize - m_nTokenBegin);
System.arraycopy (m_aBuffer, 0, aNewBuffer, m_nBufsize - m_nTokenBegin, m_nBufpos);
m_aBuffer = aNewBuffer;
System.arraycopy (m_aBufLine, m_nTokenBegin, aNewBufLine, 0, m_nBufsize - m_nTokenBegin);
System.arraycopy (m_aBufLine, 0, aNewBufLine, m_nBufsize - m_nTokenBegin, m_nBufpos);
m_aBufLine = aNewBufLine;
System.arraycopy (m_aBufColumn, m_nTokenBegin, newbufcolumn, 0, m_nBufsize - m_nTokenBegin);
System.arraycopy (m_aBufColumn, 0, newbufcolumn, m_nBufsize - m_nTokenBegin, m_nBufpos);
m_aBufColumn = newbufcolumn;
m_nBufpos += (m_nBufsize - m_nTokenBegin);
}
else
{
System.arraycopy (m_aBuffer, m_nTokenBegin, aNewBuffer, 0, m_nBufsize - m_nTokenBegin);
m_aBuffer = aNewBuffer;
System.arraycopy (m_aBufLine, m_nTokenBegin, aNewBufLine, 0, m_nBufsize - m_nTokenBegin);
m_aBufLine = aNewBufLine;
System.arraycopy (m_aBufColumn, m_nTokenBegin, newbufcolumn, 0, m_nBufsize - m_nTokenBegin);
m_aBufColumn = newbufcolumn;
m_nBufpos -= m_nTokenBegin;
}
}
catch (final Throwable t)
{
throw new Error ("Something went wrong", t);
}
m_nBufsize += 2048;
m_nAvailable = m_nBufsize;
m_nTokenBegin = 0;
}
private void _fillBuff () throws IOException
{
if (m_nMaxNextCharInd == DEFAULT_BUF_SIZE)
{
m_nMaxNextCharInd = 0;
m_nNextCharInd = 0;
}
try
{
final int i = m_aReader.read (m_aNextCharBuf, m_nMaxNextCharInd, DEFAULT_BUF_SIZE - m_nMaxNextCharInd);
if (i == -1)
{
m_aReader.close ();
throw new IOException ("EOF in JavaCharStream");
}
m_nMaxNextCharInd += i;
return;
}
catch (final IOException ex)
{
if (m_nBufpos != 0)
{
--m_nBufpos;
backup (0);
}
else
{
m_aBufLine[m_nBufpos] = m_nLine;
m_aBufColumn[m_nBufpos] = m_nColumn;
}
throw ex;
}
}
private char _readByte () throws IOException
{
++m_nNextCharInd;
if (m_nNextCharInd >= m_nMaxNextCharInd)
_fillBuff ();
return m_aNextCharBuf[m_nNextCharInd];
}
/**
* @return starting character for token.
* @throws IOException
*/
public char BeginToken () throws IOException
{
if (m_nInBuf > 0)
{
--m_nInBuf;
if (++m_nBufpos == m_nBufsize)
m_nBufpos = 0;
m_nTokenBegin = m_nBufpos;
return m_aBuffer[m_nBufpos];
}
m_nTokenBegin = 0;
m_nBufpos = -1;
return readChar ();
}
private void _adjustBuffSize ()
{
if (m_nAvailable == m_nBufsize)
{
if (m_nTokenBegin > 2048)
{
m_nBufpos = 0;
m_nAvailable = m_nTokenBegin;
}
else
_expandBuff (false);
}
else
if (m_nAvailable > m_nTokenBegin)
m_nAvailable = m_nBufsize;
else
if ((m_nTokenBegin - m_nAvailable) < 2048)
_expandBuff (true);
else
m_nAvailable = m_nTokenBegin;
}
private void _updateLineColumn (final char c)
{
m_nColumn++;
if (m_bPrevCharIsLF)
{
m_bPrevCharIsLF = false;
m_nColumn = 1;
m_nLine++;
}
else
if (m_bPrevCharIsCR)
{
m_bPrevCharIsCR = false;
if (c == '\n')
m_bPrevCharIsLF = true;
else
{
m_nColumn = 1;
m_nLine++;
}
}
switch (c)
{
case '\r':
m_bPrevCharIsCR = true;
break;
case '\n':
m_bPrevCharIsLF = true;
break;
case '\t':
m_nColumn--;
m_nColumn += (m_nTabSize - (m_nColumn % m_nTabSize));
break;
default:
break;
}
m_aBufLine[m_nBufpos] = m_nLine;
m_aBufColumn[m_nBufpos] = m_nColumn;
}
private static boolean _isHexChar (final char c)
{
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
private static int _hexval (final char c) throws IOException
{
final int ret = StringHelper.getHexValue (c);
if (ret < 0)
throw new IOException ("Illegal hex char '" + c + "'");
return ret;
}
/**
* Read a character.
*
* @return The read character
* @throws IOException
* if an I/O error occurs
*/
public char readChar () throws IOException
{
if (m_nInBuf > 0)
{
--m_nInBuf;
if (++m_nBufpos == m_nBufsize)
m_nBufpos = 0;
return m_aBuffer[m_nBufpos];
}
if (++m_nBufpos == m_nAvailable)
_adjustBuffSize ();
char c;
m_aBuffer[m_nBufpos] = c = _readByte ();
// This would be the point to handle CSS (un)escaping
if (m_bTrackLineColumn)
_updateLineColumn (c);
return c;
}
@Deprecated
public int getColumn ()
{
return getEndColumn ();
}
@Deprecated
public int getLine ()
{
return getEndLine ();
}
/** @return end column. */
public int getEndColumn ()
{
return m_aBufColumn[m_nBufpos];
}
/** @return end line. */
public int getEndLine ()
{
return m_aBufLine[m_nBufpos];
}
/** @return column of token start */
public int getBeginColumn ()
{
return m_aBufColumn[m_nTokenBegin];
}
/** @return line number of token start */
public int getBeginLine ()
{
return m_aBufLine[m_nTokenBegin];
}
/** Retreat. */
public void backup (final int nAmount)
{
m_nInBuf += nAmount;
m_nBufpos -= nAmount;
if (m_nBufpos < 0)
m_nBufpos += m_nBufsize;
}
/** @return token image as String */
public String GetImage ()
{
if (m_nBufpos >= m_nTokenBegin)
return new String (m_aBuffer, m_nTokenBegin, m_nBufpos - m_nTokenBegin + 1);
return new String (m_aBuffer, m_nTokenBegin, m_nBufsize - m_nTokenBegin) + new String (m_aBuffer, 0, m_nBufpos + 1);
}
/** @return suffix */
public char [] GetSuffix (final int len)
{
final char [] ret = new char [len];
if ((m_nBufpos + 1) >= len)
System.arraycopy (m_aBuffer, m_nBufpos - len + 1, ret, 0, len);
else
{
System.arraycopy (m_aBuffer, m_nBufsize - (len - m_nBufpos - 1), ret, 0, len - m_nBufpos - 1);
System.arraycopy (m_aBuffer, 0, ret, len - m_nBufpos - 1, m_nBufpos + 1);
}
return ret;
}
/** Set buffers back to null when finished. */
public void Done ()
{
m_aNextCharBuf = null;
m_aBuffer = null;
m_aBufLine = null;
m_aBufColumn = null;
}
/**
* Method to adjust line and column numbers for the start of a token.
*/
public void adjustBeginLineColumn (int newLine, final int newCol)
{
int start = m_nTokenBegin;
int len;
if (m_nBufpos >= m_nTokenBegin)
{
len = m_nBufpos - m_nTokenBegin + m_nInBuf + 1;
}
else
{
len = m_nBufsize - m_nTokenBegin + m_nBufpos + 1 + m_nInBuf;
}
int i = 0, j = 0, k = 0;
int nextColDiff = 0, columnDiff = 0;
while (i < len && m_aBufLine[j = start % m_nBufsize] == m_aBufLine[k = ++start % m_nBufsize])
{
m_aBufLine[j] = newLine;
nextColDiff = columnDiff + m_aBufColumn[k] - m_aBufColumn[j];
m_aBufColumn[j] = newCol + columnDiff;
columnDiff = nextColDiff;
i++;
}
if (i < len)
{
m_aBufLine[j] = newLine++;
m_aBufColumn[j] = newCol + columnDiff;
while (i++ < len)
{
if (m_aBufLine[j = start % m_nBufsize] != m_aBufLine[++start % m_nBufsize])
m_aBufLine[j] = newLine++;
else
m_aBufLine[j] = newLine;
}
}
m_nLine = m_aBufLine[j];
m_nColumn = m_aBufColumn[j];
}
public boolean getTrackLineColumn ()
{
return m_bTrackLineColumn;
}
public void setTrackLineColumn (final boolean tlc)
{
m_bTrackLineColumn = tlc;
}
}