Skip to content

Instantly share code, notes, and snippets.

@mahairod
Last active January 25, 2024 01:36
Show Gist options
  • Save mahairod/534b2255e46c094014e11b5f57735c94 to your computer and use it in GitHub Desktop.
Save mahairod/534b2255e46c094014e11b5f57735c94 to your computer and use it in GitHub Desktop.
Java InputStream with support for multiple marks/resets and input counting
/*
* Авторское право принадлежит Антону Александровичу Астафьеву <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