{"record":{"id":"21da78e671aa768d","repo":"can1357/oh-my-pi","slug":"unsupported-rar4-ppmd-compressed-block","errorCode":null,"errorMessage":"Unsupported RAR4 PPMd compressed block","messagePattern":"Unsupported RAR4 PPMd compressed block","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/rar/rar4-decoder.ts","lineNumber":176,"sourceCode":"\t\tconst prior =\n\t\t\tthis.#history.byteLength > dictionarySize\n\t\t\t\t? this.#history.subarray(this.#history.byteLength - dictionarySize)\n\t\t\t\t: this.#history;\n\t\tconst output = new Uint8Array(prior.byteLength + unpackedSize + 260);\n\t\toutput.set(prior);\n\t\tconst outputStart = prior.byteLength;\n\t\tconst outputEnd = outputStart + unpackedSize;\n\t\tlet outputPosition = outputStart;\n\t\tconst bits = new Bits(packed);\n\t\tconst main = new Huffman(MAIN_SIZE);\n\t\tconst distanceDecoder = new Huffman(DIST_SIZE);\n\t\tconst lowDistanceDecoder = new Huffman(LOW_DIST_SIZE);\n\t\tconst lengthDecoder = new Huffman(LEN_SIZE);\n\t\tconst filters: PendingFilter[] = [];\n\n\t\tconst readTables = (): void => {\n\t\t\tbits.align();\n\t\t\tif (bits.read(1) !== 0) throw new ArchiveError(\"Unsupported RAR4 PPMd compressed block\");\n\t\t\tconst keepPrevious = bits.read(1) !== 0;\n\t\t\tthis.#previousLowDistance = 0;\n\t\t\tthis.#lowDistanceRepeats = 0;\n\t\t\tif (!keepPrevious) this.#carriedLengths.fill(0);\n\t\t\tconst lengths = readLengthTable(bits, this.#carriedLengths, TOTAL_SIZE);\n\t\t\tlet offset = 0;\n\t\t\tmain.build(lengths, offset, MAIN_SIZE);\n\t\t\toffset += MAIN_SIZE;\n\t\t\tdistanceDecoder.build(lengths, offset, DIST_SIZE);\n\t\t\toffset += DIST_SIZE;\n\t\t\tlowDistanceDecoder.build(lengths, offset, LOW_DIST_SIZE);\n\t\t\toffset += LOW_DIST_SIZE;\n\t\t\tlengthDecoder.build(lengths, offset, LEN_SIZE);\n\t\t\tthis.#carriedLengths.set(lengths);\n\t\t};\n\n\t\tconst copyMatch = (distance: number, length: number): void => {\n\t\t\tif (distance <= 0 || distance > dictionarySize || distance > outputPosition) corrupt(\"invalid LZ distance\");","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/rar/rar4-decoder.ts#L158-L194","documentation":"readTables in the RAR4 decoder reads a block-type bit from the compressed stream: a 1 indicates a PPMd (PPM version with variant H) compressed block. The decoder only implements the LZSS+Huffman path, so PPMd blocks are rejected with this error rather than producing garbage output.","triggerScenarios":"Decoding a RAR4 file whose archive creator selected PPMd compression (RAR 3.x 'ppmd' method, -mcppmd or compression method 3–5 with PPMd) and the decoder reaches the block-table reader and sees the PPMd flag bit set.","commonSituations":"Archives compressed with WinRAR's PPMd option; archives where large text payloads were stored with PPMd for better ratios; extracting only some members works (LZ ones) while PPMd ones fail.","solutions":["Repack the archive using standard LZ compression in WinRAR/7-Zip (avoid the PPMd option), then retry.","Extract with a full-featured tool (7-Zip, unrar) that supports PPMd and feed the unpacked files to this library.","Detect the RAR compression method up front and warn/fallback for PPMd members instead of failing mid-extract.","If the flag bit appears in an implausible position, suspect corruption — validate the archive with an external tool."],"exampleFix":"// before\nawait extractArchive(\"text-heavy.ppmd.rar\", dest);\n// after (shell pre-conversion)\n7z x text-heavy.ppmd.rar -otmp && 7z a -mx=9 text-heavy.lz.zip ./tmp/*","handlingStrategy":"fallback","validationCode":"// Inspect the RAR main/file header compression method; PPMd is method 3-5 with the PPMd flag.\n// If a member uses PPMd, route it to an external extractor instead of this decoder.\nconst usesPpmd = detectRarCompressionMethod(p) === \"ppmd\";\nif (usesPpmd) return extractWithExternalTool(p, dest);","typeGuard":null,"tryCatchPattern":"try {\n  await extractArchive(p, dest);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"PPMd\")) {\n    return extractWith7zip(p, dest); // fallback decoder\n  }\n  throw err;\n}","preventionTips":["Repack RAR archives with standard LZ compression (not PPMd) before automated processing.","Keep a full-featured fallback extractor (7z/unrar) available for exotic compression methods.","Pre-scan member compression methods and warn before attempting extraction.","Normalize incoming archives to zip/tar in ingestion pipelines."],"tags":["archive","rar","rar4","ppmd","unsupported-compression"],"backgroundTag":"unsupported-compression-method","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}