summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJames Ahlborn <jtahlborn@yahoo.com>2008-02-29 19:02:36 +0000
committerJames Ahlborn <jtahlborn@yahoo.com>2008-02-29 19:02:36 +0000
commit36bf2ed080c73c0342eb121170abb7e548140f24 (patch)
tree86f2053570fa57bc51a6796b2c767e7220406d90 /src
parent933b73269e5929c58d05f9f0df4f2ca8edd289f2 (diff)
downloadjackcess-36bf2ed080c73c0342eb121170abb7e548140f24.tar.gz
jackcess-36bf2ed080c73c0342eb121170abb7e548140f24.zip
better handling of index entry compression; validate index entry length reading
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@241 f203690c-595d-4dc9-a70b-905162fa7fd2
Diffstat (limited to 'src')
-rw-r--r--src/java/com/healthmarketscience/jackcess/Index.java193
1 files changed, 130 insertions, 63 deletions
diff --git a/src/java/com/healthmarketscience/jackcess/Index.java b/src/java/com/healthmarketscience/jackcess/Index.java
index 5c26f64..20c3605 100644
--- a/src/java/com/healthmarketscience/jackcess/Index.java
+++ b/src/java/com/healthmarketscience/jackcess/Index.java
@@ -425,7 +425,7 @@ public class Index implements Comparable<Index> {
break;
}
}
-
+
// read all leaf pages
while(true) {
@@ -507,16 +507,32 @@ public class Index implements Comparable<Index> {
int lastStart = 0;
byte[] valuePrefix = null;
boolean firstEntry = true;
+ ByteBuffer tmpEntryBuffer = null;
+
for (int i = 0; i < entryMaskLength; i++) {
byte entryMask = indexPage.get(entryMaskPos + i);
for (int j = 0; j < 8; j++) {
if ((entryMask & (1 << j)) != 0) {
- int length = i * 8 + j - lastStart;
+ int length = (i * 8) + j - lastStart;
indexPage.position(entryPos + lastStart);
+ int startReadPos = indexPage.position();
+
+ // determine if we can read straight from the index page (if no
+ // valuePrefix). otherwise, create temp buf with complete entry.
+ ByteBuffer curEntryBuffer = indexPage;
+ int curEntryLen = length;
+ if(valuePrefix != null) {
+ tmpEntryBuffer = getTempEntryBuffer(
+ indexPage, length, valuePrefix, tmpEntryBuffer);
+ curEntryBuffer = tmpEntryBuffer;
+ curEntryLen += valuePrefix.length;
+ }
+
if(isLeaf) {
- entries.add(new Entry(indexPage, valuePrefix, _columns));
+ entries.add(new Entry(curEntryBuffer, curEntryLen, _columns));
} else {
- nodeEntries.add(new NodeEntry(indexPage, valuePrefix, _columns));
+ nodeEntries.add(new NodeEntry(
+ curEntryBuffer, curEntryLen, _columns));
}
// read any shared "compressed" bytes
@@ -537,7 +553,30 @@ public class Index implements Comparable<Index> {
}
}
}
-
+
+ /**
+ * Returns an entry buffer containing the relevant data for an entry given
+ * the valuePrefix.
+ */
+ private ByteBuffer getTempEntryBuffer(
+ ByteBuffer indexPage, int entryLen, byte[] valuePrefix,
+ ByteBuffer tmpEntryBuffer)
+ {
+ int totalLen = entryLen + valuePrefix.length;
+ if((tmpEntryBuffer == null) || (tmpEntryBuffer.capacity() < totalLen)) {
+ tmpEntryBuffer = ByteBuffer.allocate(totalLen);
+ } else {
+ tmpEntryBuffer.clear();
+ }
+
+ // combine valuePrefix and rest of entry from indexPage, then prep for
+ // reading
+ tmpEntryBuffer.put(valuePrefix);
+ tmpEntryBuffer.put(indexPage.array(), indexPage.position(), entryLen);
+ tmpEntryBuffer.flip();
+
+ return tmpEntryBuffer;
+ }
/**
* Adds a row to this index
@@ -949,20 +988,43 @@ public class Index implements Comparable<Index> {
}
}
}
-
+
/**
* Read an existing entry in from a buffer
*/
- private Entry(ByteBuffer buffer, byte[] valuePrefix,
+ private Entry(ByteBuffer buffer, int entryLen,
Map<Column, Byte> columns)
throws IOException
{
+ this(buffer, entryLen, columns, 0);
+ }
+
+ /**
+ * Read an existing entry in from a buffer
+ */
+ private Entry(ByteBuffer buffer, int entryLen,
+ Map<Column, Byte> columns, int extraTrailingLen)
+ throws IOException
+ {
+ // we need 4 trailing bytes for the rowId, plus whatever the caller
+ // wants
+ int trailingByteLen = 4 + extraTrailingLen;
+
+ int colEntryLen = entryLen - trailingByteLen;
+
_entryColumns = new ArrayList<EntryColumn>();
for(Map.Entry<Column, Byte> entry : columns.entrySet()) {
Column col = entry.getKey();
Byte flags = entry.getValue();
+ int startCurEntryPos = buffer.position();
_entryColumns.add(newEntryColumn(col)
- .initFromBuffer(buffer, flags, valuePrefix));
+ .initFromBuffer(buffer, flags, colEntryLen));
+ int curEntryLen = buffer.position() - startCurEntryPos;
+ if(curEntryLen > colEntryLen) {
+ throw new IOException("could not parse entry column, expected " +
+ colEntryLen + ", read " + curEntryLen);
+ }
+ colEntryLen -= curEntryLen;
}
int page = ByteUtil.get3ByteInt(buffer, ByteOrder.BIG_ENDIAN);
int row = buffer.get();
@@ -1123,7 +1185,7 @@ public class Index implements Comparable<Index> {
*/
protected abstract EntryColumn initFromBuffer(ByteBuffer buffer,
byte flags,
- byte[] valuePrefix)
+ int colEntryLen)
throws IOException;
protected abstract boolean isNullValue();
@@ -1136,6 +1198,7 @@ public class Index implements Comparable<Index> {
if(isNullValue()) {
buffer.put((byte)0);
} else {
+ buffer.put((byte) 0x7F);
writeNonNullValue(buffer);
}
}
@@ -1185,22 +1248,16 @@ public class Index implements Comparable<Index> {
@Override
protected EntryColumn initFromBuffer(ByteBuffer buffer,
byte flags,
- byte[] valuePrefix)
+ int colEntryLen)
throws IOException
{
+ // FIXME, eventually take colEntryLen into account
-
- byte flag = ((valuePrefix == null) ? buffer.get() : valuePrefix[0]);
+ byte flag = buffer.get();
// FIXME, reverse is 0x80, reverse null is 0xFF
- if (flag != (byte) 0) {
+ if ((flag != (byte) 0) && (flag != (byte)0xFF)) {
byte[] data = new byte[_column.getType().getFixedSize()];
- int dataOffset = 0;
- if((valuePrefix != null) && (valuePrefix.length > 1)) {
- System.arraycopy(valuePrefix, 1, data, 0,
- (valuePrefix.length - 1));
- dataOffset += (valuePrefix.length - 1);
- }
- buffer.get(data, dataOffset, (data.length - dataOffset));
+ buffer.get(data);
_value = (Comparable) _column.read(data, ByteOrder.BIG_ENDIAN);
//ints and shorts are stored in index as value + 2147483648
@@ -1226,7 +1283,6 @@ public class Index implements Comparable<Index> {
*/
@Override
protected void writeNonNullValue(ByteBuffer buffer) throws IOException {
- buffer.put((byte) 0x7F);
Comparable value = _value;
if (value instanceof Integer) {
value = Integer.valueOf((int) (((Integer) value).longValue() -
@@ -1267,6 +1323,8 @@ public class Index implements Comparable<Index> {
private byte[] _valueBytes;
/** extra column bytes */
private byte[] _extraBytes;
+ /** whether or not the trailing bytes were found */
+ private boolean _hasTrailingBytes;
private TextEntryColumn(Column col) throws IOException {
super(col);
@@ -1295,54 +1353,55 @@ public class Index implements Comparable<Index> {
@Override
protected EntryColumn initFromBuffer(ByteBuffer buffer,
byte flags,
- byte[] valuePrefix)
+ int colEntryLen)
throws IOException
{
- byte flag = ((valuePrefix == null) ? buffer.get() : valuePrefix[0]);
+ // can't read more than colEntryLen
+ int maxPos = buffer.position() + colEntryLen;
+
+ byte flag = buffer.get();
// FIXME, reverse is 0x80, reverse null is 0xFF
// end flag is FE, post extra bytes is FF 00
// extra bytes are inverted, so are normal bytes
- if (flag != (byte) 0) {
+ if ((flag != (byte) 0) && (flag != (byte)0xFF)) {
int endPos = buffer.position();
+ _hasTrailingBytes = true;
while(buffer.get(endPos) != (byte) 1) {
+ if(endPos == maxPos) {
+ _hasTrailingBytes = false;
+ break;
+ }
++endPos;
}
- // FIXME, prefix could probably include extraBytes...
-
// read index bytes
- int numPrefixBytes = ((valuePrefix == null) ? 0 :
- (valuePrefix.length - 1));
+ int numPrefixBytes = 0;
int dataOffset = 0;
- _valueBytes = new byte[(endPos - buffer.position()) +
- numPrefixBytes];
- if(numPrefixBytes > 0) {
- System.arraycopy(valuePrefix, 1, _valueBytes, 0, numPrefixBytes);
- dataOffset += numPrefixBytes;
- }
- buffer.get(_valueBytes, dataOffset,
- (_valueBytes.length - dataOffset));
+ _valueBytes = new byte[endPos - buffer.position()];
+ buffer.get(_valueBytes);
- // read end codes byte
- buffer.get();
+ if(_hasTrailingBytes) {
+
+ // read end codes byte
+ buffer.get();
- //Forward past 0x00 (in some cases, there is more data here, which
- //we don't currently understand)
- byte endByte = buffer.get();
- if(endByte != (byte)0x00) {
- endPos = buffer.position() - 1;
- buffer.position(endPos);
- while(buffer.get(endPos) != (byte)0x00) {
- ++endPos;
+ //Forward past 0x00 (in some cases, there is more data here, which
+ //we don't currently understand)
+ byte endByte = buffer.get();
+ if(endByte != (byte)0x00) {
+ endPos = buffer.position() - 1;
+ buffer.position(endPos);
+ while(buffer.get(endPos) != (byte)0x00) {
+ ++endPos;
+ }
+ _extraBytes = new byte[endPos - buffer.position()];
+ buffer.get(_extraBytes);
+
+ // re-get endByte
+ buffer.get();
}
- _extraBytes = new byte[endPos - buffer.position()];
- buffer.get(_extraBytes);
-
- // re-get endByte
- buffer.get();
}
-
}
return this;
@@ -1358,20 +1417,24 @@ public class Index implements Comparable<Index> {
*/
@Override
protected void writeNonNullValue(ByteBuffer buffer) throws IOException {
- buffer.put((byte) 0x7F);
buffer.put(_valueBytes);
- buffer.put((byte) 1);
- if(_extraBytes != null) {
- buffer.put(_extraBytes);
+ if(_hasTrailingBytes) {
+ buffer.put((byte) 1);
+ if(_extraBytes != null) {
+ buffer.put(_extraBytes);
+ }
+ buffer.put((byte) 0);
}
- buffer.put((byte) 0);
}
@Override
protected int nonNullSize() {
- int rtn = _valueBytes.length + 2;
- if(_extraBytes != null) {
- rtn += _extraBytes.length;
+ int rtn = _valueBytes.length;
+ if(_hasTrailingBytes) {
+ rtn += 2;
+ if(_extraBytes != null) {
+ rtn += _extraBytes.length;
+ }
}
return rtn;
}
@@ -1400,6 +1463,9 @@ public class Index implements Comparable<Index> {
if(rtn != 0) {
return rtn;
}
+ if(_hasTrailingBytes != textOther._hasTrailingBytes) {
+ return(_hasTrailingBytes ? 1 : -1);
+ }
return BYTE_CODE_COMPARATOR.compare(
_extraBytes, textOther._extraBytes);
}
@@ -1419,15 +1485,16 @@ public class Index implements Comparable<Index> {
/**
* Read an existing node entry in from a buffer
*/
- private NodeEntry(ByteBuffer buffer, byte[] valuePrefix,
+ private NodeEntry(ByteBuffer buffer, int entryLen,
Map<Column, Byte> columns)
throws IOException
{
- super(buffer, valuePrefix, columns);
+ // we need 4 trailing bytes for the sub-page number
+ super(buffer, entryLen, columns, 4);
_subPageNumber = ByteUtil.getInt(buffer, ByteOrder.BIG_ENDIAN);
}
-
+
public int getSubPageNumber() {
return _subPageNumber;
}