make sure there is an exception if the file is corrupt
This commit is contained in:
@@ -13,9 +13,9 @@ enum ByteType {
|
|||||||
VERSION(1);// 00000001
|
VERSION(1);// 00000001
|
||||||
|
|
||||||
interface ContinuationByte {
|
interface ContinuationByte {
|
||||||
long NUMBER_OF_VALUES_BITS = 7;
|
int NUMBER_OF_VALUES_BITS = 7;
|
||||||
|
|
||||||
long CONTINUATION_BYTE_PREFIX = 1 << NUMBER_OF_VALUES_BITS; // 10000000
|
int CONTINUATION_BYTE_PREFIX = 1 << NUMBER_OF_VALUES_BITS; // 10000000
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VersionByte {
|
interface VersionByte {
|
||||||
@@ -24,19 +24,23 @@ enum ByteType {
|
|||||||
* which cannot hold any value (unless it is 0). And the second byte is
|
* which cannot hold any value (unless it is 0). And the second byte is
|
||||||
* the actual value.
|
* the actual value.
|
||||||
*/
|
*/
|
||||||
long MIN_LENGTH = 2;
|
int MIN_LENGTH = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final long firstBytePrefix;
|
private final int firstBytePrefix;
|
||||||
|
|
||||||
private ByteType(final long firstBytePrefix) {
|
private ByteType(final int firstBytePrefix) {
|
||||||
this.firstBytePrefix = firstBytePrefix;
|
this.firstBytePrefix = firstBytePrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getBytePrefix() {
|
public int getBytePrefix() {
|
||||||
return firstBytePrefix;
|
return firstBytePrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getBytePrefixAsByte() {
|
||||||
|
return (byte) firstBytePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the max value for the first byte is the prefix minus 1, because prefixes
|
* the max value for the first byte is the prefix minus 1, because prefixes
|
||||||
* start with 0⋯010⋯0, so prefix -1 is 0⋯01⋯1 which is exactly the max value
|
* start with 0⋯010⋯0, so prefix -1 is 0⋯01⋯1 which is exactly the max value
|
||||||
@@ -53,7 +57,7 @@ enum ByteType {
|
|||||||
*
|
*
|
||||||
* @return bitmap with the value bits set
|
* @return bitmap with the value bits set
|
||||||
*/
|
*/
|
||||||
public long getValueBits() {
|
public int getValueBits() {
|
||||||
return firstBytePrefix - 1;
|
return firstBytePrefix - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +68,7 @@ enum ByteType {
|
|||||||
return firstBytePrefix == (theByte & prefixBits);
|
return firstBytePrefix == (theByte & prefixBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getPrefixBits() {
|
public int getPrefixBits() {
|
||||||
return (~getValueBits()) & 0xff;
|
return (~getValueBits()) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +82,7 @@ enum ByteType {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getValue(final int aByte) {
|
public int getValue(final int aByte) {
|
||||||
return aByte & getValueBits();
|
return aByte & getValueBits();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ class PdbReader implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Entry readNullableEntry() throws ReadRuntimeException {
|
Entry readNullableEntry() throws ReadRuntimeException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final long epochMilliIncrement = readValue(ByteType.DATE_INCREMENT);
|
final long epochMilliIncrement = readValue(ByteType.DATE_INCREMENT);
|
||||||
if (epochMilliIncrement < 0) {
|
if (epochMilliIncrement < 0) {
|
||||||
@@ -127,6 +128,7 @@ class PdbReader implements AutoCloseable {
|
|||||||
|
|
||||||
if (!byteType.isValid(firstByte)) {
|
if (!byteType.isValid(firstByte)) {
|
||||||
if (firstByte < 0) {
|
if (firstByte < 0) {
|
||||||
|
// end of file reached
|
||||||
return -1;
|
return -1;
|
||||||
} else if (ByteType.DATE_OFFSET.isValid(firstByte)) {
|
} else if (ByteType.DATE_OFFSET.isValid(firstByte)) {
|
||||||
final long dateOffsetInit = firstByte & ByteType.DATE_OFFSET.getValueBits();
|
final long dateOffsetInit = firstByte & ByteType.DATE_OFFSET.getValueBits();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
@@ -88,6 +89,39 @@ public class PdbReaderWriterTest {
|
|||||||
|
|
||||||
Assert.assertEquals(actual, entry);
|
Assert.assertEquals(actual, entry);
|
||||||
}
|
}
|
||||||
|
reader.readEntry().ifPresent(e -> {
|
||||||
|
throw new AssertionError();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = FileCorruptException.class)
|
||||||
|
public void testReadExceptionOnCorruptEntries() throws Exception {
|
||||||
|
|
||||||
|
final Entry entryA = new Entry(1, 1, TAGS);
|
||||||
|
|
||||||
|
final File file = Files.createTempFile(dataDirectory, "pdb", ".db").toFile();
|
||||||
|
final PdbFile pdbFile = new PdbFile(file.toPath(), TAGS);
|
||||||
|
|
||||||
|
try (PdbWriter writer = new PdbWriter(pdbFile)) {
|
||||||
|
writer.write(entryA);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make the file corrupt
|
||||||
|
// two date consecutive increments will never happen in valid data
|
||||||
|
final byte[] corruptEntries = new byte[] { //
|
||||||
|
ByteType.DATE_INCREMENT.getBytePrefixAsByte(), //
|
||||||
|
ByteType.DATE_INCREMENT.getBytePrefixAsByte() //
|
||||||
|
};
|
||||||
|
|
||||||
|
Files.write(file.toPath(), corruptEntries, StandardOpenOption.APPEND);
|
||||||
|
|
||||||
|
try (final PdbReader reader = new PdbReader(pdbFile)) {
|
||||||
|
|
||||||
|
final Entry actualA = reader.readEntry().orElseThrow(() -> new AssertionError());
|
||||||
|
Assert.assertEquals(actualA, entryA);
|
||||||
|
|
||||||
|
reader.readEntry(); // should throw FileCorruptException
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user