372 lines
10 KiB
Java
372 lines
10 KiB
Java
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (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.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
/*
|
|
* $Header: /home/befator/cvs/jail/cvsroot/mozilla/modules/edtplug/classes/netscape/plugin/composer/io/SlidingBuffer.java,v 3.2 1999-11-06 03:30:03 dmose%mozilla.org Exp $
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 3.1 1998/03/28 03:33:50 ltabb
|
|
* bump rev to 3.1
|
|
*
|
|
* Revision 1.1 1998/03/28 02:39:09 ltabb
|
|
* Free the lizard
|
|
*
|
|
* Revision 2.1 1998/03/11 23:56:37 anthonyd
|
|
* Bump revision number to 2
|
|
*
|
|
* Revision 1.5 1998/03/06 04:19:44 jwz
|
|
* added NPL and copyright
|
|
*
|
|
* Revision 1.4 1998/02/16 22:11:51 anthonyd
|
|
* Sanitized Files.
|
|
*
|
|
* Revision 1.3 1996/12/18 02:32:54 palevich
|
|
* Version 13.
|
|
*
|
|
* Revision 1.2 1996/12/07 04:30:04 palevich
|
|
* Updated composer plugin API
|
|
*
|
|
* Revision 1.1 1996/11/20 03:19:21 palevich
|
|
* Added Kipp's tokenizer.
|
|
*
|
|
* Revision 1.1 1996/10/28 18:31:03 kipp
|
|
* I fixed some problems in lexical analysis by writing SlidingBuffer.java and
|
|
* then switching the LexicalStream to use it instead of the LookAheadUnicodeInputStream
|
|
* class (which doesn't quite work).
|
|
*
|
|
*/
|
|
package netscape.plugin.composer.io;
|
|
|
|
import java.io.*;
|
|
|
|
/**
|
|
* A sliding buffer that moves over a Reader. The buffer
|
|
* is designed to support lexical analyzers.
|
|
*/
|
|
class SlidingBuffer extends Reader {
|
|
static final int DEFAULT_BUFFER_LENGTH = 4096;
|
|
|
|
// The underlying input stream
|
|
protected Reader in;
|
|
|
|
// The data buffer. buf[offset] is the next character to read.
|
|
// end is the offset of the last piece of data in the buffer, plus one
|
|
// end - offset is the number of characters in the buffer
|
|
protected char buffer[];
|
|
protected int offset;
|
|
protected int end;
|
|
|
|
public SlidingBuffer(Reader in) {
|
|
this.in = in;
|
|
buffer = new char[DEFAULT_BUFFER_LENGTH];
|
|
}
|
|
|
|
public SlidingBuffer(Reader in, int buflen) {
|
|
this.in = in;
|
|
if (buflen < DEFAULT_BUFFER_LENGTH) buflen = DEFAULT_BUFFER_LENGTH;
|
|
buffer = new char[buflen];
|
|
}
|
|
|
|
/**
|
|
* Reads a character of data. This method will block if no input is
|
|
* available.
|
|
* @return the byte read, or -1 if the end of the
|
|
* stream is reached.
|
|
* @exception IOException If an I/O error has occurred.
|
|
*/
|
|
public int read() throws IOException {
|
|
int amount = end - offset;
|
|
if (amount == 0) {
|
|
if (!fill()) return -1;
|
|
}
|
|
char c = buffer[offset++];
|
|
return c;
|
|
}
|
|
|
|
/**
|
|
* Reads into an array of characters. This method will
|
|
* block until some input is available.
|
|
* @param c the buffer into which the data is read
|
|
* @return the actual number of characters read, -1 is
|
|
* returned when the end of the stream is reached.
|
|
* @exception IOException If an I/O error has occurred.
|
|
*/
|
|
public int read(char c[]) throws IOException {
|
|
int amount = end - offset;
|
|
if (amount == 0) {
|
|
if (!fill()) return -1;
|
|
}
|
|
amount = end - offset;
|
|
if (amount > c.length) amount = c.length;
|
|
System.arraycopy(buffer, offset, c, 0, amount);
|
|
offset += amount;
|
|
return amount;
|
|
}
|
|
|
|
/**
|
|
* Reads into an array of characters. This method will
|
|
* block until some input is available.
|
|
* @param c the buffer into which the data is read
|
|
* @param off the start offset of the data
|
|
* @param len the maximum number of bytes read
|
|
* @return the actual number of characters read, -1 is
|
|
* returned when the end of the stream is reached.
|
|
* @exception IOException If an I/O error has occurred.
|
|
*/
|
|
public int read(char c[], int off, int len) throws IOException {
|
|
int amount = end - offset;
|
|
if (amount == 0) {
|
|
if (!fill()) return -1;
|
|
}
|
|
amount = end - offset;
|
|
if (amount > len) amount = len;
|
|
System.arraycopy(buffer, offset, c, off, amount);
|
|
offset += amount;
|
|
return amount;
|
|
}
|
|
|
|
/**
|
|
* Skips n bytes of input.
|
|
* @param n the number of characters to be skipped
|
|
* @return the actual number of characters skipped.
|
|
* @exception IOException If an I/O error has occurred.
|
|
*/
|
|
public long skip(long n) throws IOException {
|
|
int amount = end - offset;
|
|
if (amount >= n) {
|
|
offset += n;
|
|
return n;
|
|
}
|
|
offset = 0;
|
|
end = 0;
|
|
return amount + in.skip(n - amount);
|
|
}
|
|
|
|
///**
|
|
// * Returns the number of characters that can be read
|
|
// * without blocking.
|
|
// * @return the number of available characters.
|
|
// */
|
|
//public int available() throws IOException {
|
|
// return (end - offset) + in.available();
|
|
//}
|
|
|
|
/************************************************************************/
|
|
|
|
public int peek() throws IOException {
|
|
int amount = end - offset;
|
|
if (amount == 0) {
|
|
if (!fill()) return -1;
|
|
}
|
|
int c = buffer[offset];
|
|
return c;
|
|
}
|
|
|
|
/**
|
|
* Unread some characters. This will throw an IOException if the count
|
|
* being unread is larger than the amount of previously read data
|
|
* in the buffer.
|
|
*/
|
|
public void unread(int count) throws IOException {
|
|
if (offset < count) {
|
|
throw new IOException("invalid unread; offset=" + offset
|
|
+ " count=" + count);
|
|
}
|
|
offset -= count;
|
|
}
|
|
|
|
/**
|
|
* Look ahead one character. Return true if the next character matches
|
|
* (and consume the character), otherwise return false and leave the
|
|
* input stream unaffected.
|
|
*/
|
|
public boolean lookAhead(char c) throws IOException {
|
|
int amount = end - offset;
|
|
if (amount == 0) {
|
|
if (!fill()) return false;
|
|
}
|
|
if (buffer[offset] == c) {
|
|
offset++;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Look ahead for a string of characters. Each character in the string
|
|
* must match exactly otherwise false is returned (and the input stream
|
|
* is left unaffected).
|
|
*/
|
|
public boolean lookAhead(String s) throws IOException {
|
|
return lookAhead(s, false);
|
|
}
|
|
|
|
/**
|
|
* Look ahead for a string of characters allowing for case to not
|
|
* matter.
|
|
*/
|
|
public boolean lookAhead(String s, boolean ignoreCase) throws IOException {
|
|
int slen = s.length();
|
|
int amount = end - offset;
|
|
if (amount < slen) {
|
|
if (!fillForCapacity(slen)) return false;
|
|
}
|
|
for (int i = 0; i < slen; i++) {
|
|
char c1 = buffer[offset+i];
|
|
char c2 = s.charAt(i);
|
|
if (ignoreCase) {
|
|
c1 = Character.toLowerCase(c1);
|
|
c2 = Character.toLowerCase(c2);
|
|
}
|
|
if (c1 != c2) {
|
|
return false;
|
|
}
|
|
}
|
|
offset += slen;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Eat up any whitespace in the buffer. White space is defined as space,
|
|
* tab, return, newline, form feed. If any was eaten up return
|
|
* true, otherwise return false.
|
|
*/
|
|
/* XXX we can add an interface to specify a bitmap that defines
|
|
which characters we want to treat as whitespace... */
|
|
public boolean eatWhiteSpace() throws IOException {
|
|
boolean eaten = false;
|
|
for (;;) {
|
|
for (int i = offset; i < end; i++) {
|
|
char c = buffer[i];
|
|
if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n') ||
|
|
(c == '\f')) {
|
|
eaten = true;
|
|
continue;
|
|
}
|
|
offset = i;
|
|
return eaten;
|
|
}
|
|
if (!fill()) break;
|
|
}
|
|
return eaten;
|
|
}
|
|
|
|
/**
|
|
* Eat up one newline if present in the buffer. If a newline
|
|
* was eaten up return true otherwise false. This will handle
|
|
* mac (\r), unix (\n) and windows (\r\n) style of newlines
|
|
* transparently.
|
|
*/
|
|
public boolean eatNewline() throws IOException {
|
|
boolean eaten = false;
|
|
int amount = end - offset;
|
|
if (amount < 2) {
|
|
if (!fillForCapacity(2)) {
|
|
// Couldn't get two characters
|
|
if (end - offset == 0) {
|
|
return false;
|
|
}
|
|
if ((buffer[offset] == '\r') || (buffer[offset] == '\n')) {
|
|
offset++;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
if (buffer[offset] == '\r') {
|
|
offset++;
|
|
eaten = true;
|
|
}
|
|
if (buffer[offset] == '\n') {
|
|
eaten = true;
|
|
offset++;
|
|
}
|
|
return eaten;
|
|
}
|
|
|
|
/************************************************************************/
|
|
|
|
protected boolean fill() throws IOException {
|
|
if (end - offset != 0) {
|
|
throw new IOException("fill of non-empty buffer");
|
|
}
|
|
offset = 0;
|
|
end = in.read(buffer, 0, buffer.length);
|
|
if (end < 0) {
|
|
end = 0;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Fill the buffer, keeping whatever is unread in the buffer and
|
|
* ensuring that "capacity" characters of total filled buffer
|
|
* space is available. Return false if the final amount of data
|
|
* in the buffer is less than capacity, otherwise return true.
|
|
*/
|
|
protected boolean fillForCapacity(int capacity) throws IOException {
|
|
int amount = end - offset;
|
|
if (amount >= capacity) {
|
|
// The buffer already holds enough data to satisfy capacity
|
|
return true;
|
|
}
|
|
|
|
// The buffer needs more data. See if the buffer itself must be
|
|
// enlarged to statisfy capacity.
|
|
if (capacity >= buffer.length) {
|
|
// Grow the buffer to hold enough space
|
|
int newBufLen = buffer.length * 2;
|
|
if (newBufLen < capacity) newBufLen = capacity;
|
|
char newbuf[] = new char[newBufLen];
|
|
System.arraycopy(buffer, offset, newbuf, 0, amount);
|
|
offset = 0;
|
|
end = amount;
|
|
buffer = newbuf;
|
|
} else {
|
|
if (amount != 0) {
|
|
// Slide the data that is currently present in the buffer down
|
|
// to the start of the buffer
|
|
System.arraycopy(buffer, offset, buffer, 0, amount);
|
|
offset = 0;
|
|
end = amount;
|
|
}
|
|
}
|
|
|
|
// Fill up the remainder of the buffer
|
|
int mustRead = capacity - amount;
|
|
int nb = in.read(buffer, offset, buffer.length - offset);
|
|
if (nb < mustRead) {
|
|
if (nb > 0) {
|
|
end += nb;
|
|
}
|
|
return false;
|
|
}
|
|
end += nb;
|
|
return true;
|
|
}
|
|
|
|
public void close() throws IOException {
|
|
in.close();
|
|
}
|
|
}
|