{"record":{"id":"b2077f20095ea971","repo":"QL-Win/QuickLook","slug":"the-specified-file-does-not-appear-to-be-an-ole-co","errorCode":null,"errorMessage":"The specified file does not appear to be an OLE Compound File (invalid header).","messagePattern":"The specified file does not appear to be an OLE Compound File \\(invalid header\\)\\.","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"QuickLook.Plugin/QuickLook.Plugin.ArchiveViewer/CompoundFileBinary/CompoundFileExtractor.cs","lineNumber":58,"sourceCode":"    {\n        if (!Directory.Exists(destinationDirectory))\n        {\n            Directory.CreateDirectory(destinationDirectory);\n        }\n\n        // Ensure the compound file exists\n        if (!File.Exists(compoundFilePath))\n            throw new FileNotFoundException(\"Compound file not found.\", compoundFilePath);\n\n        // Validate magic header for OLE compound file: D0 CF 11 E0 A1 B1 1A E1\n        byte[] magicHeader = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];\n        byte[] header = new byte[8];\n        using (FileStream fs = new(compoundFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))\n        {\n            int read = fs.Read(header, 0, header.Length);\n            if (read < header.Length || !header.SequenceEqual(magicHeader))\n            {\n                throw new InvalidDataException(\"The specified file does not appear to be an OLE Compound File (invalid header).\");\n            }\n        }\n\n        // Open the compound file as an IStorage implementation wrapped by DisposableIStorage.\n        using DisposableIStorage storage = new(compoundFilePath, STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE, IntPtr.Zero);\n        IEnumerator<STATSTG> enumerator = storage.EnumElements();\n\n        // Enumerate all elements (streams and storages) at the root of the compound file.\n        while (enumerator.MoveNext())\n        {\n            STATSTG entryStat = enumerator.Current;\n\n            // STGTY_STREAM indicates the element is a stream (treat as a file).\n            if (entryStat.type == (int)STGTY.STGTY_STREAM)\n            {\n                ExtractStreamToDirectory(storage, entryStat.pwcsName, destinationDirectory);\n            }\n            // STGTY_STORAGE indicates the element is a nested storage (treat as a directory).","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/QL-Win/QuickLook/blob/cb5d9c429c81d9796fac469da2a68efb5626946d/QuickLook.Plugin/QuickLook.Plugin.ArchiveViewer/CompoundFileBinary/CompoundFileExtractor.cs#L40-L76","documentation":"Thrown by CompoundFileExtractor.ExtractToDirectory when the file exists but its first 8 bytes do not match the OLE Compound File magic header D0 CF 11 E0 A1 B1 1A E1. The file is therefore not a structured-storage / OLE container and cannot be opened via IStorage.","triggerScenarios":"Calling ExtractToDirectory on a file that is not an OLE compound file: a .docx (which is a zip), a raw binary, a text file, or a file with a .cfb/.doc extension that is actually a newer XML/zip-based format.","commonSituations":"Modern Office files (.docx/.xlsx/.pptx) are zip, not OLE — users expect old .doc but pass new formats; a file renamed to look like a compound file; legacy .doc that is actually RTF or plain text; a corrupt OLE file whose header is overwritten.","solutions":["Validate the OLE magic header before calling the extractor.","If the file is a modern Office format (.docx etc.), route to a zip-based extractor instead.","Detect format by extension + magic bytes and dispatch to the correct parser.","Catch InvalidDataException and report the file as unsupported for compound-file extraction."],"exampleFix":"// before\nCompoundFileExtractor.ExtractToDirectory(path, dest);\n\n// after\nstatic bool IsOle(string p)\n{\n    using var fs = File.OpenRead(p);\n    var h = new byte[8]; fs.Read(h, 0, 8);\n    return h[0]==0xD0 && h[1]==0xCF && h[2]==0x11 && h[3]==0xE0\n        && h[4]==0xA1 && h[5]==0xB1 && h[6]==0x1A && h[7]==0xE1;\n}\nif (!IsOle(path))\n    throw new InvalidDataException($\"{path} is not an OLE Compound File.\");\nCompoundFileExtractor.ExtractToDirectory(path, dest);","handlingStrategy":"validation","validationCode":"// Validate the OLE Compound File magic header before extraction.\nstatic readonly byte[] OleMagic = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];\npublic static bool IsOleCompoundFile(string path)\n{\n    try\n    {\n        using var fs = File.OpenRead(path);\n        var h = new byte[8];\n        return fs.Read(h, 0, 8) == 8 && h.SequenceEqual(OleMagic);\n    }\n    catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try { CompoundFileExtractor.ExtractToDirectory(path, dest); }\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"OLE Compound File\"))\n{\n    // Not an OLE file; route to a zip-based extractor if it's a modern Office file.\n}","preventionTips":["Validate the OLE magic header before extraction.","Route modern Office files (.docx/.xlsx) to a zip-based parser.","Detect format by magic bytes, not just extension."],"tags":["ole","compound-file","magic-bytes","invaliddata","csharp"],"backgroundTag":null,"analyzedSha":"cb5d9c429c81d9796fac469da2a68efb5626946d","analyzedAt":"2026-08-13T11:51:01.370Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}