Skip to content

Instantly share code, notes, and snippets.

@EricZimmerman
Last active January 25, 2024 19:27
Show Gist options
  • Save EricZimmerman/db7c55660f5615398c22 to your computer and use it in GitHub Desktop.
Save EricZimmerman/db7c55660f5615398c22 to your computer and use it in GitHub Desktop.
ThumbCache*.db parser
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
namespace ThumbCache
{
public class ThumbCache
{
public List<Bitmap> Images { get; }
public ThumbCache(string fileName)
{
var s = new FileStream(fileName,FileMode.Open,FileAccess.Read);
var bs = new BinaryReader(s);
Images = new List<Bitmap>();
var rawBytes = bs.ReadBytes((int) bs.BaseStream.Length);
bs.Close();
s.Close();
var index = 0;
var sig = Encoding.ASCII.GetString(rawBytes, index, 4);
if (sig.Equals("CMMM") == false)
{
throw new InvalidDataException("Header != CMMM");
}
index += 4;
var ver = BitConverter.ToUInt32(rawBytes, index);
index += 4;
var cacheType = BitConverter.ToUInt32(rawBytes, index);
index += 4;
var firstOffset = BitConverter.ToUInt32(rawBytes, index);
index += 4;
var firstAvailOffset = BitConverter.ToUInt32(rawBytes, index);
index += 4;
var numEntries = BitConverter.ToUInt32(rawBytes, index);
index += 4;
while (index < rawBytes.Length)
{
sig = Encoding.ASCII.GetString(rawBytes, index, 4);
var lastStart = index;
index += 4;
var cacheSize = BitConverter.ToUInt32(rawBytes, index);
index += 4;
index += 8; //skip entry hash
var identifierSize = BitConverter.ToInt32(rawBytes, index);
index += 4;
var paddingSize = BitConverter.ToInt32(rawBytes, index);
index += 4;
var dataSize = BitConverter.ToUInt32(rawBytes, index);
index += 4;
index += 4;//skip unknown
index += 8;//skip data checksum
index += 8;//skip header checksum
index += 8;//move 8 for rest to work
var identifier = Encoding.Unicode.GetString(rawBytes, index, identifierSize);
index += identifierSize;
index += paddingSize;
var rawImageBytes = rawBytes.Skip(index).Take((int) dataSize).ToArray();
if (rawImageBytes.Length > 0)
{
Bitmap newBitmap = GetImageFromByteArray(rawImageBytes);
Images.Add(newBitmap);
}
index = lastStart + (int) cacheSize;
}
}
//from http://stackoverflow.com/questions/3801275/how-to-convert-image-in-byte-array/16576471#16576471
private static readonly ImageConverter _imageConverter = new ImageConverter();
public static Bitmap GetImageFromByteArray(byte[] byteArray)
{
Bitmap bm = (Bitmap)_imageConverter.ConvertFrom(byteArray);
if (bm != null && (bm.HorizontalResolution != (int)bm.HorizontalResolution ||
bm.VerticalResolution != (int)bm.VerticalResolution))
{
// Correct a strange glitch that has been observed in the test program when converting
// from a PNG file image created by CopyImageToByteArray() - the dpi value "drifts"
// slightly away from the nominal integer value
bm.SetResolution((int)(bm.HorizontalResolution + 0.5f),
(int)(bm.VerticalResolution + 0.5f));
}
return bm;
}
}
}
@EricZimmerman
Copy link
Author

On Windows 8.1, all these files processed fine:
thumbcache_16.db
thumbcache_32.db
thumbcache_48.db
thumbcache_96.db
thumbcache_256.db
thumbcache_1024.db

@EricZimmerman
Copy link
Author

you can get around "in use" errors on a running system by copying the file:

var fname = @"C:\Users\eric\AppData\Local\Microsoft\Windows\Explorer\thumbcache_96.db";
var newName = @"C:\temp\thumbcache_96.db";
File.Copy(fname, newName, true);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment