Last active
January 25, 2024 01:36
-
-
Save mahairod/534b2255e46c094014e11b5f57735c94 to your computer and use it in GitHub Desktop.
Java InputStream with support for multiple marks/resets and input counting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Авторское право принадлежит Антону Александровичу Астафьеву <anton@astafiev.me> ѱ 2024. | |
* Все права защищены и охраняются законом. | |
* Copyright (c) 2024 Anton Astafiev <anton@astafiev.me>. All rights reserved. | |
* | |
* Собственная лицензия Астафьева | |
* Данный программный код является собственностью Астафьева Антона Александровича | |
* и может быть использован только с его личного разрешения | |
*/ | |
package net.elliptica.disk; | |
import java.io.BufferedInputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* @author Антон А. Астафьев {@literal <anton@astafiev.me>} (Anton A. Astafiev) | |
* @version 0.1 (2024) | |
*/ | |
public class MultiMarkedInputStream extends BufferedInputStream { | |
private final List<Integer> marks = new ArrayList<>(); | |
private long mmcount; | |
public MultiMarkedInputStream(InputStream in) { | |
super(in); | |
} | |
public MultiMarkedInputStream(InputStream in, int size) { | |
super(in, size); | |
} | |
/* | |
* support for stream bytes counting | |
*/ | |
/** | |
* Returns the number of bytes read. | |
*/ | |
public long getCount() { | |
return mmcount; | |
} | |
@Override | |
public int read() throws IOException { | |
int result = super.read(); | |
if (result != -1) { | |
mmcount++; | |
} | |
return result; | |
} | |
@Override | |
public int read(byte[] b, int off, int len) throws IOException { | |
int result = super.read(b, off, len); | |
if (result != -1) { | |
mmcount += result; | |
} | |
return result; | |
} | |
@Override | |
public long skip(long n) throws IOException { | |
long result = super.skip(n); | |
mmcount += result; | |
return result; | |
} | |
/* | |
* multimark support | |
*/ | |
@Override | |
public synchronized void reset() throws IOException { | |
if (marks.isEmpty()) { | |
throw new IOException("Mark not set"); | |
} | |
syncMarks(); | |
int mrk = marks.remove(marks.size() - 1); | |
int toDiscard = super.pos - mrk; | |
if (marks.isEmpty()) { | |
super.reset(); | |
} else { | |
getBufIfOpen(); // Cause exception if closed | |
if (super.markpos < 0) { | |
throw new IOException("Resetting to invalid mark"); | |
} | |
super.pos = mrk; | |
} | |
mmcount -= toDiscard; | |
} | |
@Override | |
public synchronized void mark(int readlimit) { | |
if (marks.isEmpty()) { | |
super.mark(readlimit); | |
} else { | |
if (readlimit > marklimit) { | |
marklimit = readlimit; | |
} | |
} | |
syncMarks(); | |
marks.add(super.pos); | |
} | |
private void syncMarks() { | |
if (marks.isEmpty()) { | |
return; | |
} | |
int firstmark = marks.get(0); | |
if (firstmark > super.markpos) { | |
int delta = firstmark - super.markpos; | |
marks.replaceAll(el -> el - delta); | |
} | |
} | |
private byte[] getBufIfOpen() throws IOException { | |
byte[] buffer = buf; | |
if (buffer == null) { | |
throw new IOException("Stream closed"); | |
} | |
return buffer; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment