001/** 002 * Java Web Archive Toolkit - Software to read and validate ARC, WARC 003 * and GZip files. (http://jwat.org/) 004 * Copyright 2011-2012 Netarkivet.dk (http://netarkivet.dk/) 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.jwat.common; 019 020import java.io.IOException; 021import java.io.StringReader; 022 023/** 024 * <code>StringReader</code> that keeps tracks of the number of consumed chars 025 * at any given time. 026 * 027 * @author lbihanic, selghissassi, nicl 028 */ 029public class CharCountingStringReader extends StringReader { 030 031 /** Number of consumed bytes since the beginning of the stream. */ 032 protected long consumed = 0; 033 034 /** Byte counter which can also be changed. */ 035 protected long counter = 0; 036 037 /** 038 * Creates a new <code>StringReader</code> that keeps track of 039 * consumed characters. 040 * @param str Arbitrary string. 041 */ 042 public CharCountingStringReader(String str) { 043 super(str); 044 } 045 046 @Override 047 public boolean markSupported() { 048 return false; 049 } 050 051 @Override 052 public synchronized void mark(int readlimit) { 053 throw new UnsupportedOperationException(); 054 } 055 056 @Override 057 public synchronized void reset() throws IOException { 058 throw new UnsupportedOperationException(); 059 } 060 061 /** 062 * Consumed length getter. 063 * @return the consumed length 064 */ 065 public long getConsumed() { 066 return consumed; 067 } 068 069 /** 070 * Change the counter value. 071 * Useful for reading zero indexed relative data. 072 * @param bytes new counter value 073 */ 074 public void setCounter(long bytes) { 075 counter = bytes; 076 } 077 078 /** 079 * Retrieve the current counter value. 080 * @return current counter value 081 */ 082 public long getCounter() { 083 return counter; 084 } 085 086 @Override 087 public int read() throws IOException { 088 int c = super.read(); 089 if (c != -1) { 090 ++consumed; 091 ++counter; 092 } 093 return c; 094 } 095 096 @Override 097 public int read(char[] cbuf, int off, int len) throws IOException { 098 int bytesRead = super.read(cbuf, off, len); 099 if (bytesRead > 0) { 100 consumed += bytesRead; 101 counter += bytesRead; 102 } 103 return bytesRead; 104 } 105 106 @Override 107 public long skip(long n) throws IOException { 108 long bytesSkipped = super.skip(n); 109 consumed += bytesSkipped; 110 counter += bytesSkipped; 111 return bytesSkipped; 112 } 113 114 /** 115 * Reads a line defined as characters read until encountering a 116 * <code>LF</code> or EOF. 117 * @return Line read from buffered <code>StringReader</code> 118 * @throws IOException if an I/O error occurs while reading line 119 */ 120 public String readLine() throws IOException { 121 StringBuilder buf = new StringBuilder(); 122 int c; 123 while (true) { 124 c = read(); 125 if (c == -1) { 126 return null; 127 } 128 if (c == '\n') { 129 break; 130 } 131 if (c != '\r') { 132 buf.append((char) c); 133 } 134 } 135 return buf.toString(); 136 } 137 138}