-/*******************************************************************************\r
- * Copyright (c) 2010 Ericsson\r
- *\r
- * All rights reserved. This program and the accompanying materials are\r
- * made available under the terms of the Eclipse Public License v1.0 which\r
- * accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * Patrick Tasse - Initial API and implementation, based on article by Nick Zhang\r
- * (http://www.javaworld.com/javatips/jw-javatip26.html)\r
- ******************************************************************************/\r
-\r
-package org.eclipse.linuxtools.tmf.core.io;\r
-\r
-import java.io.File;\r
-import java.io.IOException;\r
-import java.io.RandomAccessFile;\r
-import java.nio.charset.Charset;\r
-\r
-/**\r
- * A class to mitigate the Java I/O inefficiency of RandomAccessFile.\r
- *\r
- * @version 1.0\r
- * @author Patrick Tasse\r
- */\r
-public class BufferedRandomAccessFile extends RandomAccessFile {\r
-\r
- private static final int DEFAULT_BUF_SIZE = 8192;\r
- private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8"); //$NON-NLS-1$\r
-\r
- final int BUF_SIZE;\r
- byte buffer[];\r
- int buf_end = 0;\r
- int buf_pos = 0;\r
- long real_pos = 0;\r
- StringBuilder sb = new StringBuilder();\r
-\r
- /**\r
- * Constructor using the default buffer size\r
- *\r
- * @param name\r
- * File path. This is passed as-is to the RandomeAccessFile's\r
- * constructor.\r
- * @param mode\r
- * File open mode ("r", "rw", etc.). This is passed as-is to\r
- * RandomAccessFile's constructor.\r
- * @throws IOException\r
- * If the file was not found or couldn't be opened with the\r
- * request permissions\r
- */\r
- public BufferedRandomAccessFile(String name, String mode) throws IOException {\r
- this(name, mode, DEFAULT_BUF_SIZE);\r
- }\r
-\r
- /**\r
- * Constructor using the default buffer size\r
- *\r
- * @param file\r
- * File object. This is passed as-is to the RandomeAccessFile's\r
- * constructor.\r
- * @param mode\r
- * File open mode ("r", "rw", etc.). This is passed as-is to\r
- * RandomAccessFile's constructor.\r
- * @throws IOException\r
- * If the file was not found or couldn't be opened with the\r
- * request permissions\r
- */\r
- public BufferedRandomAccessFile(File file, String mode) throws IOException {\r
- this(file, mode, DEFAULT_BUF_SIZE);\r
- }\r
-\r
- /**\r
- * Standard constructor.\r
- *\r
- * @param name\r
- * File path. This is passed as-is to the RandomeAccessFile's\r
- * constructor.\r
- * @param mode\r
- * File open mode ("r", "rw", etc.). This is passed as-is to\r
- * RandomAccessFile's constructor.\r
- * @param bufsize\r
- * Buffer size to use, in bytes\r
- * @throws IOException\r
- * If the file was not found or couldn't be opened with the\r
- * request permissions\r
- */\r
- public BufferedRandomAccessFile(String name, String mode, int bufsize) throws IOException {\r
- super(name, mode);\r
- invalidate();\r
- BUF_SIZE = bufsize;\r
- buffer = new byte[BUF_SIZE];\r
- }\r
-\r
- /**\r
- * Standard constructor.\r
- *\r
- * @param file\r
- * File object. This is passed as-is to the RandomeAccessFile's\r
- * constructor.\r
- * @param mode\r
- * File open mode ("r", "rw", etc.). This is passed as-is to\r
- * RandomAccessFile's constructor.\r
- * @param bufsize\r
- * Buffer size to use, in bytes\r
- * @throws IOException\r
- * If the file was not found or couldn't be opened with the\r
- * request permissions\r
- */\r
- public BufferedRandomAccessFile(File file, String mode, int bufsize) throws IOException {\r
- super(file, mode);\r
- invalidate();\r
- BUF_SIZE = bufsize;\r
- buffer = new byte[BUF_SIZE];\r
- }\r
-\r
- @Override\r
- public final int read() throws IOException{\r
- if (buf_pos >= buf_end) {\r
- if (fillBuffer() < 0) {\r
- return -1;\r
- }\r
- }\r
- if (buf_end == 0) {\r
- return -1;\r
- }\r
- return buffer[buf_pos++];\r
- }\r
-\r
- @Override\r
- public int read(byte b[], int off, int len) throws IOException {\r
- int leftover = buf_end - buf_pos;\r
- if (len <= leftover) {\r
- System.arraycopy(buffer, buf_pos, b, off, len);\r
- buf_pos += len;\r
- return len;\r
- }\r
- for(int i = 0; i < len; i++) {\r
- int c = this.read();\r
- if (c != -1) {\r
- b[off+i] = (byte) c;\r
- } else {\r
- return i;\r
- }\r
- }\r
- return len;\r
- }\r
-\r
- @Override\r
- public long getFilePointer() throws IOException{\r
- long l = real_pos;\r
- return (l - buf_end + buf_pos);\r
- }\r
-\r
- @Override\r
- public void seek(long pos) throws IOException {\r
- int n = (int) (real_pos - pos);\r
- if(n >= 0 && n <= buf_end) {\r
- buf_pos = buf_end - n;\r
- } else {\r
- super.seek(pos);\r
- invalidate();\r
- }\r
- }\r
-\r
- /**\r
- * Read the next line from the buffer (ie, until the next '\n'). The bytes\r
- * are interpreted as UTF-8 characters.\r
- *\r
- * @return The String that was read\r
- * @throws IOException\r
- * If we failed reading the file\r
- */\r
- public final String getNextLine() throws IOException {\r
- String str = null;\r
- if (buf_end - buf_pos <= 0) {\r
- if (fillBuffer() < 0) {\r
- return null;\r
- }\r
- }\r
- int lineend = -1;\r
- for (int i = buf_pos; i < buf_end; i++) {\r
- if (buffer[i] == '\n') {\r
- lineend = i;\r
- break;\r
- }\r
- }\r
- if (lineend < 0) {\r
- sb.delete(0, sb.length());\r
- int c;\r
- while (((c = read()) != -1) && (c != '\n')) {\r
- sb.append((char) c);\r
- }\r
- if ((c == -1) && (sb.length() == 0)) {\r
- return null;\r
- }\r
- if (sb.charAt(sb.length() - 1) == '\r') {\r
- sb.deleteCharAt(sb.length() - 1);\r
- }\r
- return sb.toString();\r
- }\r
- if (lineend > 0 && buffer[lineend - 1] == '\r' && lineend > buf_pos) {\r
- str = new String(buffer, buf_pos, lineend - buf_pos - 1, CHARSET_UTF8);\r
- } else {\r
- str = new String(buffer, buf_pos, lineend - buf_pos, CHARSET_UTF8);\r
- }\r
- buf_pos = lineend + 1;\r
- return str;\r
- }\r
-\r
- private int fillBuffer() throws IOException {\r
- int n = super.read(buffer, 0, BUF_SIZE);\r
- if (n >= 0) {\r
- real_pos += n;\r
- buf_end = n;\r
- buf_pos = 0;\r
- }\r
- return n;\r
- }\r
-\r
- private void invalidate() throws IOException {\r
- buf_end = 0;\r
- buf_pos = 0;\r
- real_pos = super.getFilePointer();\r
- }\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2010 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation, based on article by Nick Zhang
+ * (http://www.javaworld.com/javatips/jw-javatip26.html)
+ ******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.charset.Charset;
+
+/**
+ * A class to mitigate the Java I/O inefficiency of RandomAccessFile.
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class BufferedRandomAccessFile extends RandomAccessFile {
+
+ private static final int DEFAULT_BUF_SIZE = 8192;
+ private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8"); //$NON-NLS-1$
+
+ final int BUF_SIZE;
+ byte buffer[];
+ int buf_end = 0;
+ int buf_pos = 0;
+ long real_pos = 0;
+ StringBuilder sb = new StringBuilder();
+
+ /**
+ * Constructor using the default buffer size
+ *
+ * @param name
+ * File path. This is passed as-is to the RandomeAccessFile's
+ * constructor.
+ * @param mode
+ * File open mode ("r", "rw", etc.). This is passed as-is to
+ * RandomAccessFile's constructor.
+ * @throws IOException
+ * If the file was not found or couldn't be opened with the
+ * request permissions
+ */
+ public BufferedRandomAccessFile(String name, String mode) throws IOException {
+ this(name, mode, DEFAULT_BUF_SIZE);
+ }
+
+ /**
+ * Constructor using the default buffer size
+ *
+ * @param file
+ * File object. This is passed as-is to the RandomeAccessFile's
+ * constructor.
+ * @param mode
+ * File open mode ("r", "rw", etc.). This is passed as-is to
+ * RandomAccessFile's constructor.
+ * @throws IOException
+ * If the file was not found or couldn't be opened with the
+ * request permissions
+ */
+ public BufferedRandomAccessFile(File file, String mode) throws IOException {
+ this(file, mode, DEFAULT_BUF_SIZE);
+ }
+
+ /**
+ * Standard constructor.
+ *
+ * @param name
+ * File path. This is passed as-is to the RandomeAccessFile's
+ * constructor.
+ * @param mode
+ * File open mode ("r", "rw", etc.). This is passed as-is to
+ * RandomAccessFile's constructor.
+ * @param bufsize
+ * Buffer size to use, in bytes
+ * @throws IOException
+ * If the file was not found or couldn't be opened with the
+ * request permissions
+ */
+ public BufferedRandomAccessFile(String name, String mode, int bufsize) throws IOException {
+ super(name, mode);
+ invalidate();
+ BUF_SIZE = bufsize;
+ buffer = new byte[BUF_SIZE];
+ }
+
+ /**
+ * Standard constructor.
+ *
+ * @param file
+ * File object. This is passed as-is to the RandomeAccessFile's
+ * constructor.
+ * @param mode
+ * File open mode ("r", "rw", etc.). This is passed as-is to
+ * RandomAccessFile's constructor.
+ * @param bufsize
+ * Buffer size to use, in bytes
+ * @throws IOException
+ * If the file was not found or couldn't be opened with the
+ * request permissions
+ */
+ public BufferedRandomAccessFile(File file, String mode, int bufsize) throws IOException {
+ super(file, mode);
+ invalidate();
+ BUF_SIZE = bufsize;
+ buffer = new byte[BUF_SIZE];
+ }
+
+ @Override
+ public final int read() throws IOException{
+ if (buf_pos >= buf_end) {
+ if (fillBuffer() < 0) {
+ return -1;
+ }
+ }
+ if (buf_end == 0) {
+ return -1;
+ }
+ return buffer[buf_pos++];
+ }
+
+ @Override
+ public int read(byte b[], int off, int len) throws IOException {
+ int leftover = buf_end - buf_pos;
+ if (len <= leftover) {
+ System.arraycopy(buffer, buf_pos, b, off, len);
+ buf_pos += len;
+ return len;
+ }
+ for(int i = 0; i < len; i++) {
+ int c = this.read();
+ if (c != -1) {
+ b[off+i] = (byte) c;
+ } else {
+ return i;
+ }
+ }
+ return len;
+ }
+
+ @Override
+ public long getFilePointer() throws IOException{
+ long l = real_pos;
+ return (l - buf_end + buf_pos);
+ }
+
+ @Override
+ public void seek(long pos) throws IOException {
+ int n = (int) (real_pos - pos);
+ if(n >= 0 && n <= buf_end) {
+ buf_pos = buf_end - n;
+ } else {
+ super.seek(pos);
+ invalidate();
+ }
+ }
+
+ /**
+ * Read the next line from the buffer (ie, until the next '\n'). The bytes
+ * are interpreted as UTF-8 characters.
+ *
+ * @return The String that was read
+ * @throws IOException
+ * If we failed reading the file
+ */
+ public final String getNextLine() throws IOException {
+ String str = null;
+ if (buf_end - buf_pos <= 0) {
+ if (fillBuffer() < 0) {
+ return null;
+ }
+ }
+ int lineend = -1;
+ for (int i = buf_pos; i < buf_end; i++) {
+ if (buffer[i] == '\n') {
+ lineend = i;
+ break;
+ }
+ }
+ if (lineend < 0) {
+ sb.delete(0, sb.length());
+ int c;
+ while (((c = read()) != -1) && (c != '\n')) {
+ sb.append((char) c);
+ }
+ if ((c == -1) && (sb.length() == 0)) {
+ return null;
+ }
+ if (sb.charAt(sb.length() - 1) == '\r') {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+ return sb.toString();
+ }
+ if (lineend > 0 && buffer[lineend - 1] == '\r' && lineend > buf_pos) {
+ str = new String(buffer, buf_pos, lineend - buf_pos - 1, CHARSET_UTF8);
+ } else {
+ str = new String(buffer, buf_pos, lineend - buf_pos, CHARSET_UTF8);
+ }
+ buf_pos = lineend + 1;
+ return str;
+ }
+
+ private int fillBuffer() throws IOException {
+ int n = super.read(buffer, 0, BUF_SIZE);
+ if (n >= 0) {
+ real_pos += n;
+ buf_end = n;
+ buf_pos = 0;
+ }
+ return n;
+ }
+
+ private void invalidate() throws IOException {
+ buf_end = 0;
+ buf_pos = 0;
+ real_pos = super.getFilePointer();
+ }
+}