QL-Win/QuickLook · warning · EndOfStreamException

DS_Store block: not enough bytes

Error message

DS_Store block: not enough bytes

What it means

Thrown by DSStoreBlock.ReadUint32 when fewer than 4 bytes remain in the current block (Size - Pos < 4). This EndOfStreamException fires during header/offset/TOC/filename parsing when a block is shorter than the parser expects.

Source

Thrown at QuickLook.Plugin/QuickLook.Plugin.ArchiveViewer/DSStore/DSStoreExtractor.cs:201

            | ((uint)arr[offset + 1] << 16)
            | ((uint)arr[offset + 2] << 8)
            | arr[offset + 3];
    }

    private sealed class DSStoreBlock(DSStoreAllocator alloc, uint offset, uint size, byte[] data)
    {
#pragma warning disable IDE0052
        private readonly DSStoreAllocator _alloc  = alloc;   // kept for parity / future use
#pragma warning restore IDE0052
        private readonly byte[] _data = data;

        public uint Offset { get; } = offset;
        public uint Size   { get; } = size;
        public uint Pos    { get; private set; }

        public uint ReadUint32()
        {
            if (Size - Pos < 4) throw new EndOfStreamException("DS_Store block: not enough bytes");
            uint v = ((uint)_data[Pos] << 24)
                   | ((uint)_data[Pos + 1] << 16)
                   | ((uint)_data[Pos + 2] << 8)
                   | _data[Pos + 3];
            Pos += 4;
            return v;
        }

        public byte ReadByte()
        {
            if (Size - Pos < 1) throw new EndOfStreamException("DS_Store block: not enough bytes");
            return _data[Pos++];
        }

        public byte[] ReadBuf(int length)
        {
            if ((int)Size - (int)Pos < length)
                throw new EndOfStreamException("DS_Store block: not enough bytes");

View on GitHub (pinned to cb5d9c429c)

Solutions

  1. Catch EndOfStreamException around GetFileNames and return filenames collected so far.
  2. Re-obtain the .DS_Store from the source.
  3. Add bounds-checking / graceful truncation handling in the traversal loop.
  4. Validate block sizes against the file length during NewBlock.
Defensive patterns

Strategy: try-catch

Try / catch

try { var names = DSStoreExtractor.GetFileNames(path); }
catch (EndOfStreamException ex) when (ex.Message.Contains("DS_Store block"))
{
    // Block ran out of bytes during a uint32 read; return partial results.
    names = new List<string>();
}

Prevention

When it happens

Trigger: ReadUint32 is called (directly or via ReadToc/ReadOffsets/Traverse/ReadFileName) on a block whose remaining bytes are < 4: corrupt block size in the offset table, truncated block data, or a malformed .DS_Store structure.

Common situations: Corrupt .DS_Store where block sizes are inconsistent with actual data; a file from an incompatible macOS version with a subtly different layout; truncated download.

Related errors


AI-assisted analysis of QL-Win/QuickLook@cb5d9c429c (2026-08-13). Data as JSON: /api/errors/ab57caab3a0d5d83. Report an issue: GitHub.