@Override
public int read(byte[] b, int off, int len) throws IOException {
- if(spare != null) {
- // This is risky, but spare is normally only a byte or two...
- System.arraycopy(spare, 0, b, off, spare.length);
- int ret = spare.length;
- spare = null;
- return ret;
+ // Grab any data left from last time
+ int readA = readFromSpare(b, off, len);
+
+ // Now read from the stream
+ int readB = source.read(b, off+readA, len-readA);
+
+ // Figure out how much we've done
+ int read;
+ if(readB == -1 || readB == 0) {
+ read = readA;
+ } else {
+ read = readA + readB;
+ }
+
+ // Fix up our data
+ if(read > 0) {
+ read = fixUp(b, off, read);
}
- int read = source.read(b, off, len);
- read = fixUp(b, off, read);
+ // All done
return read;
}
public int read(byte[] b) throws IOException {
return this.read(b, 0, b.length);
}
+
+ /**
+ * Reads into the buffer from the spare bytes
+ */
+ private int readFromSpare(byte[] b, int offset, int len) {
+ if(spare == null) return 0;
+ if(len == 0) throw new IllegalArgumentException("Asked to read 0 bytes");
+
+ if(spare.length <= len) {
+ // All fits, good
+ System.arraycopy(spare, 0, b, offset, spare.length);
+ int read = spare.length;
+ spare = null;
+ return read;
+ } else {
+ // We have more spare than they can copy with...
+ byte[] newspare = new byte[spare.length-len];
+ System.arraycopy(spare, 0, b, offset, len);
+ System.arraycopy(spare, len, newspare, 0, newspare.length);
+ spare = newspare;
+ return len;
+ }
+ }
+ private void addToSpare(byte[] b, int offset, int len, boolean atTheEnd) {
+ if(spare == null) {
+ spare = new byte[len];
+ System.arraycopy(b, offset, spare, 0, len);
+ } else {
+ byte[] newspare = new byte[spare.length+len];
+ if(atTheEnd) {
+ System.arraycopy(spare, 0, newspare, 0, spare.length);
+ System.arraycopy(b, offset, newspare, spare.length, len);
+ } else {
+ System.arraycopy(b, offset, newspare, 0, len);
+ System.arraycopy(spare, 0, newspare, len, spare.length);
+ }
+ spare = newspare;
+ }
+ }
private int fixUp(byte[] b, int offset, int read) {
+ // Do we have any potential overhanging ones?
+ for(int i=0; i<detect.length-1; i++) {
+ int base = offset+read-1-i;
+ if(base < 0) continue;
+
+ boolean going = true;
+ for(int j=0; j<=i && going; j++) {
+ if(b[base+j] == detect[j]) {
+ // Matches
+ } else {
+ going = false;
+ }
+ }
+ if(going) {
+ // There could be a <br> handing over the end, eg <br|
+ addToSpare(b, base, i+1, true);
+ read -= 1;
+ read -= i;
+ break;
+ }
+ }
+
// Find places to fix
ArrayList<Integer> fixAt = new ArrayList<Integer>();
- for(int i=offset; i<offset+read-4; i++) {
+ for(int i=offset; i<=offset+read-detect.length; i++) {
boolean going = true;
for(int j=0; j<detect.length && going; j++) {
if(b[i+j] != detect[j]) {
return read;
}
- // Save a bit, if needed to fit
- int overshoot = offset+read+fixAt.size() - b.length;
+ // If there isn't space in the buffer to contain
+ // all the fixes, then save the overshoot for next time
+ int needed = offset+read+fixAt.size();
+ int overshoot = needed - b.length;
if(overshoot > 0) {
- spare = new byte[overshoot];
- System.arraycopy(b, b.length-overshoot, spare, 0, overshoot);
+ // Make sure we don't loose part of a <br>!
+ int fixes = 0;
+ for(int at : fixAt) {
+ if(at > offset+read-detect.length-overshoot-fixes) {
+ overshoot = needed - at - 1 - fixes;
+ break;
+ }
+ fixes++;
+ }
+
+ addToSpare(b, offset+read-overshoot, overshoot, false);
read -= overshoot;
}
// Fix them, in reverse order so the
// positions are valid
for(int j=fixAt.size()-1; j>=0; j--) {
- int i = fixAt.get(j);
+ int i = fixAt.get(j);
+ if(i >= read+offset) {
+ // This one has moved into the overshoot
+ continue;
+ }
+ if(i > read-3) {
+ // This one has moved into the overshoot
+ continue;
+ }
byte[] tmp = new byte[read-i-3];
System.arraycopy(b, i+3, tmp, 0, tmp.length);