[armedbear-cvs] r11400 - branches/open-external-format/src/org/armedbear/lisp/util

Erik Huelsmann ehuelsmann at common-lisp.net
Sat Nov 29 16:42:47 UTC 2008


Author: ehuelsmann
Date: Sat Nov 29 16:42:46 2008
New Revision: 11400

Log:
Set fixed line ending style.

Found by: Hideo

Modified:
   branches/open-external-format/src/org/armedbear/lisp/util/RandomAccessCharacterFile.java   (contents, props changed)

Modified: branches/open-external-format/src/org/armedbear/lisp/util/RandomAccessCharacterFile.java
==============================================================================
--- branches/open-external-format/src/org/armedbear/lisp/util/RandomAccessCharacterFile.java	(original)
+++ branches/open-external-format/src/org/armedbear/lisp/util/RandomAccessCharacterFile.java	Sat Nov 29 16:42:46 2008
@@ -1,446 +1,446 @@
-/*
- * RandomAccessCharacterFile.java
- *
- * Copyright (C) 2008 Hideo at Yokohama
- * Copyright (C) 2008 Erik Huelsmann
- * $Id$
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- * As a special exception, the copyright holders of this library give you
- * permission to link this library with independent modules to produce an
- * executable, regardless of the license terms of these independent
- * modules, and to copy and distribute the resulting executable under
- * terms of your choice, provided that you also meet, for each linked
- * independent module, the terms and conditions of the license of that
- * module.  An independent module is a module which is not derived from
- * or based on this library.  If you modify this library, you may extend
- * this exception to your version of the library, but you are not
- * obligated to do so.  If you do not wish to do so, delete this
- * exception statement from your version.
- */
-
-package org.armedbear.lisp.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.io.Reader;
-import java.io.Writer;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CoderResult;
-
-public class RandomAccessCharacterFile {
-
-        public class RandomAccessInputStream extends InputStream {
-
-                private RandomAccessCharacterFile racf;
-
-                public RandomAccessInputStream(RandomAccessCharacterFile racf) {
-                        this.racf = racf;
-                }
-                private byte[] buf = new byte[1];
-
-                public int read() throws IOException {
-                        int len = read(buf);
-                        if (len == 1) {
-                                // byte is signed, char is unsigned, int is signed.
-                                // buf can hold 0xff, we want it as 0xff in int, not -1.
-                                return 0xff & (int) buf[0];
-                        } else {
-                                return -1;
-                        }
-                }
-                
-                @Override
-                public int read(byte[] b, int off, int len) throws IOException {
-                        return racf.read(b, off, len);
-                }
-        }
-
-        public class RandomAccessOutputStream extends OutputStream {
-
-                private RandomAccessCharacterFile racf;
-
-                public RandomAccessOutputStream(RandomAccessCharacterFile racf) {
-                        this.racf = racf;
-                }
-
-                private byte[] buf = new byte[1];
-                public void write(int b) throws IOException {
-                        buf[0] = (byte)b;
-                        write(buf);
-                }
-
-                @Override
-                public void write(byte[] b, int off, int len) throws IOException {
-                        racf.write(b, off, len);
-                }
-        }
-
-        public class RandomAccessReader extends Reader {
-
-                private RandomAccessCharacterFile racf;
-
-                public RandomAccessReader(
-                                RandomAccessCharacterFile racf) {
-                        this.racf = racf;
-                }
-
-                public void close() throws IOException {
-                        racf.close();
-                }
-
-                public int read(char[] cb, int off, int len) throws IOException {
-                        return racf.read(cb, off, len);
-                }
-        }
-
-        public class RandomAccessWriter extends Writer {
-
-                private RandomAccessCharacterFile racf;
-
-                public RandomAccessWriter(
-                                RandomAccessCharacterFile racf) {
-                        this.racf = racf;
-                }
-
-                public void close() throws IOException {
-                        racf.close();
-                }
-
-                public void flush() throws IOException {
-                        racf.flush();
-                }
-
-                public void write(char[] cb, int off, int len) throws IOException {
-                        racf.write(cb, off, len);
-                }
-
-        }
-
-
-	final static int BUFSIZ = 4*1024; // setting this to a small value like 8 is helpful for testing.
-	
-	private RandomAccessWriter writer;
-	private RandomAccessReader reader;
-	private RandomAccessInputStream inputStream;
-	private RandomAccessOutputStream outputStream;
-	private FileChannel fcn;
-	private long fcnpos; /* where fcn is pointing now. */
-	private long fcnsize; /* the file size */
-	
-	private Charset cset;
-	private CharsetEncoder cenc;
-	private CharsetDecoder cdec;
-	
-	/**
-	 * bbuf is treated as a cache of the file content.
-	 * If it points to somewhere in the middle of the file, it holds the copy of the file content,
-	 * even when you are writing a large chunk of data.  If you write in the middle of a file,
-	 * bbuf first gets filled with contents of the data, and only after that any new data is
-	 * written on bbuf.
-	 * The exception is when you are appending data at the end of the file.
-	 */
-	private ByteBuffer bbuf;
-	private boolean bbufIsDirty; /* whether bbuf holds data that must be written. */
-	private long bbufpos; /* where the beginning of bbuf is pointing in the file now. */
-
-	public RandomAccessCharacterFile(RandomAccessFile raf, String encoding) throws IOException {
-		fcn = raf.getChannel();
-		fcnpos = 0; // fcn points at BOF.
-		fcnsize = fcn.size();
-		
-		cset = Charset.forName(encoding);
-		cdec = cset.newDecoder();
-		cenc = cset.newEncoder(); 
-		
-		bbuf = ByteBuffer.allocate(BUFSIZ);
-		
-		// there is no readable data available in the buffers.
-		bbuf.flip();
-		
-		// there is no write pending data in the buffers.
-		bbufIsDirty = false;
-		
-		bbufpos = fcn.position(); // so as the byte buffer.
-
-		reader = new RandomAccessReader(this);
-		writer = new RandomAccessWriter(this);
-		inputStream = new RandomAccessInputStream(this);
-		outputStream = new RandomAccessOutputStream(this);
-	}
-	
-	public Writer getWriter() {
-		return writer;
-	}
-	
-	public Reader getReader() {
-		return reader;
-	}
-	
-	public InputStream getInputStream() {
-		return inputStream;
-	}
-	
-	public OutputStream getOutputStream() {
-		return outputStream;
-	}
-	
-	public void close() throws IOException {
-		internalFlush(true);
-		fcn.close();
-	}
-	
-	public void flush() throws IOException {
-		internalFlush(false);
-	}
-
-	public int read(char[] cb, int off, int len) throws IOException {
-		CharBuffer cbuf = CharBuffer.wrap(cb, off, len);
-		boolean decodeWasUnderflow = false;
-                boolean atEof = false;
-		while ((cbuf.remaining() > 0) && dataIsAvailableForRead()
-                        && ! atEof) {
-			if ((bbuf.remaining() == 0) || decodeWasUnderflow) {
-				// need to read from the file.
-				flushBbuf(); // in case bbuf is dirty.
-				// update bbufpos.
-				bbufpos += bbuf.position();
-				int partialBytes = bbuf.remaining(); // partialBytes > 0 happens when decodeWasUnderflow
-				// if reads and writes are mixed, we may need to seek first.
-				if (bbufpos + partialBytes != fcnpos) {
-					fcn.position(bbufpos + partialBytes);
-				}
-				// need to read data from file.
-				bbuf.compact();
-                                //###FIXME: we're ignoring end-of-stream here!!!
-				atEof = (fcn.read(bbuf) == -1);
-				bbuf.flip();
-				fcnpos = bbufpos + bbuf.remaining();
-			}
-			CoderResult r = cdec.decode(bbuf, cbuf, pointingAtEOF() );
-			decodeWasUnderflow = (CoderResult.UNDERFLOW == r);
-		}
-		if (cbuf.remaining() == len) {
-			return -1;
-		} else {
-			return len - cbuf.remaining();
-		}
-	}
-
-	public boolean dataIsAvailableForRead() throws IOException {
-		return ((bbuf.remaining() > 0) || (fcn.position() < fcn.size()));
-	}
-	
-	private boolean pointingAtEOF() {
-		return (bbuf.remaining() == 0) && (fcnpos == fcnsize);
-	}
-
-	public void write(char[] cb, int off, int len) throws IOException {
-		CharBuffer cbuf = CharBuffer.wrap(cb, off, len);
-		encodeAndWrite(cbuf, false, false);
-	}
-
-	private void internalFlush(boolean endOfFile) throws IOException {
-		if (endOfFile) {
-			CharBuffer cbuf = CharBuffer.allocate(0);
-			encodeAndWrite(cbuf, true, endOfFile);
-		} else {
-			flushBbuf();
-		}
-	}
-
-	private void encodeAndWrite(CharBuffer cbuf, boolean flush, boolean endOfFile) throws IOException {
-		if (bbufpos == fcnsize) {
-			bbuf.clear();
-		}
-		while (cbuf.remaining() > 0) {
-			CoderResult r = cenc.encode(cbuf, bbuf, endOfFile);
-			bbufIsDirty = true;
-			long curpos = bbufpos + bbuf.position();
-			if (curpos > fcnsize) {
-				// the file is extended.
-				fcnsize = curpos;
-			}
-			if (CoderResult.OVERFLOW == r || bbuf.remaining() == 0) {
-				flushBbuf();
-				bbufpos += bbuf.limit();
-				bbuf.clear();
-				if (fcnpos < fcnsize) {
-					fcn.read(bbuf);
-					bbuf.flip();
-					fcnpos += bbuf.remaining();
-				}
-				// if we are at the end of file, bbuf is simply cleared.
-				// in that case, bbufpos + bbuf.position points to the EOF, not fcnpos. 
-			}
-		}
-		if (bbuf.position() > 0 && bbufIsDirty && flush) {
-			flushBbuf();
-		}
-	}
-
-	public void position(long newPosition) throws IOException {
-                flushBbuf();
-		long bbufend = bbufpos + bbuf.limit();
-		if (newPosition >= bbufpos && newPosition < bbufend) {
-			// near seek. within existing data of bbuf.
-			bbuf.position((int)(newPosition - bbufpos));
-		} else {
-			// far seek. discard the buffer.
-			flushBbuf();
-			fcn.position(newPosition);
-			fcnpos = newPosition;
-			bbuf.clear();
-			bbuf.flip(); // "there is no useful data on this buffer yet."
-			bbufpos = fcnpos;
-		}
-	}
-	
-	public long position() throws IOException {
-                flushBbuf();
-		return bbufpos + bbuf.position(); // the logical position within the file.
-	}
-
-        public long length() throws IOException {
-            flushBbuf();
-            return fcn.size();
-        }
-        
-	private void flushBbuf() throws IOException {
-		if (bbufIsDirty) {
-			if (fcnpos != bbufpos) {
-				fcn.position(bbufpos);
-			}
-			bbuf.position(0);
-			if (bbufpos + bbuf.limit() > fcnsize) {
-				// the buffer is at the end of the file.
-				// area beyond fcnsize does not have data.
-				bbuf.limit((int)(fcnsize - bbufpos));
-			}
-			fcn.write(bbuf);
-			fcnpos = bbufpos + bbuf.limit();
-			bbufIsDirty = false;
-		}
-	}
-
-	public int read(byte[] b, int off, int len) throws IOException {
-		int pos = off;
-                boolean atEof = false;
-		while (pos - off < len && dataIsAvailableForRead()
-                        && ! atEof) {
-			if (bbuf.remaining() == 0) {
-				// need to read from the file.
-				flushBbuf(); // in case bbuf is dirty.
-				// update bbufpos.
-				bbufpos += bbuf.limit();
-				// if reads and writes are mixed, we may need to seek first.
-				if (bbufpos != fcnpos) {
-					fcn.position(bbufpos);
-				}
-				// need to read data from file.
-				bbuf.clear();
-				atEof = (fcn.read(bbuf) == -1);
-				bbuf.flip();
-				fcnpos = bbufpos + bbuf.remaining();
-			}
-			int want = len - pos;
-			if (want > bbuf.remaining()) {
-				want = bbuf.remaining();
-			}
-			bbuf.get(b, pos, want);
-			pos += want;
-		}
-		return pos - off;
-	}
-        
-	// a method corresponding to the good ol' ungetc in C.
-	// This function may fail when using (combined) character codes that use
-	// escape sequences to switch between sub-codes.
-	// ASCII, ISO-8859 series, any 8bit code are OK, all unicode variations are OK,
-	// but applications of the ISO-2022 encoding framework can have trouble.
-	// Example of such code is ISO-2022-JP which is used in Japanese e-mail.
-	private CharBuffer singleCharBuf;
-	private ByteBuffer shortByteBuf;
-	public void unreadChar(char c) throws IOException {
-		// algorithm : 
-		//  1. encode c into bytes, to find out how many bytes it corresponds to
-		//  2. move the position backwards that many bytes.
-		//  ** we stop here.  Don't bother to write the bytes to the buffer,
-		//     assuming that it is the same as the original data.
-		//     If we allow to write back different characters, the buffer must get 'dirty'
-		//     but that would require read/write permissions on files you use unreadChar,
-		//     even if you are just reading for some tokenizer.
-		//
-		//  So we don't do the following.
-		//  3. write the bytes.
-		//  4. move the position back again.
-		if (singleCharBuf == null) {
-			singleCharBuf = CharBuffer.allocate(1);
-			shortByteBuf = ByteBuffer.allocate((int)cenc.maxBytesPerChar());
-		}
-		singleCharBuf.clear();
-		singleCharBuf.append(c);
-		singleCharBuf.flip();
-		shortByteBuf.clear();
-		cenc.encode(singleCharBuf, shortByteBuf, false);
-		int n = shortByteBuf.position();
-		long pos = position() - n;
-		position(pos);
-	}
-	
-	public void unreadByte(byte b) throws IOException {
-		long pos = position() - 1;
-		position(pos);
-	}
-
-	public void write(byte[] b, int off, int len) throws IOException {
-		int pos = off;
-		while (pos < off + len) {
-			int want = len;
-			if (want > bbuf.remaining()) {
-				want = bbuf.remaining();
-			}
-			bbuf.put(b, pos, want);
-			pos += want;
-			bbufIsDirty = true;
-			long curpos = bbufpos + bbuf.position();
-			if (curpos > fcn.size()) {
-				// the file is extended.
-				fcnsize = curpos;
-			}
-			if (bbuf.remaining() == 0) {
-				flushBbuf();
-				bbufpos += bbuf.limit();
-				bbuf.clear();
-				if (fcn.position() < fcn.size()) {
-                                        bbufpos = fcn.position();
-					fcn.read(bbuf);
-					bbuf.flip();
-					fcnpos += bbuf.remaining();
-				}
-				// if we are at the end of file, bbuf is simply cleared.
-				// in that case, bbufpos + bbuf.position points to the EOF, not fcnpos. 
-			}
-		}
-	}
-}
+/*
+ * RandomAccessCharacterFile.java
+ *
+ * Copyright (C) 2008 Hideo at Yokohama
+ * Copyright (C) 2008 Erik Huelsmann
+ * $Id$
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * As a special exception, the copyright holders of this library give you
+ * permission to link this library with independent modules to produce an
+ * executable, regardless of the license terms of these independent
+ * modules, and to copy and distribute the resulting executable under
+ * terms of your choice, provided that you also meet, for each linked
+ * independent module, the terms and conditions of the license of that
+ * module.  An independent module is a module which is not derived from
+ * or based on this library.  If you modify this library, you may extend
+ * this exception to your version of the library, but you are not
+ * obligated to do so.  If you do not wish to do so, delete this
+ * exception statement from your version.
+ */
+
+package org.armedbear.lisp.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+
+public class RandomAccessCharacterFile {
+
+        public class RandomAccessInputStream extends InputStream {
+
+                private RandomAccessCharacterFile racf;
+
+                public RandomAccessInputStream(RandomAccessCharacterFile racf) {
+                        this.racf = racf;
+                }
+                private byte[] buf = new byte[1];
+
+                public int read() throws IOException {
+                        int len = read(buf);
+                        if (len == 1) {
+                                // byte is signed, char is unsigned, int is signed.
+                                // buf can hold 0xff, we want it as 0xff in int, not -1.
+                                return 0xff & (int) buf[0];
+                        } else {
+                                return -1;
+                        }
+                }
+                
+                @Override
+                public int read(byte[] b, int off, int len) throws IOException {
+                        return racf.read(b, off, len);
+                }
+        }
+
+        public class RandomAccessOutputStream extends OutputStream {
+
+                private RandomAccessCharacterFile racf;
+
+                public RandomAccessOutputStream(RandomAccessCharacterFile racf) {
+                        this.racf = racf;
+                }
+
+                private byte[] buf = new byte[1];
+                public void write(int b) throws IOException {
+                        buf[0] = (byte)b;
+                        write(buf);
+                }
+
+                @Override
+                public void write(byte[] b, int off, int len) throws IOException {
+                        racf.write(b, off, len);
+                }
+        }
+
+        public class RandomAccessReader extends Reader {
+
+                private RandomAccessCharacterFile racf;
+
+                public RandomAccessReader(
+                                RandomAccessCharacterFile racf) {
+                        this.racf = racf;
+                }
+
+                public void close() throws IOException {
+                        racf.close();
+                }
+
+                public int read(char[] cb, int off, int len) throws IOException {
+                        return racf.read(cb, off, len);
+                }
+        }
+
+        public class RandomAccessWriter extends Writer {
+
+                private RandomAccessCharacterFile racf;
+
+                public RandomAccessWriter(
+                                RandomAccessCharacterFile racf) {
+                        this.racf = racf;
+                }
+
+                public void close() throws IOException {
+                        racf.close();
+                }
+
+                public void flush() throws IOException {
+                        racf.flush();
+                }
+
+                public void write(char[] cb, int off, int len) throws IOException {
+                        racf.write(cb, off, len);
+                }
+
+        }
+
+
+	final static int BUFSIZ = 4*1024; // setting this to a small value like 8 is helpful for testing.
+	
+	private RandomAccessWriter writer;
+	private RandomAccessReader reader;
+	private RandomAccessInputStream inputStream;
+	private RandomAccessOutputStream outputStream;
+	private FileChannel fcn;
+	private long fcnpos; /* where fcn is pointing now. */
+	private long fcnsize; /* the file size */
+	
+	private Charset cset;
+	private CharsetEncoder cenc;
+	private CharsetDecoder cdec;
+	
+	/**
+	 * bbuf is treated as a cache of the file content.
+	 * If it points to somewhere in the middle of the file, it holds the copy of the file content,
+	 * even when you are writing a large chunk of data.  If you write in the middle of a file,
+	 * bbuf first gets filled with contents of the data, and only after that any new data is
+	 * written on bbuf.
+	 * The exception is when you are appending data at the end of the file.
+	 */
+	private ByteBuffer bbuf;
+	private boolean bbufIsDirty; /* whether bbuf holds data that must be written. */
+	private long bbufpos; /* where the beginning of bbuf is pointing in the file now. */
+
+	public RandomAccessCharacterFile(RandomAccessFile raf, String encoding) throws IOException {
+		fcn = raf.getChannel();
+		fcnpos = 0; // fcn points at BOF.
+		fcnsize = fcn.size();
+		
+		cset = Charset.forName(encoding);
+		cdec = cset.newDecoder();
+		cenc = cset.newEncoder(); 
+		
+		bbuf = ByteBuffer.allocate(BUFSIZ);
+		
+		// there is no readable data available in the buffers.
+		bbuf.flip();
+		
+		// there is no write pending data in the buffers.
+		bbufIsDirty = false;
+		
+		bbufpos = fcn.position(); // so as the byte buffer.
+
+		reader = new RandomAccessReader(this);
+		writer = new RandomAccessWriter(this);
+		inputStream = new RandomAccessInputStream(this);
+		outputStream = new RandomAccessOutputStream(this);
+	}
+	
+	public Writer getWriter() {
+		return writer;
+	}
+	
+	public Reader getReader() {
+		return reader;
+	}
+	
+	public InputStream getInputStream() {
+		return inputStream;
+	}
+	
+	public OutputStream getOutputStream() {
+		return outputStream;
+	}
+	
+	public void close() throws IOException {
+		internalFlush(true);
+		fcn.close();
+	}
+	
+	public void flush() throws IOException {
+		internalFlush(false);
+	}
+
+	public int read(char[] cb, int off, int len) throws IOException {
+		CharBuffer cbuf = CharBuffer.wrap(cb, off, len);
+		boolean decodeWasUnderflow = false;
+                boolean atEof = false;
+		while ((cbuf.remaining() > 0) && dataIsAvailableForRead()
+                        && ! atEof) {
+			if ((bbuf.remaining() == 0) || decodeWasUnderflow) {
+				// need to read from the file.
+				flushBbuf(); // in case bbuf is dirty.
+				// update bbufpos.
+				bbufpos += bbuf.position();
+				int partialBytes = bbuf.remaining(); // partialBytes > 0 happens when decodeWasUnderflow
+				// if reads and writes are mixed, we may need to seek first.
+				if (bbufpos + partialBytes != fcnpos) {
+					fcn.position(bbufpos + partialBytes);
+				}
+				// need to read data from file.
+				bbuf.compact();
+                                //###FIXME: we're ignoring end-of-stream here!!!
+				atEof = (fcn.read(bbuf) == -1);
+				bbuf.flip();
+				fcnpos = bbufpos + bbuf.remaining();
+			}
+			CoderResult r = cdec.decode(bbuf, cbuf, pointingAtEOF() );
+			decodeWasUnderflow = (CoderResult.UNDERFLOW == r);
+		}
+		if (cbuf.remaining() == len) {
+			return -1;
+		} else {
+			return len - cbuf.remaining();
+		}
+	}
+
+	public boolean dataIsAvailableForRead() throws IOException {
+		return ((bbuf.remaining() > 0) || (fcn.position() < fcn.size()));
+	}
+	
+	private boolean pointingAtEOF() {
+		return (bbuf.remaining() == 0) && (fcnpos == fcnsize);
+	}
+
+	public void write(char[] cb, int off, int len) throws IOException {
+		CharBuffer cbuf = CharBuffer.wrap(cb, off, len);
+		encodeAndWrite(cbuf, false, false);
+	}
+
+	private void internalFlush(boolean endOfFile) throws IOException {
+		if (endOfFile) {
+			CharBuffer cbuf = CharBuffer.allocate(0);
+			encodeAndWrite(cbuf, true, endOfFile);
+		} else {
+			flushBbuf();
+		}
+	}
+
+	private void encodeAndWrite(CharBuffer cbuf, boolean flush, boolean endOfFile) throws IOException {
+		if (bbufpos == fcnsize) {
+			bbuf.clear();
+		}
+		while (cbuf.remaining() > 0) {
+			CoderResult r = cenc.encode(cbuf, bbuf, endOfFile);
+			bbufIsDirty = true;
+			long curpos = bbufpos + bbuf.position();
+			if (curpos > fcnsize) {
+				// the file is extended.
+				fcnsize = curpos;
+			}
+			if (CoderResult.OVERFLOW == r || bbuf.remaining() == 0) {
+				flushBbuf();
+				bbufpos += bbuf.limit();
+				bbuf.clear();
+				if (fcnpos < fcnsize) {
+					fcn.read(bbuf);
+					bbuf.flip();
+					fcnpos += bbuf.remaining();
+				}
+				// if we are at the end of file, bbuf is simply cleared.
+				// in that case, bbufpos + bbuf.position points to the EOF, not fcnpos. 
+			}
+		}
+		if (bbuf.position() > 0 && bbufIsDirty && flush) {
+			flushBbuf();
+		}
+	}
+
+	public void position(long newPosition) throws IOException {
+                flushBbuf();
+		long bbufend = bbufpos + bbuf.limit();
+		if (newPosition >= bbufpos && newPosition < bbufend) {
+			// near seek. within existing data of bbuf.
+			bbuf.position((int)(newPosition - bbufpos));
+		} else {
+			// far seek. discard the buffer.
+			flushBbuf();
+			fcn.position(newPosition);
+			fcnpos = newPosition;
+			bbuf.clear();
+			bbuf.flip(); // "there is no useful data on this buffer yet."
+			bbufpos = fcnpos;
+		}
+	}
+	
+	public long position() throws IOException {
+                flushBbuf();
+		return bbufpos + bbuf.position(); // the logical position within the file.
+	}
+
+        public long length() throws IOException {
+            flushBbuf();
+            return fcn.size();
+        }
+        
+	private void flushBbuf() throws IOException {
+		if (bbufIsDirty) {
+			if (fcnpos != bbufpos) {
+				fcn.position(bbufpos);
+			}
+			bbuf.position(0);
+			if (bbufpos + bbuf.limit() > fcnsize) {
+				// the buffer is at the end of the file.
+				// area beyond fcnsize does not have data.
+				bbuf.limit((int)(fcnsize - bbufpos));
+			}
+			fcn.write(bbuf);
+			fcnpos = bbufpos + bbuf.limit();
+			bbufIsDirty = false;
+		}
+	}
+
+	public int read(byte[] b, int off, int len) throws IOException {
+		int pos = off;
+                boolean atEof = false;
+		while (pos - off < len && dataIsAvailableForRead()
+                        && ! atEof) {
+			if (bbuf.remaining() == 0) {
+				// need to read from the file.
+				flushBbuf(); // in case bbuf is dirty.
+				// update bbufpos.
+				bbufpos += bbuf.limit();
+				// if reads and writes are mixed, we may need to seek first.
+				if (bbufpos != fcnpos) {
+					fcn.position(bbufpos);
+				}
+				// need to read data from file.
+				bbuf.clear();
+				atEof = (fcn.read(bbuf) == -1);
+				bbuf.flip();
+				fcnpos = bbufpos + bbuf.remaining();
+			}
+			int want = len - pos;
+			if (want > bbuf.remaining()) {
+				want = bbuf.remaining();
+			}
+			bbuf.get(b, pos, want);
+			pos += want;
+		}
+		return pos - off;
+	}
+        
+	// a method corresponding to the good ol' ungetc in C.
+	// This function may fail when using (combined) character codes that use
+	// escape sequences to switch between sub-codes.
+	// ASCII, ISO-8859 series, any 8bit code are OK, all unicode variations are OK,
+	// but applications of the ISO-2022 encoding framework can have trouble.
+	// Example of such code is ISO-2022-JP which is used in Japanese e-mail.
+	private CharBuffer singleCharBuf;
+	private ByteBuffer shortByteBuf;
+	public void unreadChar(char c) throws IOException {
+		// algorithm : 
+		//  1. encode c into bytes, to find out how many bytes it corresponds to
+		//  2. move the position backwards that many bytes.
+		//  ** we stop here.  Don't bother to write the bytes to the buffer,
+		//     assuming that it is the same as the original data.
+		//     If we allow to write back different characters, the buffer must get 'dirty'
+		//     but that would require read/write permissions on files you use unreadChar,
+		//     even if you are just reading for some tokenizer.
+		//
+		//  So we don't do the following.
+		//  3. write the bytes.
+		//  4. move the position back again.
+		if (singleCharBuf == null) {
+			singleCharBuf = CharBuffer.allocate(1);
+			shortByteBuf = ByteBuffer.allocate((int)cenc.maxBytesPerChar());
+		}
+		singleCharBuf.clear();
+		singleCharBuf.append(c);
+		singleCharBuf.flip();
+		shortByteBuf.clear();
+		cenc.encode(singleCharBuf, shortByteBuf, false);
+		int n = shortByteBuf.position();
+		long pos = position() - n;
+		position(pos);
+	}
+	
+	public void unreadByte(byte b) throws IOException {
+		long pos = position() - 1;
+		position(pos);
+	}
+
+	public void write(byte[] b, int off, int len) throws IOException {
+		int pos = off;
+		while (pos < off + len) {
+			int want = len;
+			if (want > bbuf.remaining()) {
+				want = bbuf.remaining();
+			}
+			bbuf.put(b, pos, want);
+			pos += want;
+			bbufIsDirty = true;
+			long curpos = bbufpos + bbuf.position();
+			if (curpos > fcn.size()) {
+				// the file is extended.
+				fcnsize = curpos;
+			}
+			if (bbuf.remaining() == 0) {
+				flushBbuf();
+				bbufpos += bbuf.limit();
+				bbuf.clear();
+				if (fcn.position() < fcn.size()) {
+                                        bbufpos = fcn.position();
+					fcn.read(bbuf);
+					bbuf.flip();
+					fcnpos += bbuf.remaining();
+				}
+				// if we are at the end of file, bbuf is simply cleared.
+				// in that case, bbufpos + bbuf.position points to the EOF, not fcnpos. 
+			}
+		}
+	}
+}




More information about the armedbear-cvs mailing list