Skip to content

Commit

Permalink
feat: Implement thumbcache file parsing
Browse files Browse the repository at this point in the history
- Implemented `ThumbcacheParser` class to parse thumbcache files.
- Added `parseThumbcacheFile` method to read and parse thumbcache file entries.
- Utilized `ByteBuffer` for reading binary data with little-endian byte order.
- Added detailed logging of thumbcache entry attributes.
  • Loading branch information
marcus6n committed Oct 19, 2024
1 parent 11252d6 commit 5393004
Showing 1 changed file with 83 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,32 +48,93 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata,
}

private void parseThumbcacheFile(InputStream stream, XHTMLContentHandler xhtml) throws IOException, SAXException {
byte[] buffer = new byte[80]; // Buffer para a leitura de cada entrada
byte[] buffer = new byte[56];

ByteBuffer fileHeader = ByteBuffer.allocate(24).order(ByteOrder.LITTLE_ENDIAN);
stream.read(fileHeader.array());

String signature = new String(fileHeader.array(), 0, 4);
if (!"CMMM".equals(signature)) {
xhtml.characters("Error processing cache file: Invalid header signature; expected 'CMMM'.\n");
return;
}

int formatVersion = fileHeader.getInt(4); //
int cacheType = fileHeader.getInt(8); //
int firstCacheEntryOffset = fileHeader.getInt(12);
int firstAvailableCacheEntryOffset = fileHeader.getInt(16);
int numberOfCacheEntries = fileHeader.getInt(20);

xhtml.startElement("pre");
xhtml.characters("Cache file format version : " + formatVersion + "\n");
xhtml.characters("Cache type : " + cacheType + "\n");
xhtml.characters("Offset to first cache entry : " + firstCacheEntryOffset + "\n");
xhtml.characters("Offset to first available entry: " + firstAvailableCacheEntryOffset + "\n");
xhtml.characters("Number of cache entries : " + numberOfCacheEntries + "\n");

String windowsVersion = "";
switch (formatVersion) {
case 20:
windowsVersion = "Windows Vista";
break;
case 21:
windowsVersion = "Windows 7";
break;
case 30:
windowsVersion = "Windows 8.0";
break;
case 31:
windowsVersion = "Windows 8.1";
break;
case 32:
windowsVersion = "Windows 10 / 11";
break;
default:
windowsVersion = "Unknown version";
}
xhtml.characters("Seen on Windows version : " + windowsVersion + "\n");
xhtml.endElement("pre");

// Processando as entradas de cache
while (stream.read(buffer) == buffer.length) {
ByteBuffer bb = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN);

int size = bb.getInt();
long entryHash = bb.getLong();
int identifierStringSize = bb.getInt();
int paddingSize = bb.getInt();
int dataSize = bb.getInt();
int unknown1 = bb.getInt();
long dataChecksum = bb.getInt() & 0xFFFFFFFFL;
long headerChecksum = bb.getLong();

// Exibir os detalhes do cache
xhtml.startElement("pre");
xhtml.characters("size : " + size + "\n");
xhtml.characters("entry hash : 0x" + Long.toHexString(entryHash) + "\n");
xhtml.characters("identifier string size : " + identifierStringSize + "\n");
xhtml.characters("padding size : " + paddingSize + "\n");
xhtml.characters("data size : " + dataSize + "\n");
xhtml.characters("unknown1 : 0x" + Integer.toHexString(unknown1) + "\n");
xhtml.characters("data checksum : 0x" + Long.toHexString(dataChecksum) + "\n");
xhtml.characters("header checksum : 0x" + Long.toHexString(headerChecksum) + "\n");
xhtml.characters("\nidentifier string : " + Long.toHexString(entryHash) + "\n");
xhtml.endElement("pre");
String entrySignature = new String(buffer, 0, 4); //
if (!"CMMM".equals(entrySignature)) {
xhtml.characters("Error: Invalid entry signature, expected 'CMMM'. Skipping entry.\n");
continue;
}

int entrySize = bb.getInt(4);
long entryHash = bb.getLong(8);
int identifierStringSize = bb.getInt(16);
int paddingSize = bb.getInt(20);
int dataSize = bb.getInt(24); //
long dataChecksum = bb.getLong(40);
long headerChecksum = bb.getLong(48);

if (dataSize > 0 && identifierStringSize > 0) {
byte[] identifierBytes = new byte[identifierStringSize];
stream.read(identifierBytes);
String identifierString = new String(identifierBytes, "UTF-16LE");

xhtml.startElement("pre");
xhtml.characters("Entry hash : 0x" + Long.toHexString(entryHash) + "\n");
xhtml.characters("Entry size : " + entrySize + "\n");
xhtml.characters("Identifier string : " + identifierString + "\n");
xhtml.characters("Data size : " + dataSize + "\n");
xhtml.characters("Data checksum : 0x" + Long.toHexString(dataChecksum) + "\n");
xhtml.characters("Header checksum : 0x" + Long.toHexString(headerChecksum) + "\n");
xhtml.endElement("pre");
}

if (paddingSize > 0) {
stream.skip(paddingSize);
}

if (dataSize > 0) {
stream.skip(dataSize);
}
}
}
}

0 comments on commit 5393004

Please sign in to comment.