7z-iterator 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/cjs/SevenZipIterator.js +2 -0
  2. package/dist/cjs/SevenZipIterator.js.map +1 -1
  3. package/dist/cjs/lib/Lock.d.cts +1 -0
  4. package/dist/cjs/lib/Lock.d.ts +1 -0
  5. package/dist/cjs/lib/Lock.js +8 -0
  6. package/dist/cjs/lib/Lock.js.map +1 -1
  7. package/dist/cjs/nextEntry.js +2 -2
  8. package/dist/cjs/nextEntry.js.map +1 -1
  9. package/dist/cjs/sevenz/NumberCodec.d.cts +9 -0
  10. package/dist/cjs/sevenz/NumberCodec.d.ts +9 -0
  11. package/dist/cjs/sevenz/NumberCodec.js +39 -14
  12. package/dist/cjs/sevenz/NumberCodec.js.map +1 -1
  13. package/dist/cjs/sevenz/SevenZipParser.d.cts +13 -0
  14. package/dist/cjs/sevenz/SevenZipParser.d.ts +13 -0
  15. package/dist/cjs/sevenz/SevenZipParser.js +250 -11
  16. package/dist/cjs/sevenz/SevenZipParser.js.map +1 -1
  17. package/dist/cjs/sevenz/codecs/Bcj2.d.cts +16 -0
  18. package/dist/cjs/sevenz/codecs/Bcj2.d.ts +16 -0
  19. package/dist/cjs/sevenz/codecs/Bcj2.js +201 -0
  20. package/dist/cjs/sevenz/codecs/Bcj2.js.map +1 -0
  21. package/dist/cjs/sevenz/codecs/Lzma2.js +54 -10
  22. package/dist/cjs/sevenz/codecs/Lzma2.js.map +1 -1
  23. package/dist/cjs/sevenz/codecs/index.d.cts +6 -0
  24. package/dist/cjs/sevenz/codecs/index.d.ts +6 -0
  25. package/dist/cjs/sevenz/codecs/index.js +17 -0
  26. package/dist/cjs/sevenz/codecs/index.js.map +1 -1
  27. package/dist/cjs/sevenz/constants.d.cts +1 -0
  28. package/dist/cjs/sevenz/constants.d.ts +1 -0
  29. package/dist/cjs/sevenz/constants.js +6 -0
  30. package/dist/cjs/sevenz/constants.js.map +1 -1
  31. package/dist/cjs/types.d.cts +1 -0
  32. package/dist/cjs/types.d.ts +1 -0
  33. package/dist/cjs/types.js.map +1 -1
  34. package/dist/esm/SevenZipIterator.js +2 -0
  35. package/dist/esm/SevenZipIterator.js.map +1 -1
  36. package/dist/esm/lib/Lock.d.ts +1 -0
  37. package/dist/esm/lib/Lock.js +8 -0
  38. package/dist/esm/lib/Lock.js.map +1 -1
  39. package/dist/esm/nextEntry.js +2 -2
  40. package/dist/esm/nextEntry.js.map +1 -1
  41. package/dist/esm/sevenz/NumberCodec.d.ts +9 -0
  42. package/dist/esm/sevenz/NumberCodec.js +48 -14
  43. package/dist/esm/sevenz/NumberCodec.js.map +1 -1
  44. package/dist/esm/sevenz/SevenZipParser.d.ts +13 -0
  45. package/dist/esm/sevenz/SevenZipParser.js +251 -12
  46. package/dist/esm/sevenz/SevenZipParser.js.map +1 -1
  47. package/dist/esm/sevenz/codecs/Bcj2.d.ts +16 -0
  48. package/dist/esm/sevenz/codecs/Bcj2.js +183 -0
  49. package/dist/esm/sevenz/codecs/Bcj2.js.map +1 -0
  50. package/dist/esm/sevenz/codecs/Lzma2.js +54 -10
  51. package/dist/esm/sevenz/codecs/Lzma2.js.map +1 -1
  52. package/dist/esm/sevenz/codecs/index.d.ts +6 -0
  53. package/dist/esm/sevenz/codecs/index.js +15 -0
  54. package/dist/esm/sevenz/codecs/index.js.map +1 -1
  55. package/dist/esm/sevenz/constants.d.ts +1 -0
  56. package/dist/esm/sevenz/constants.js +6 -0
  57. package/dist/esm/sevenz/constants.js.map +1 -1
  58. package/dist/esm/types.d.ts +1 -0
  59. package/dist/esm/types.js.map +1 -1
  60. package/package.json +9 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/SevenZipIterator.ts"],"sourcesContent":["import BaseIterator from 'extract-base-iterator';\nimport fs from 'fs';\nimport os from 'os';\nimport osShim from 'os-shim';\nimport path from 'path';\nimport Queue from 'queue-cb';\nimport shortHash from 'short-hash';\nimport tempSuffix from 'temp-suffix';\nimport Lock from './lib/Lock.ts';\nimport streamToSource, { type SourceResult } from './lib/streamToSource.ts';\nimport nextEntry from './nextEntry.ts';\nimport { setPassword } from './sevenz/codecs/index.ts';\nimport { type ArchiveSource, FileSource, type SevenZipEntry, SevenZipParser } from './sevenz/SevenZipParser.ts';\n\nvar tmpdir = os.tmpdir || osShim.tmpdir;\n\nimport type { ExtractOptions, LockT, SevenZipFileIterator } from './types.ts';\n\n/**\n * Iterator wrapper around SevenZipParser entries\n */\nclass EntryIterator implements SevenZipFileIterator {\n private parser: SevenZipParser;\n private entries: SevenZipEntry[];\n private index = 0;\n\n constructor(parser: SevenZipParser) {\n this.parser = parser;\n this.entries = parser.getEntries();\n }\n\n next(): SevenZipEntry | null {\n if (this.index >= this.entries.length) {\n return null;\n }\n return this.entries[this.index++];\n }\n\n getParser(): SevenZipParser {\n return this.parser;\n }\n}\n\nexport default class SevenZipIterator extends BaseIterator {\n lock: LockT;\n iterator: SevenZipFileIterator;\n\n constructor(source: string | NodeJS.ReadableStream, options: ExtractOptions = {}) {\n super(options);\n this.lock = new Lock();\n this.lock.iterator = this;\n var queue = new Queue(1);\n var cancelled = false;\n var archiveSource: ArchiveSource | null = null;\n var setup = (): undefined => {\n cancelled = true;\n return undefined;\n };\n this.processing.push(setup);\n\n // Set password (or clear if not provided)\n setPassword(options.password || null);\n\n if (typeof source === 'string') {\n // File path input - use FileSource directly\n queue.defer((cb: (err?: Error) => void) => {\n fs.stat(source, (statErr, stats) => {\n if (this.done || cancelled) return;\n if (statErr) return cb(statErr);\n\n fs.open(source, 'r', (err, fd) => {\n if (this.done || cancelled) return;\n if (err) return cb(err);\n\n archiveSource = new FileSource(fd, stats.size);\n this.lock.fd = fd;\n cb();\n });\n });\n });\n } else {\n // Stream input - use hybrid memory/temp-file approach\n var tempPath = path.join(tmpdir(), '7z-iterator', shortHash(process.cwd()), tempSuffix('tmp.7z'));\n queue.defer((cb: (err?: Error) => void) => {\n streamToSource(\n source,\n {\n memoryThreshold: options.memoryThreshold,\n tempPath: tempPath,\n },\n (err?: Error, result?: SourceResult) => {\n if (this.done || cancelled) return;\n if (err) return cb(err);\n if (!result) return cb(new Error('No result from streamToSource'));\n\n archiveSource = result.source;\n if (result.fd !== undefined) {\n this.lock.fd = result.fd;\n }\n if (result.tempPath) {\n this.lock.tempPath = result.tempPath;\n }\n cb();\n }\n );\n });\n }\n\n // Parse and build iterator\n queue.defer((cb: (err?: Error) => void) => {\n if (this.done || cancelled) return;\n if (!archiveSource) return cb(new Error('No archive source'));\n\n try {\n var parser = new SevenZipParser(archiveSource);\n parser.parse();\n this.iterator = new EntryIterator(parser);\n cb();\n } catch (parseErr) {\n cb(parseErr as Error);\n }\n });\n\n // start processing\n queue.await((err?: Error) => {\n this.processing.remove(setup);\n if (this.done || cancelled) return;\n err ? this.end(err) : this.push(nextEntry);\n });\n }\n\n end(err?: Error) {\n if (this.lock) {\n const lock = this.lock;\n this.lock = null; // Clear before release to prevent re-entrancy\n lock.err = err;\n lock.release();\n }\n // Don't call base end here - Lock.__destroy() handles it\n this.iterator = null;\n }\n}\n"],"names":["BaseIterator","fs","os","osShim","path","Queue","shortHash","tempSuffix","Lock","streamToSource","nextEntry","setPassword","FileSource","SevenZipParser","tmpdir","EntryIterator","next","index","entries","length","getParser","parser","getEntries","SevenZipIterator","end","err","lock","release","iterator","source","options","queue","cancelled","archiveSource","setup","undefined","processing","push","password","defer","cb","stat","statErr","stats","done","open","fd","size","tempPath","join","process","cwd","memoryThreshold","result","Error","parse","parseErr","await","remove"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/SevenZipIterator.ts"],"sourcesContent":["import BaseIterator from 'extract-base-iterator';\nimport fs from 'fs';\nimport os from 'os';\nimport osShim from 'os-shim';\nimport path from 'path';\nimport Queue from 'queue-cb';\nimport shortHash from 'short-hash';\nimport tempSuffix from 'temp-suffix';\nimport Lock from './lib/Lock.ts';\nimport streamToSource, { type SourceResult } from './lib/streamToSource.ts';\nimport nextEntry from './nextEntry.ts';\nimport { setPassword } from './sevenz/codecs/index.ts';\nimport { type ArchiveSource, FileSource, type SevenZipEntry, SevenZipParser } from './sevenz/SevenZipParser.ts';\n\nvar tmpdir = os.tmpdir || osShim.tmpdir;\n\nimport type { ExtractOptions, LockT, SevenZipFileIterator } from './types.ts';\n\n/**\n * Iterator wrapper around SevenZipParser entries\n */\nclass EntryIterator implements SevenZipFileIterator {\n private parser: SevenZipParser;\n private entries: SevenZipEntry[];\n private index = 0;\n\n constructor(parser: SevenZipParser) {\n this.parser = parser;\n this.entries = parser.getEntries();\n }\n\n next(): SevenZipEntry | null {\n if (this.index >= this.entries.length) {\n return null;\n }\n return this.entries[this.index++];\n }\n\n getParser(): SevenZipParser {\n return this.parser;\n }\n}\n\nexport default class SevenZipIterator extends BaseIterator {\n lock: LockT;\n iterator: SevenZipFileIterator;\n\n constructor(source: string | NodeJS.ReadableStream, options: ExtractOptions = {}) {\n super(options);\n this.lock = new Lock();\n this.lock.iterator = this;\n var queue = new Queue(1);\n var cancelled = false;\n var archiveSource: ArchiveSource | null = null;\n var setup = (): undefined => {\n cancelled = true;\n return undefined;\n };\n this.processing.push(setup);\n\n // Set password (or clear if not provided)\n setPassword(options.password || null);\n\n if (typeof source === 'string') {\n // File path input - use FileSource directly\n queue.defer((cb: (err?: Error) => void) => {\n fs.stat(source, (statErr, stats) => {\n if (this.done || cancelled) return;\n if (statErr) return cb(statErr);\n\n fs.open(source, 'r', (err, fd) => {\n if (this.done || cancelled) return;\n if (err) return cb(err);\n\n archiveSource = new FileSource(fd, stats.size);\n this.lock.fd = fd;\n cb();\n });\n });\n });\n } else {\n // Stream input - use hybrid memory/temp-file approach\n // Store source stream in lock for cleanup if destroyed during download\n this.lock.sourceStream = source as NodeJS.ReadableStream;\n var tempPath = path.join(tmpdir(), '7z-iterator', shortHash(process.cwd()), tempSuffix('tmp.7z'));\n queue.defer((cb: (err?: Error) => void) => {\n streamToSource(\n source,\n {\n memoryThreshold: options.memoryThreshold,\n tempPath: tempPath,\n },\n (err?: Error, result?: SourceResult) => {\n if (this.done || cancelled) return;\n if (err) return cb(err);\n if (!result) return cb(new Error('No result from streamToSource'));\n\n archiveSource = result.source;\n if (result.fd !== undefined) {\n this.lock.fd = result.fd;\n }\n if (result.tempPath) {\n this.lock.tempPath = result.tempPath;\n }\n cb();\n }\n );\n });\n }\n\n // Parse and build iterator\n queue.defer((cb: (err?: Error) => void) => {\n if (this.done || cancelled) return;\n if (!archiveSource) return cb(new Error('No archive source'));\n\n try {\n var parser = new SevenZipParser(archiveSource);\n parser.parse();\n this.iterator = new EntryIterator(parser);\n cb();\n } catch (parseErr) {\n cb(parseErr as Error);\n }\n });\n\n // start processing\n queue.await((err?: Error) => {\n this.processing.remove(setup);\n if (this.done || cancelled) return;\n err ? this.end(err) : this.push(nextEntry);\n });\n }\n\n end(err?: Error) {\n if (this.lock) {\n const lock = this.lock;\n this.lock = null; // Clear before release to prevent re-entrancy\n lock.err = err;\n lock.release();\n }\n // Don't call base end here - Lock.__destroy() handles it\n this.iterator = null;\n }\n}\n"],"names":["BaseIterator","fs","os","osShim","path","Queue","shortHash","tempSuffix","Lock","streamToSource","nextEntry","setPassword","FileSource","SevenZipParser","tmpdir","EntryIterator","next","index","entries","length","getParser","parser","getEntries","SevenZipIterator","end","err","lock","release","iterator","source","options","queue","cancelled","archiveSource","setup","undefined","processing","push","password","defer","cb","stat","statErr","stats","done","open","fd","size","sourceStream","tempPath","join","process","cwd","memoryThreshold","result","Error","parse","parseErr","await","remove"],"mappings":"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"}
@@ -5,6 +5,7 @@ export default class Lock {
5
5
  fd: number;
6
6
  iterator: BaseIterator;
7
7
  err: Error;
8
+ sourceStream: NodeJS.ReadableStream;
8
9
  retain(): void;
9
10
  release(): void;
10
11
  private __destroy;
@@ -11,6 +11,12 @@ let Lock = class Lock {
11
11
  if (this.count === 0) this.__destroy();
12
12
  }
13
13
  __destroy() {
14
+ // Destroy source stream FIRST to stop data flow (e.g., during download)
15
+ if (this.sourceStream) {
16
+ const stream = this.sourceStream;
17
+ if (typeof stream.destroy === 'function') stream.destroy();
18
+ this.sourceStream = null;
19
+ }
14
20
  if (this.tempPath) {
15
21
  try {
16
22
  rimraf2.sync(this.tempPath, {
@@ -36,6 +42,8 @@ let Lock = class Lock {
36
42
  this.fd = null;
37
43
  this.iterator = null;
38
44
  this.err = null;
45
+ // cleanup resources
46
+ this.sourceStream = null;
39
47
  }
40
48
  };
41
49
  export { Lock as default };
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/lib/Lock.ts"],"sourcesContent":["import BaseIterator from 'extract-base-iterator';\nimport fs from 'fs';\nimport rimraf2 from 'rimraf2';\n\nexport default class Lock {\n private count = 1;\n\n // members\n tempPath: string = null;\n fd: number = null;\n iterator: BaseIterator = null;\n err: Error = null;\n\n retain() {\n this.count++;\n }\n\n release() {\n if (this.count <= 0) throw new Error('Lock count is corrupted');\n this.count--;\n if (this.count === 0) this.__destroy();\n }\n\n private __destroy() {\n if (this.tempPath) {\n try {\n rimraf2.sync(this.tempPath, { disableGlob: true });\n } catch (_err) {\n /* empty */\n }\n this.tempPath = null;\n }\n\n if (this.fd) {\n fs.closeSync(this.fd);\n this.fd = null;\n }\n\n if (this.iterator) {\n BaseIterator.prototype.end.call(this.iterator, this.err || null);\n this.iterator = null;\n }\n }\n}\n"],"names":["BaseIterator","fs","rimraf2","Lock","retain","count","release","Error","__destroy","tempPath","sync","disableGlob","_err","fd","closeSync","iterator","prototype","end","call","err"],"mappings":"AAAA,OAAOA,kBAAkB,wBAAwB;AACjD,OAAOC,QAAQ,KAAK;AACpB,OAAOC,aAAa,UAAU;AAEf,IAAA,AAAMC,OAAN,MAAMA;IASnBC,SAAS;QACP,IAAI,CAACC,KAAK;IACZ;IAEAC,UAAU;QACR,IAAI,IAAI,CAACD,KAAK,IAAI,GAAG,MAAM,IAAIE,MAAM;QACrC,IAAI,CAACF,KAAK;QACV,IAAI,IAAI,CAACA,KAAK,KAAK,GAAG,IAAI,CAACG,SAAS;IACtC;IAEQA,YAAY;QAClB,IAAI,IAAI,CAACC,QAAQ,EAAE;YACjB,IAAI;gBACFP,QAAQQ,IAAI,CAAC,IAAI,CAACD,QAAQ,EAAE;oBAAEE,aAAa;gBAAK;YAClD,EAAE,OAAOC,MAAM;YACb,SAAS,GACX;YACA,IAAI,CAACH,QAAQ,GAAG;QAClB;QAEA,IAAI,IAAI,CAACI,EAAE,EAAE;YACXZ,GAAGa,SAAS,CAAC,IAAI,CAACD,EAAE;YACpB,IAAI,CAACA,EAAE,GAAG;QACZ;QAEA,IAAI,IAAI,CAACE,QAAQ,EAAE;YACjBf,aAAagB,SAAS,CAACC,GAAG,CAACC,IAAI,CAAC,IAAI,CAACH,QAAQ,EAAE,IAAI,CAACI,GAAG,IAAI;YAC3D,IAAI,CAACJ,QAAQ,GAAG;QAClB;IACF;;aArCQV,QAAQ;QAEhB,UAAU;aACVI,WAAmB;aACnBI,KAAa;aACbE,WAAyB;aACzBI,MAAa;;AAgCf;AAvCA,SAAqBhB,kBAuCpB"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/lib/Lock.ts"],"sourcesContent":["import BaseIterator from 'extract-base-iterator';\nimport fs from 'fs';\nimport rimraf2 from 'rimraf2';\n\nexport default class Lock {\n private count = 1;\n\n // members\n tempPath: string = null;\n fd: number = null;\n iterator: BaseIterator = null;\n err: Error = null;\n\n // cleanup resources\n sourceStream: NodeJS.ReadableStream = null;\n\n retain() {\n this.count++;\n }\n\n release() {\n if (this.count <= 0) throw new Error('Lock count is corrupted');\n this.count--;\n if (this.count === 0) this.__destroy();\n }\n\n private __destroy() {\n // Destroy source stream FIRST to stop data flow (e.g., during download)\n if (this.sourceStream) {\n const stream = this.sourceStream as NodeJS.ReadableStream & { destroy?: () => void };\n if (typeof stream.destroy === 'function') stream.destroy();\n this.sourceStream = null;\n }\n\n if (this.tempPath) {\n try {\n rimraf2.sync(this.tempPath, { disableGlob: true });\n } catch (_err) {\n /* empty */\n }\n this.tempPath = null;\n }\n\n if (this.fd) {\n fs.closeSync(this.fd);\n this.fd = null;\n }\n\n if (this.iterator) {\n BaseIterator.prototype.end.call(this.iterator, this.err || null);\n this.iterator = null;\n }\n }\n}\n"],"names":["BaseIterator","fs","rimraf2","Lock","retain","count","release","Error","__destroy","sourceStream","stream","destroy","tempPath","sync","disableGlob","_err","fd","closeSync","iterator","prototype","end","call","err"],"mappings":"AAAA,OAAOA,kBAAkB,wBAAwB;AACjD,OAAOC,QAAQ,KAAK;AACpB,OAAOC,aAAa,UAAU;AAEf,IAAA,AAAMC,OAAN,MAAMA;IAYnBC,SAAS;QACP,IAAI,CAACC,KAAK;IACZ;IAEAC,UAAU;QACR,IAAI,IAAI,CAACD,KAAK,IAAI,GAAG,MAAM,IAAIE,MAAM;QACrC,IAAI,CAACF,KAAK;QACV,IAAI,IAAI,CAACA,KAAK,KAAK,GAAG,IAAI,CAACG,SAAS;IACtC;IAEQA,YAAY;QAClB,wEAAwE;QACxE,IAAI,IAAI,CAACC,YAAY,EAAE;YACrB,MAAMC,SAAS,IAAI,CAACD,YAAY;YAChC,IAAI,OAAOC,OAAOC,OAAO,KAAK,YAAYD,OAAOC,OAAO;YACxD,IAAI,CAACF,YAAY,GAAG;QACtB;QAEA,IAAI,IAAI,CAACG,QAAQ,EAAE;YACjB,IAAI;gBACFV,QAAQW,IAAI,CAAC,IAAI,CAACD,QAAQ,EAAE;oBAAEE,aAAa;gBAAK;YAClD,EAAE,OAAOC,MAAM;YACb,SAAS,GACX;YACA,IAAI,CAACH,QAAQ,GAAG;QAClB;QAEA,IAAI,IAAI,CAACI,EAAE,EAAE;YACXf,GAAGgB,SAAS,CAAC,IAAI,CAACD,EAAE;YACpB,IAAI,CAACA,EAAE,GAAG;QACZ;QAEA,IAAI,IAAI,CAACE,QAAQ,EAAE;YACjBlB,aAAamB,SAAS,CAACC,GAAG,CAACC,IAAI,CAAC,IAAI,CAACH,QAAQ,EAAE,IAAI,CAACI,GAAG,IAAI;YAC3D,IAAI,CAACJ,QAAQ,GAAG;QAClB;IACF;;aA/CQb,QAAQ;QAEhB,UAAU;aACVO,WAAmB;aACnBI,KAAa;aACbE,WAAyB;aACzBI,MAAa;QAEb,oBAAoB;aACpBb,eAAsC;;AAuCxC;AAjDA,SAAqBN,kBAiDpB"}
@@ -21,8 +21,8 @@ export default function nextEntry(iterator, callback) {
21
21
  value: null
22
22
  });
23
23
  });
24
- // done: signal iteration is complete
25
- if (iterator.isDone() || !entry) return callback(null, {
24
+ // done: signal iteration is complete (guard against stale lock)
25
+ if (!iterator.lock || iterator.isDone() || !entry) return callback(null, {
26
26
  done: true,
27
27
  value: null
28
28
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/nextEntry.ts"],"sourcesContent":["import once from 'call-once-fn';\nimport { type DirectoryAttributes, DirectoryEntry, type FileAttributes, type LinkAttributes, SymbolicLinkEntry } from 'extract-base-iterator';\nimport compact from 'lodash.compact';\nimport path from 'path';\nimport FileEntry from './FileEntry.ts';\nimport type SevenZipIterator from './SevenZipIterator.ts';\nimport type { SevenZipEntry } from './sevenz/SevenZipParser.ts';\nimport type { Entry, EntryCallback } from './types.ts';\n\nexport type NextCallback = (error?: Error, entry?: Entry) => undefined;\n\n// Entry attributes object that gets mutated in switch - union of possible shapes\n// mtime is number for FileAttributes compatibility (timestamp in ms)\ntype EntryAttributesBuilder = {\n path: string;\n basename: string;\n mtime: number;\n mode: number;\n type?: 'file' | 'directory';\n size?: number;\n};\n\nexport default function nextEntry<_T>(iterator: SevenZipIterator, callback: EntryCallback): undefined {\n if (!iterator.iterator) {\n callback(new Error('iterator missing'));\n return;\n }\n\n var entry: SevenZipEntry | null = null;\n entry = iterator.iterator.next();\n\n var nextCallback = once((err?: Error, entry?: Entry) => {\n // keep processing\n if (entry) iterator.push(nextEntry);\n err ? callback(err) : callback(null, entry ? { done: false, value: entry } : { done: true, value: null });\n }) as NextCallback;\n\n // done: signal iteration is complete\n if (iterator.isDone() || !entry) return callback(null, { done: true, value: null });\n\n // Skip anti-files (these mark files to delete in delta archives)\n if (entry.isAntiFile) {\n iterator.push(nextEntry);\n return callback(null, null);\n }\n\n // Determine type from entry\n var type = entry.type;\n\n // Default modes (decimal values for Node 0.8 compatibility)\n // 0o755 = 493, 0o644 = 420\n var defaultMode = type === 'directory' ? 493 : 420;\n\n // Build attributes from 7z entry\n // mtime must be timestamp (number) for FileAttributes compatibility\n var mtimeDate = entry.mtime || new Date();\n var attributes: EntryAttributesBuilder = {\n path: compact(entry.path.split(path.sep)).join(path.sep),\n basename: entry.name,\n mtime: mtimeDate.getTime(),\n mode: entry.mode !== undefined ? entry.mode : defaultMode,\n };\n\n switch (type) {\n case 'directory':\n attributes.type = 'directory';\n return nextCallback(null, new DirectoryEntry(attributes as DirectoryAttributes));\n\n case 'link': {\n // For symlinks, the file content IS the symlink target path\n // Read the content to get the linkpath for SymbolicLinkEntry\n var parser = iterator.iterator.getParser();\n var stream = parser.getEntryStream(entry);\n var chunks: Buffer[] = [];\n\n stream.on('data', (chunk: Buffer) => {\n chunks.push(chunk);\n });\n stream.on('end', () => {\n var linkpath = Buffer.concat(chunks).toString('utf8');\n\n var linkAttributes: LinkAttributes = {\n path: attributes.path,\n mtime: attributes.mtime,\n mode: attributes.mode,\n linkpath: linkpath,\n };\n\n nextCallback(null, new SymbolicLinkEntry(linkAttributes));\n });\n stream.on('error', (err: Error) => {\n nextCallback(err);\n });\n return;\n }\n\n case 'file': {\n attributes.type = 'file';\n attributes.size = entry.size;\n var parser2 = iterator.iterator.getParser();\n return nextCallback(null, new FileEntry(attributes as FileAttributes, entry, parser2, iterator.lock));\n }\n }\n\n return callback(new Error(`Unrecognized entry type: ${type}`));\n}\n"],"names":["once","DirectoryEntry","SymbolicLinkEntry","compact","path","FileEntry","nextEntry","iterator","callback","Error","entry","next","nextCallback","err","push","done","value","isDone","isAntiFile","type","defaultMode","mtimeDate","mtime","Date","attributes","split","sep","join","basename","name","getTime","mode","undefined","parser","getParser","stream","getEntryStream","chunks","on","chunk","linkpath","Buffer","concat","toString","linkAttributes","size","parser2","lock"],"mappings":"AAAA,OAAOA,UAAU,eAAe;AAChC,SAAmCC,cAAc,EAA4CC,iBAAiB,QAAQ,wBAAwB;AAC9I,OAAOC,aAAa,iBAAiB;AACrC,OAAOC,UAAU,OAAO;AACxB,OAAOC,eAAe,iBAAiB;AAkBvC,eAAe,SAASC,UAAcC,QAA0B,EAAEC,QAAuB;IACvF,IAAI,CAACD,SAASA,QAAQ,EAAE;QACtBC,SAAS,IAAIC,MAAM;QACnB;IACF;IAEA,IAAIC,QAA8B;IAClCA,QAAQH,SAASA,QAAQ,CAACI,IAAI;IAE9B,IAAIC,eAAeZ,KAAK,CAACa,KAAaH;QACpC,kBAAkB;QAClB,IAAIA,OAAOH,SAASO,IAAI,CAACR;QACzBO,MAAML,SAASK,OAAOL,SAAS,MAAME,QAAQ;YAAEK,MAAM;YAAOC,OAAON;QAAM,IAAI;YAAEK,MAAM;YAAMC,OAAO;QAAK;IACzG;IAEA,qCAAqC;IACrC,IAAIT,SAASU,MAAM,MAAM,CAACP,OAAO,OAAOF,SAAS,MAAM;QAAEO,MAAM;QAAMC,OAAO;IAAK;IAEjF,iEAAiE;IACjE,IAAIN,MAAMQ,UAAU,EAAE;QACpBX,SAASO,IAAI,CAACR;QACd,OAAOE,SAAS,MAAM;IACxB;IAEA,4BAA4B;IAC5B,IAAIW,OAAOT,MAAMS,IAAI;IAErB,4DAA4D;IAC5D,2BAA2B;IAC3B,IAAIC,cAAcD,SAAS,cAAc,MAAM;IAE/C,iCAAiC;IACjC,oEAAoE;IACpE,IAAIE,YAAYX,MAAMY,KAAK,IAAI,IAAIC;IACnC,IAAIC,aAAqC;QACvCpB,MAAMD,QAAQO,MAAMN,IAAI,CAACqB,KAAK,CAACrB,KAAKsB,GAAG,GAAGC,IAAI,CAACvB,KAAKsB,GAAG;QACvDE,UAAUlB,MAAMmB,IAAI;QACpBP,OAAOD,UAAUS,OAAO;QACxBC,MAAMrB,MAAMqB,IAAI,KAAKC,YAAYtB,MAAMqB,IAAI,GAAGX;IAChD;IAEA,OAAQD;QACN,KAAK;YACHK,WAAWL,IAAI,GAAG;YAClB,OAAOP,aAAa,MAAM,IAAIX,eAAeuB;QAE/C,KAAK;YAAQ;gBACX,4DAA4D;gBAC5D,6DAA6D;gBAC7D,IAAIS,SAAS1B,SAASA,QAAQ,CAAC2B,SAAS;gBACxC,IAAIC,SAASF,OAAOG,cAAc,CAAC1B;gBACnC,IAAI2B,SAAmB,EAAE;gBAEzBF,OAAOG,EAAE,CAAC,QAAQ,CAACC;oBACjBF,OAAOvB,IAAI,CAACyB;gBACd;gBACAJ,OAAOG,EAAE,CAAC,OAAO;oBACf,IAAIE,WAAWC,OAAOC,MAAM,CAACL,QAAQM,QAAQ,CAAC;oBAE9C,IAAIC,iBAAiC;wBACnCxC,MAAMoB,WAAWpB,IAAI;wBACrBkB,OAAOE,WAAWF,KAAK;wBACvBS,MAAMP,WAAWO,IAAI;wBACrBS,UAAUA;oBACZ;oBAEA5B,aAAa,MAAM,IAAIV,kBAAkB0C;gBAC3C;gBACAT,OAAOG,EAAE,CAAC,SAAS,CAACzB;oBAClBD,aAAaC;gBACf;gBACA;YACF;QAEA,KAAK;YAAQ;gBACXW,WAAWL,IAAI,GAAG;gBAClBK,WAAWqB,IAAI,GAAGnC,MAAMmC,IAAI;gBAC5B,IAAIC,UAAUvC,SAASA,QAAQ,CAAC2B,SAAS;gBACzC,OAAOtB,aAAa,MAAM,IAAIP,UAAUmB,YAA8Bd,OAAOoC,SAASvC,SAASwC,IAAI;YACrG;IACF;IAEA,OAAOvC,SAAS,IAAIC,MAAM,CAAC,yBAAyB,EAAEU,MAAM;AAC9D"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/nextEntry.ts"],"sourcesContent":["import once from 'call-once-fn';\nimport { type DirectoryAttributes, DirectoryEntry, type FileAttributes, type LinkAttributes, SymbolicLinkEntry } from 'extract-base-iterator';\nimport compact from 'lodash.compact';\nimport path from 'path';\nimport FileEntry from './FileEntry.ts';\nimport type SevenZipIterator from './SevenZipIterator.ts';\nimport type { SevenZipEntry } from './sevenz/SevenZipParser.ts';\nimport type { Entry, EntryCallback } from './types.ts';\n\nexport type NextCallback = (error?: Error, entry?: Entry) => undefined;\n\n// Entry attributes object that gets mutated in switch - union of possible shapes\n// mtime is number for FileAttributes compatibility (timestamp in ms)\ntype EntryAttributesBuilder = {\n path: string;\n basename: string;\n mtime: number;\n mode: number;\n type?: 'file' | 'directory';\n size?: number;\n};\n\nexport default function nextEntry<_T>(iterator: SevenZipIterator, callback: EntryCallback): undefined {\n if (!iterator.iterator) {\n callback(new Error('iterator missing'));\n return;\n }\n\n var entry: SevenZipEntry | null = null;\n entry = iterator.iterator.next();\n\n var nextCallback = once((err?: Error, entry?: Entry) => {\n // keep processing\n if (entry) iterator.push(nextEntry);\n err ? callback(err) : callback(null, entry ? { done: false, value: entry } : { done: true, value: null });\n }) as NextCallback;\n\n // done: signal iteration is complete (guard against stale lock)\n if (!iterator.lock || iterator.isDone() || !entry) return callback(null, { done: true, value: null });\n\n // Skip anti-files (these mark files to delete in delta archives)\n if (entry.isAntiFile) {\n iterator.push(nextEntry);\n return callback(null, null);\n }\n\n // Determine type from entry\n var type = entry.type;\n\n // Default modes (decimal values for Node 0.8 compatibility)\n // 0o755 = 493, 0o644 = 420\n var defaultMode = type === 'directory' ? 493 : 420;\n\n // Build attributes from 7z entry\n // mtime must be timestamp (number) for FileAttributes compatibility\n var mtimeDate = entry.mtime || new Date();\n var attributes: EntryAttributesBuilder = {\n path: compact(entry.path.split(path.sep)).join(path.sep),\n basename: entry.name,\n mtime: mtimeDate.getTime(),\n mode: entry.mode !== undefined ? entry.mode : defaultMode,\n };\n\n switch (type) {\n case 'directory':\n attributes.type = 'directory';\n return nextCallback(null, new DirectoryEntry(attributes as DirectoryAttributes));\n\n case 'link': {\n // For symlinks, the file content IS the symlink target path\n // Read the content to get the linkpath for SymbolicLinkEntry\n var parser = iterator.iterator.getParser();\n var stream = parser.getEntryStream(entry);\n var chunks: Buffer[] = [];\n\n stream.on('data', (chunk: Buffer) => {\n chunks.push(chunk);\n });\n stream.on('end', () => {\n var linkpath = Buffer.concat(chunks).toString('utf8');\n\n var linkAttributes: LinkAttributes = {\n path: attributes.path,\n mtime: attributes.mtime,\n mode: attributes.mode,\n linkpath: linkpath,\n };\n\n nextCallback(null, new SymbolicLinkEntry(linkAttributes));\n });\n stream.on('error', (err: Error) => {\n nextCallback(err);\n });\n return;\n }\n\n case 'file': {\n attributes.type = 'file';\n attributes.size = entry.size;\n var parser2 = iterator.iterator.getParser();\n return nextCallback(null, new FileEntry(attributes as FileAttributes, entry, parser2, iterator.lock));\n }\n }\n\n return callback(new Error(`Unrecognized entry type: ${type}`));\n}\n"],"names":["once","DirectoryEntry","SymbolicLinkEntry","compact","path","FileEntry","nextEntry","iterator","callback","Error","entry","next","nextCallback","err","push","done","value","lock","isDone","isAntiFile","type","defaultMode","mtimeDate","mtime","Date","attributes","split","sep","join","basename","name","getTime","mode","undefined","parser","getParser","stream","getEntryStream","chunks","on","chunk","linkpath","Buffer","concat","toString","linkAttributes","size","parser2"],"mappings":"AAAA,OAAOA,UAAU,eAAe;AAChC,SAAmCC,cAAc,EAA4CC,iBAAiB,QAAQ,wBAAwB;AAC9I,OAAOC,aAAa,iBAAiB;AACrC,OAAOC,UAAU,OAAO;AACxB,OAAOC,eAAe,iBAAiB;AAkBvC,eAAe,SAASC,UAAcC,QAA0B,EAAEC,QAAuB;IACvF,IAAI,CAACD,SAASA,QAAQ,EAAE;QACtBC,SAAS,IAAIC,MAAM;QACnB;IACF;IAEA,IAAIC,QAA8B;IAClCA,QAAQH,SAASA,QAAQ,CAACI,IAAI;IAE9B,IAAIC,eAAeZ,KAAK,CAACa,KAAaH;QACpC,kBAAkB;QAClB,IAAIA,OAAOH,SAASO,IAAI,CAACR;QACzBO,MAAML,SAASK,OAAOL,SAAS,MAAME,QAAQ;YAAEK,MAAM;YAAOC,OAAON;QAAM,IAAI;YAAEK,MAAM;YAAMC,OAAO;QAAK;IACzG;IAEA,gEAAgE;IAChE,IAAI,CAACT,SAASU,IAAI,IAAIV,SAASW,MAAM,MAAM,CAACR,OAAO,OAAOF,SAAS,MAAM;QAAEO,MAAM;QAAMC,OAAO;IAAK;IAEnG,iEAAiE;IACjE,IAAIN,MAAMS,UAAU,EAAE;QACpBZ,SAASO,IAAI,CAACR;QACd,OAAOE,SAAS,MAAM;IACxB;IAEA,4BAA4B;IAC5B,IAAIY,OAAOV,MAAMU,IAAI;IAErB,4DAA4D;IAC5D,2BAA2B;IAC3B,IAAIC,cAAcD,SAAS,cAAc,MAAM;IAE/C,iCAAiC;IACjC,oEAAoE;IACpE,IAAIE,YAAYZ,MAAMa,KAAK,IAAI,IAAIC;IACnC,IAAIC,aAAqC;QACvCrB,MAAMD,QAAQO,MAAMN,IAAI,CAACsB,KAAK,CAACtB,KAAKuB,GAAG,GAAGC,IAAI,CAACxB,KAAKuB,GAAG;QACvDE,UAAUnB,MAAMoB,IAAI;QACpBP,OAAOD,UAAUS,OAAO;QACxBC,MAAMtB,MAAMsB,IAAI,KAAKC,YAAYvB,MAAMsB,IAAI,GAAGX;IAChD;IAEA,OAAQD;QACN,KAAK;YACHK,WAAWL,IAAI,GAAG;YAClB,OAAOR,aAAa,MAAM,IAAIX,eAAewB;QAE/C,KAAK;YAAQ;gBACX,4DAA4D;gBAC5D,6DAA6D;gBAC7D,IAAIS,SAAS3B,SAASA,QAAQ,CAAC4B,SAAS;gBACxC,IAAIC,SAASF,OAAOG,cAAc,CAAC3B;gBACnC,IAAI4B,SAAmB,EAAE;gBAEzBF,OAAOG,EAAE,CAAC,QAAQ,CAACC;oBACjBF,OAAOxB,IAAI,CAAC0B;gBACd;gBACAJ,OAAOG,EAAE,CAAC,OAAO;oBACf,IAAIE,WAAWC,OAAOC,MAAM,CAACL,QAAQM,QAAQ,CAAC;oBAE9C,IAAIC,iBAAiC;wBACnCzC,MAAMqB,WAAWrB,IAAI;wBACrBmB,OAAOE,WAAWF,KAAK;wBACvBS,MAAMP,WAAWO,IAAI;wBACrBS,UAAUA;oBACZ;oBAEA7B,aAAa,MAAM,IAAIV,kBAAkB2C;gBAC3C;gBACAT,OAAOG,EAAE,CAAC,SAAS,CAAC1B;oBAClBD,aAAaC;gBACf;gBACA;YACF;QAEA,KAAK;YAAQ;gBACXY,WAAWL,IAAI,GAAG;gBAClBK,WAAWqB,IAAI,GAAGpC,MAAMoC,IAAI;gBAC5B,IAAIC,UAAUxC,SAASA,QAAQ,CAAC4B,SAAS;gBACzC,OAAOvB,aAAa,MAAM,IAAIP,UAAUoB,YAA8Bf,OAAOqC,SAASxC,SAASU,IAAI;YACrG;IACF;IAEA,OAAOT,SAAS,IAAIC,MAAM,CAAC,yBAAyB,EAAEW,MAAM;AAC9D"}
@@ -4,6 +4,15 @@ export interface NumberReadResult {
4
4
  }
5
5
  /**
6
6
  * Read a variable-length encoded number from a buffer
7
+ * Uses 7z's variable-length uint64 encoding where the first byte indicates
8
+ * how many additional bytes follow based on its value:
9
+ * - 0x00-0x7F: 0 extra bytes (7 bits of data)
10
+ * - 0x80-0xBF: 1 extra byte (14 bits of data)
11
+ * - 0xC0-0xDF: 2 extra bytes (21 bits of data)
12
+ * - 0xE0-0xEF: 3 extra bytes (28 bits of data)
13
+ * - etc.
14
+ * - 0xFF: 8 extra bytes (full 64-bit value)
15
+ *
7
16
  * @param buf - Buffer containing encoded number
8
17
  * @param offset - Offset to start reading from
9
18
  * @returns Object with value and number of bytes consumed
@@ -17,32 +17,66 @@
17
17
  import { readUInt64LE } from 'extract-base-iterator';
18
18
  /**
19
19
  * Read a variable-length encoded number from a buffer
20
+ * Uses 7z's variable-length uint64 encoding where the first byte indicates
21
+ * how many additional bytes follow based on its value:
22
+ * - 0x00-0x7F: 0 extra bytes (7 bits of data)
23
+ * - 0x80-0xBF: 1 extra byte (14 bits of data)
24
+ * - 0xC0-0xDF: 2 extra bytes (21 bits of data)
25
+ * - 0xE0-0xEF: 3 extra bytes (28 bits of data)
26
+ * - etc.
27
+ * - 0xFF: 8 extra bytes (full 64-bit value)
28
+ *
20
29
  * @param buf - Buffer containing encoded number
21
30
  * @param offset - Offset to start reading from
22
31
  * @returns Object with value and number of bytes consumed
23
32
  */ export function readNumber(buf, offset) {
24
33
  var firstByte = buf[offset];
25
- // Count leading 1 bits to determine extra bytes
26
- var mask = 0x80;
27
- var extraBytes = 0;
28
- while((firstByte & mask) !== 0 && extraBytes < 8){
29
- extraBytes++;
30
- mask = mask >>> 1;
31
- }
32
- // Special case: all 8 bits set means 8 extra bytes
33
- if (extraBytes === 8) {
34
- // Full 64-bit value follows
34
+ // Special case: 0xFF means 8 extra bytes (full 64-bit value)
35
+ if (firstByte === 0xff) {
35
36
  return {
36
37
  value: readUInt64LE(buf, offset + 1),
37
38
  bytesRead: 9
38
39
  };
39
40
  }
40
- // Mask off the length bits from first byte
41
- var value = firstByte & (mask - 1 | mask);
42
- // Add remaining bytes (big-endian order)
41
+ // Determine number of extra bytes based on first byte value thresholds
42
+ // This matches the 7z format specification
43
+ var extraBytes = 0;
44
+ var mask = 0x80;
45
+ if (firstByte <= 0x7f) {
46
+ extraBytes = 0;
47
+ mask = 0x80;
48
+ } else if (firstByte <= 0xbf) {
49
+ extraBytes = 1;
50
+ mask = 0x40;
51
+ } else if (firstByte <= 0xdf) {
52
+ extraBytes = 2;
53
+ mask = 0x20;
54
+ } else if (firstByte <= 0xef) {
55
+ extraBytes = 3;
56
+ mask = 0x10;
57
+ } else if (firstByte <= 0xf7) {
58
+ extraBytes = 4;
59
+ mask = 0x08;
60
+ } else if (firstByte <= 0xfb) {
61
+ extraBytes = 5;
62
+ mask = 0x04;
63
+ } else if (firstByte <= 0xfd) {
64
+ extraBytes = 6;
65
+ mask = 0x02;
66
+ } else {
67
+ // 0xFE
68
+ extraBytes = 7;
69
+ mask = 0x01;
70
+ }
71
+ // Get high part from first byte (bits below the length indicator)
72
+ var highPart = firstByte & mask - 1;
73
+ // Read extra bytes as LITTLE-ENDIAN
74
+ var value = 0;
43
75
  for(var i = 0; i < extraBytes; i++){
44
- value = value * 256 + buf[offset + 1 + i];
76
+ value += buf[offset + 1 + i] * 256 ** i;
45
77
  }
78
+ // Combine: value + (highPart << (extraBytes * 8))
79
+ value += highPart * 256 ** extraBytes;
46
80
  return {
47
81
  value: value,
48
82
  bytesRead: 1 + extraBytes
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/sevenz/NumberCodec.ts"],"sourcesContent":["// Variable-length integer encoding for 7z format\n// Reference: https://py7zr.readthedocs.io/en/latest/archive_format.html\n//\n// 7z uses a space-efficient encoding where the first byte determines length:\n// 0xxxxxxx -> 1 byte (0-127)\n// 10xxxxxx xxxxxxxx -> 2 bytes (0-16383)\n// 110xxxxx + 2 bytes -> 3 bytes\n// 1110xxxx + 3 bytes -> 4 bytes\n// 11110xxx + 4 bytes -> 5 bytes\n// 111110xx + 5 bytes -> 6 bytes\n// 1111110x + 6 bytes -> 7 bytes\n// 11111110 + 7 bytes -> 8 bytes\n// 11111111 + 8 bytes -> 9 bytes (full 64-bit)\n//\n// NOTE: Returns JavaScript number which is accurate up to 2^53 - 1 (~9 PB).\n// This covers all practical file sizes.\n\nimport { readUInt64LE } from 'extract-base-iterator';\n\nexport interface NumberReadResult {\n value: number;\n bytesRead: number;\n}\n\n/**\n * Read a variable-length encoded number from a buffer\n * @param buf - Buffer containing encoded number\n * @param offset - Offset to start reading from\n * @returns Object with value and number of bytes consumed\n */\nexport function readNumber(buf: Buffer, offset: number): NumberReadResult {\n var firstByte = buf[offset];\n\n // Count leading 1 bits to determine extra bytes\n var mask = 0x80;\n var extraBytes = 0;\n\n while ((firstByte & mask) !== 0 && extraBytes < 8) {\n extraBytes++;\n mask = mask >>> 1;\n }\n\n // Special case: all 8 bits set means 8 extra bytes\n if (extraBytes === 8) {\n // Full 64-bit value follows\n return {\n value: readUInt64LE(buf, offset + 1),\n bytesRead: 9,\n };\n }\n\n // Mask off the length bits from first byte\n var value = firstByte & ((mask - 1) | mask);\n\n // Add remaining bytes (big-endian order)\n for (var i = 0; i < extraBytes; i++) {\n value = value * 256 + buf[offset + 1 + i];\n }\n\n return {\n value: value,\n bytesRead: 1 + extraBytes,\n };\n}\n\n/**\n * Read a raw 64-bit little-endian number (used in some fixed-size fields)\n * @param buf - Buffer containing the number\n * @param offset - Offset to start reading from\n * @returns The number value\n */\nexport function readRawNumber(buf: Buffer, offset: number): number {\n return readUInt64LE(buf, offset);\n}\n\n/**\n * Calculate the encoded size of a number\n * @param value - The number to encode\n * @returns Number of bytes needed to encode the value\n */\nexport function encodedSize(value: number): number {\n if (value < 0x80) return 1; // 7 bits\n if (value < 0x4000) return 2; // 14 bits\n if (value < 0x200000) return 3; // 21 bits\n if (value < 0x10000000) return 4; // 28 bits\n if (value < 0x800000000) return 5; // 35 bits\n if (value < 0x40000000000) return 6; // 42 bits\n if (value < 0x2000000000000) return 7; // 49 bits\n // 2^56 = 72057594037927936 (use calculated value to avoid precision loss)\n if (value < 72057594037927936) return 8; // 56 bits\n return 9; // 64 bits\n}\n\n/**\n * Read a boolean encoded as a single byte\n * @param buf - Buffer to read from\n * @param offset - Offset to read from\n * @returns true if byte is non-zero\n */\nexport function readBoolean(buf: Buffer, offset: number): boolean {\n return buf[offset] !== 0;\n}\n\n/**\n * Read a \"defined\" bitmask for an array of items.\n * Used when some items in a list have optional values.\n *\n * Format: If \"allDefined\" byte is 0, a bitmask follows indicating which items have values.\n * If \"allDefined\" byte is non-zero, all items are defined.\n *\n * @param buf - Buffer to read from\n * @param offset - Offset to start reading\n * @param count - Number of items\n * @returns Object with defined array and bytes consumed\n */\nexport function readDefinedVector(buf: Buffer, offset: number, count: number): { defined: boolean[]; bytesRead: number } {\n var allDefined = buf[offset] !== 0;\n var bytesRead = 1;\n var defined: boolean[] = [];\n\n if (allDefined) {\n // All items are defined\n for (var i = 0; i < count; i++) {\n defined.push(true);\n }\n } else {\n // Read bitmask\n var bitsNeeded = count;\n var bytesNeeded = Math.ceil(bitsNeeded / 8);\n\n for (var byteIdx = 0; byteIdx < bytesNeeded; byteIdx++) {\n var byte = buf[offset + 1 + byteIdx];\n for (var bit = 7; bit >= 0 && defined.length < count; bit--) {\n defined.push((byte & (1 << bit)) !== 0);\n }\n }\n bytesRead += bytesNeeded;\n }\n\n return { defined: defined, bytesRead: bytesRead };\n}\n\n/**\n * Read an array of variable-length numbers\n * @param buf - Buffer to read from\n * @param offset - Offset to start reading\n * @param count - Number of items to read\n * @returns Object with values array and bytes consumed\n */\nexport function readNumberArray(buf: Buffer, offset: number, count: number): { values: number[]; bytesRead: number } {\n var values: number[] = [];\n var totalBytesRead = 0;\n\n for (var i = 0; i < count; i++) {\n var result = readNumber(buf, offset + totalBytesRead);\n values.push(result.value);\n totalBytesRead += result.bytesRead;\n }\n\n return { values: values, bytesRead: totalBytesRead };\n}\n"],"names":["readUInt64LE","readNumber","buf","offset","firstByte","mask","extraBytes","value","bytesRead","i","readRawNumber","encodedSize","readBoolean","readDefinedVector","count","allDefined","defined","push","bitsNeeded","bytesNeeded","Math","ceil","byteIdx","byte","bit","length","readNumberArray","values","totalBytesRead","result"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/sevenz/NumberCodec.ts"],"sourcesContent":["// Variable-length integer encoding for 7z format\n// Reference: https://py7zr.readthedocs.io/en/latest/archive_format.html\n//\n// 7z uses a space-efficient encoding where the first byte determines length:\n// 0xxxxxxx -> 1 byte (0-127)\n// 10xxxxxx xxxxxxxx -> 2 bytes (0-16383)\n// 110xxxxx + 2 bytes -> 3 bytes\n// 1110xxxx + 3 bytes -> 4 bytes\n// 11110xxx + 4 bytes -> 5 bytes\n// 111110xx + 5 bytes -> 6 bytes\n// 1111110x + 6 bytes -> 7 bytes\n// 11111110 + 7 bytes -> 8 bytes\n// 11111111 + 8 bytes -> 9 bytes (full 64-bit)\n//\n// NOTE: Returns JavaScript number which is accurate up to 2^53 - 1 (~9 PB).\n// This covers all practical file sizes.\n\nimport { readUInt64LE } from 'extract-base-iterator';\n\nexport interface NumberReadResult {\n value: number;\n bytesRead: number;\n}\n\n/**\n * Read a variable-length encoded number from a buffer\n * Uses 7z's variable-length uint64 encoding where the first byte indicates\n * how many additional bytes follow based on its value:\n * - 0x00-0x7F: 0 extra bytes (7 bits of data)\n * - 0x80-0xBF: 1 extra byte (14 bits of data)\n * - 0xC0-0xDF: 2 extra bytes (21 bits of data)\n * - 0xE0-0xEF: 3 extra bytes (28 bits of data)\n * - etc.\n * - 0xFF: 8 extra bytes (full 64-bit value)\n *\n * @param buf - Buffer containing encoded number\n * @param offset - Offset to start reading from\n * @returns Object with value and number of bytes consumed\n */\nexport function readNumber(buf: Buffer, offset: number): NumberReadResult {\n var firstByte = buf[offset];\n\n // Special case: 0xFF means 8 extra bytes (full 64-bit value)\n if (firstByte === 0xff) {\n return {\n value: readUInt64LE(buf, offset + 1),\n bytesRead: 9,\n };\n }\n\n // Determine number of extra bytes based on first byte value thresholds\n // This matches the 7z format specification\n var extraBytes = 0;\n var mask = 0x80;\n\n if (firstByte <= 0x7f) {\n extraBytes = 0;\n mask = 0x80;\n } else if (firstByte <= 0xbf) {\n extraBytes = 1;\n mask = 0x40;\n } else if (firstByte <= 0xdf) {\n extraBytes = 2;\n mask = 0x20;\n } else if (firstByte <= 0xef) {\n extraBytes = 3;\n mask = 0x10;\n } else if (firstByte <= 0xf7) {\n extraBytes = 4;\n mask = 0x08;\n } else if (firstByte <= 0xfb) {\n extraBytes = 5;\n mask = 0x04;\n } else if (firstByte <= 0xfd) {\n extraBytes = 6;\n mask = 0x02;\n } else {\n // 0xFE\n extraBytes = 7;\n mask = 0x01;\n }\n\n // Get high part from first byte (bits below the length indicator)\n var highPart = firstByte & (mask - 1);\n\n // Read extra bytes as LITTLE-ENDIAN\n var value = 0;\n for (var i = 0; i < extraBytes; i++) {\n value += buf[offset + 1 + i] * 256 ** i;\n }\n\n // Combine: value + (highPart << (extraBytes * 8))\n value += highPart * 256 ** extraBytes;\n\n return {\n value: value,\n bytesRead: 1 + extraBytes,\n };\n}\n\n/**\n * Read a raw 64-bit little-endian number (used in some fixed-size fields)\n * @param buf - Buffer containing the number\n * @param offset - Offset to start reading from\n * @returns The number value\n */\nexport function readRawNumber(buf: Buffer, offset: number): number {\n return readUInt64LE(buf, offset);\n}\n\n/**\n * Calculate the encoded size of a number\n * @param value - The number to encode\n * @returns Number of bytes needed to encode the value\n */\nexport function encodedSize(value: number): number {\n if (value < 0x80) return 1; // 7 bits\n if (value < 0x4000) return 2; // 14 bits\n if (value < 0x200000) return 3; // 21 bits\n if (value < 0x10000000) return 4; // 28 bits\n if (value < 0x800000000) return 5; // 35 bits\n if (value < 0x40000000000) return 6; // 42 bits\n if (value < 0x2000000000000) return 7; // 49 bits\n // 2^56 = 72057594037927936 (use calculated value to avoid precision loss)\n if (value < 72057594037927936) return 8; // 56 bits\n return 9; // 64 bits\n}\n\n/**\n * Read a boolean encoded as a single byte\n * @param buf - Buffer to read from\n * @param offset - Offset to read from\n * @returns true if byte is non-zero\n */\nexport function readBoolean(buf: Buffer, offset: number): boolean {\n return buf[offset] !== 0;\n}\n\n/**\n * Read a \"defined\" bitmask for an array of items.\n * Used when some items in a list have optional values.\n *\n * Format: If \"allDefined\" byte is 0, a bitmask follows indicating which items have values.\n * If \"allDefined\" byte is non-zero, all items are defined.\n *\n * @param buf - Buffer to read from\n * @param offset - Offset to start reading\n * @param count - Number of items\n * @returns Object with defined array and bytes consumed\n */\nexport function readDefinedVector(buf: Buffer, offset: number, count: number): { defined: boolean[]; bytesRead: number } {\n var allDefined = buf[offset] !== 0;\n var bytesRead = 1;\n var defined: boolean[] = [];\n\n if (allDefined) {\n // All items are defined\n for (var i = 0; i < count; i++) {\n defined.push(true);\n }\n } else {\n // Read bitmask\n var bitsNeeded = count;\n var bytesNeeded = Math.ceil(bitsNeeded / 8);\n\n for (var byteIdx = 0; byteIdx < bytesNeeded; byteIdx++) {\n var byte = buf[offset + 1 + byteIdx];\n for (var bit = 7; bit >= 0 && defined.length < count; bit--) {\n defined.push((byte & (1 << bit)) !== 0);\n }\n }\n bytesRead += bytesNeeded;\n }\n\n return { defined: defined, bytesRead: bytesRead };\n}\n\n/**\n * Read an array of variable-length numbers\n * @param buf - Buffer to read from\n * @param offset - Offset to start reading\n * @param count - Number of items to read\n * @returns Object with values array and bytes consumed\n */\nexport function readNumberArray(buf: Buffer, offset: number, count: number): { values: number[]; bytesRead: number } {\n var values: number[] = [];\n var totalBytesRead = 0;\n\n for (var i = 0; i < count; i++) {\n var result = readNumber(buf, offset + totalBytesRead);\n values.push(result.value);\n totalBytesRead += result.bytesRead;\n }\n\n return { values: values, bytesRead: totalBytesRead };\n}\n"],"names":["readUInt64LE","readNumber","buf","offset","firstByte","value","bytesRead","extraBytes","mask","highPart","i","readRawNumber","encodedSize","readBoolean","readDefinedVector","count","allDefined","defined","push","bitsNeeded","bytesNeeded","Math","ceil","byteIdx","byte","bit","length","readNumberArray","values","totalBytesRead","result"],"mappings":"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"}
@@ -85,10 +85,23 @@ export declare class SevenZipParser {
85
85
  * Get a readable stream for an entry's content
86
86
  */
87
87
  getEntryStream(entry: SevenZipEntry): Readable;
88
+ /**
89
+ * Check if a folder uses BCJ2 codec
90
+ */
91
+ private folderHasBcj2;
88
92
  /**
89
93
  * Get decompressed data for a folder, with caching for solid archives
90
94
  */
91
95
  private getDecompressedFolder;
96
+ /**
97
+ * Decompress a BCJ2 folder with multi-stream handling
98
+ * BCJ2 uses 4 input streams: main, call, jump, range coder
99
+ */
100
+ private decompressBcj2Folder;
101
+ /**
102
+ * Get processing order for coders (dependency order)
103
+ */
104
+ private getCoderProcessOrder;
92
105
  /**
93
106
  * Close the parser and release resources
94
107
  */
@@ -3,7 +3,7 @@
3
3
  import { allocBuffer, crc32 } from 'extract-base-iterator';
4
4
  import fs from 'fs';
5
5
  import { PassThrough } from 'readable-stream';
6
- import { getCodec, getCodecName, isCodecSupported } from './codecs/index.js';
6
+ import { decodeBcj2Multi, getCodec, getCodecName, isBcj2Codec, isCodecSupported } from './codecs/index.js';
7
7
  import { createCodedError, ErrorCode, FileAttribute, PropertyId, SIGNATURE_HEADER_SIZE } from './constants.js';
8
8
  import { parseEncodedHeader, parseHeaderContent, parseSignatureHeader } from './headers.js';
9
9
  import { readNumber } from './NumberCodec.js';
@@ -101,19 +101,66 @@ import { readNumber } from './NumberCodec.js';
101
101
  // This tells us how to decompress the actual header
102
102
  // Read pack info from the encoded header structure
103
103
  var packInfoResult = this.parseEncodedHeaderStreams(headerBuf, 1);
104
- // Read the compressed header data
104
+ // Calculate compressed header position
105
+ // For simple archives: header is at SIGNATURE_HEADER_SIZE + packPos
106
+ // For BCJ2/complex archives: header may be at the END of pack data area
107
+ // The pack data area ends at nextHeaderOffset (where encoded header starts)
105
108
  var compressedStart = SIGNATURE_HEADER_SIZE + packInfoResult.packPos;
106
109
  var compressedData = this.source.read(compressedStart, packInfoResult.packSize);
107
110
  // Decompress using the specified codec
108
111
  var codec = getCodec(packInfoResult.codecId);
109
- var decompressedHeader = codec.decode(compressedData, packInfoResult.properties, packInfoResult.unpackSize);
110
- // Verify CRC if present
111
- if (packInfoResult.unpackCRC !== undefined) {
112
- var actualCRC = crc32(decompressedHeader);
113
- if (actualCRC !== packInfoResult.unpackCRC) {
114
- throw createCodedError('Decompressed header CRC mismatch', ErrorCode.CRC_MISMATCH);
112
+ var decompressedHeader = null;
113
+ // Try decompressing from the calculated position first
114
+ try {
115
+ decompressedHeader = codec.decode(compressedData, packInfoResult.properties, packInfoResult.unpackSize);
116
+ // Verify CRC if present
117
+ if (packInfoResult.unpackCRC !== undefined) {
118
+ var actualCRC = crc32(decompressedHeader);
119
+ if (actualCRC !== packInfoResult.unpackCRC) {
120
+ decompressedHeader = null; // CRC mismatch, need to search
121
+ }
122
+ }
123
+ } catch {
124
+ decompressedHeader = null; // Decompression failed, need to search
125
+ }
126
+ // If initial decompression failed, search for the correct position as a fallback
127
+ // This handles edge cases where packPos doesn't point directly to header pack data
128
+ if (decompressedHeader === null && this.signature) {
129
+ var packAreaEnd = SIGNATURE_HEADER_SIZE + this.signature.nextHeaderOffset;
130
+ var searchStart = packAreaEnd - packInfoResult.packSize;
131
+ var searchEnd = Math.max(SIGNATURE_HEADER_SIZE, compressedStart - 100000);
132
+ // Scan for LZMA data starting with 0x00 (range coder init)
133
+ // Try each candidate and validate with CRC
134
+ var scanChunkSize = 4096;
135
+ searchLoop: for(var chunkStart = searchStart; chunkStart >= searchEnd; chunkStart -= scanChunkSize){
136
+ var chunk = this.source.read(chunkStart, scanChunkSize + packInfoResult.packSize);
137
+ for(var i = 0; i < Math.min(chunk.length, scanChunkSize); i++){
138
+ if (chunk[i] === 0x00) {
139
+ var candidateData = chunk.subarray(i, i + packInfoResult.packSize);
140
+ if (candidateData.length === packInfoResult.packSize) {
141
+ try {
142
+ var candidateDecompressed = codec.decode(candidateData, packInfoResult.properties, packInfoResult.unpackSize);
143
+ if (packInfoResult.unpackCRC !== undefined) {
144
+ var candCRC = crc32(candidateDecompressed);
145
+ if (candCRC === packInfoResult.unpackCRC) {
146
+ decompressedHeader = candidateDecompressed;
147
+ break searchLoop;
148
+ }
149
+ } else {
150
+ decompressedHeader = candidateDecompressed;
151
+ break searchLoop;
152
+ }
153
+ } catch {
154
+ // Decompression failed, continue searching
155
+ }
156
+ }
157
+ }
158
+ }
115
159
  }
116
160
  }
161
+ if (decompressedHeader === null) {
162
+ throw createCodedError('Failed to decompress header - could not find valid LZMA data', ErrorCode.CORRUPT_HEADER);
163
+ }
117
164
  // Now parse the decompressed header
118
165
  // It should start with kHeader
119
166
  var decompOffset = 0;
@@ -354,6 +401,16 @@ import { readNumber } from './NumberCodec.js';
354
401
  return outputStream;
355
402
  }
356
403
  /**
404
+ * Check if a folder uses BCJ2 codec
405
+ */ folderHasBcj2(folder) {
406
+ for(var i = 0; i < folder.coders.length; i++){
407
+ if (isBcj2Codec(folder.coders[i].id)) {
408
+ return true;
409
+ }
410
+ }
411
+ return false;
412
+ }
413
+ /**
357
414
  * Get decompressed data for a folder, with caching for solid archives
358
415
  */ getDecompressedFolder(folderIndex) {
359
416
  // Check cache first
@@ -364,6 +421,12 @@ import { readNumber } from './NumberCodec.js';
364
421
  throw createCodedError('No streams info available', ErrorCode.CORRUPT_HEADER);
365
422
  }
366
423
  var folder = this.streamsInfo.folders[folderIndex];
424
+ // Check if this folder uses BCJ2 (requires special multi-stream handling)
425
+ if (this.folderHasBcj2(folder)) {
426
+ var data = this.decompressBcj2Folder(folderIndex);
427
+ this.decompressedCache[folderIndex] = data;
428
+ return data;
429
+ }
367
430
  // Calculate packed data position
368
431
  var packPos = SIGNATURE_HEADER_SIZE + this.streamsInfo.packPos;
369
432
  // Find which pack stream this folder uses
@@ -379,17 +442,193 @@ import { readNumber } from './NumberCodec.js';
379
442
  // Read packed data
380
443
  var packedData = this.source.read(packPos, packSize);
381
444
  // Decompress through codec chain
382
- var data = packedData;
445
+ var data2 = packedData;
383
446
  for(var l = 0; l < folder.coders.length; l++){
384
447
  var coderInfo = folder.coders[l];
385
448
  var codec = getCodec(coderInfo.id);
386
449
  // Get unpack size for this coder (needed by LZMA)
387
450
  var unpackSize = folder.unpackSizes[l];
388
- data = codec.decode(data, coderInfo.properties, unpackSize);
451
+ data2 = codec.decode(data2, coderInfo.properties, unpackSize);
389
452
  }
390
453
  // Cache for solid archives (when multiple files share a folder)
391
- this.decompressedCache[folderIndex] = data;
392
- return data;
454
+ this.decompressedCache[folderIndex] = data2;
455
+ return data2;
456
+ }
457
+ /**
458
+ * Decompress a BCJ2 folder with multi-stream handling
459
+ * BCJ2 uses 4 input streams: main, call, jump, range coder
460
+ */ decompressBcj2Folder(folderIndex) {
461
+ if (!this.streamsInfo) {
462
+ throw createCodedError('No streams info available', ErrorCode.CORRUPT_HEADER);
463
+ }
464
+ var folder = this.streamsInfo.folders[folderIndex];
465
+ // Calculate starting pack position
466
+ var packPos = SIGNATURE_HEADER_SIZE + this.streamsInfo.packPos;
467
+ // Find which pack stream index this folder starts at
468
+ var packStreamIndex = 0;
469
+ for(var j = 0; j < folderIndex; j++){
470
+ packStreamIndex += this.streamsInfo.folders[j].packedStreams.length;
471
+ }
472
+ // Calculate position
473
+ for(var k = 0; k < packStreamIndex; k++){
474
+ packPos += this.streamsInfo.packSizes[k];
475
+ }
476
+ // Read all pack streams for this folder
477
+ var numPackStreams = folder.packedStreams.length;
478
+ var packStreams = [];
479
+ var currentPos = packPos;
480
+ for(var p = 0; p < numPackStreams; p++){
481
+ var size = this.streamsInfo.packSizes[packStreamIndex + p];
482
+ packStreams.push(this.source.read(currentPos, size));
483
+ currentPos += size;
484
+ }
485
+ // Build a map of coder outputs
486
+ // For BCJ2, typical structure is:
487
+ // Coder 0: LZMA2 (main stream) - 1 in, 1 out
488
+ // Coder 1: LZMA (call stream) - 1 in, 1 out
489
+ // Coder 2: LZMA (jump stream) - 1 in, 1 out
490
+ // Coder 3: BCJ2 - 4 in, 1 out
491
+ // Pack streams map to: coder inputs not bound to other coder outputs
492
+ // First, decompress each non-BCJ2 coder
493
+ var coderOutputs = {};
494
+ // Find the BCJ2 coder
495
+ var bcj2CoderIndex = -1;
496
+ for(var c = 0; c < folder.coders.length; c++){
497
+ if (isBcj2Codec(folder.coders[c].id)) {
498
+ bcj2CoderIndex = c;
499
+ break;
500
+ }
501
+ }
502
+ if (bcj2CoderIndex === -1) {
503
+ throw createCodedError('BCJ2 coder not found in folder', ErrorCode.CORRUPT_HEADER);
504
+ }
505
+ // Build input stream index -> pack stream mapping
506
+ // folder.packedStreams tells us which input indices are unbound and their order
507
+ var inputToPackStream = {};
508
+ for(var pi = 0; pi < folder.packedStreams.length; pi++){
509
+ inputToPackStream[folder.packedStreams[pi]] = pi;
510
+ }
511
+ // Build output stream index -> coder mapping
512
+ var outputToCoder = {};
513
+ var totalOutputs = 0;
514
+ for(var co = 0; co < folder.coders.length; co++){
515
+ var numOut = folder.coders[co].numOutStreams;
516
+ for(var outp = 0; outp < numOut; outp++){
517
+ outputToCoder[totalOutputs + outp] = co;
518
+ }
519
+ totalOutputs += numOut;
520
+ }
521
+ // Decompress non-BCJ2 coders (LZMA, LZMA2)
522
+ // We need to process in dependency order
523
+ var processed = {};
524
+ var processOrder = this.getCoderProcessOrder(folder, bcj2CoderIndex);
525
+ for(var po = 0; po < processOrder.length; po++){
526
+ var coderIdx = processOrder[po];
527
+ if (coderIdx === bcj2CoderIndex) continue;
528
+ var coder = folder.coders[coderIdx];
529
+ var codec = getCodec(coder.id);
530
+ // Find input for this coder
531
+ var coderInputStart = 0;
532
+ for(var ci2 = 0; ci2 < coderIdx; ci2++){
533
+ coderInputStart += folder.coders[ci2].numInStreams;
534
+ }
535
+ // Get input data (from pack stream)
536
+ var inputIdx = coderInputStart;
537
+ var packStreamIdx = inputToPackStream[inputIdx];
538
+ var inputData = packStreams[packStreamIdx];
539
+ // Decompress
540
+ var unpackSize = folder.unpackSizes[coderIdx];
541
+ var outputData = codec.decode(inputData, coder.properties, unpackSize);
542
+ // Store in coder outputs
543
+ var coderOutputStart = 0;
544
+ for(var co2 = 0; co2 < coderIdx; co2++){
545
+ coderOutputStart += folder.coders[co2].numOutStreams;
546
+ }
547
+ coderOutputs[coderOutputStart] = outputData;
548
+ processed[coderIdx] = true;
549
+ }
550
+ // Now process BCJ2
551
+ // BCJ2 has 4 inputs, need to map them correctly
552
+ // Standard order: main(LZMA2 output), call(LZMA output), jump(LZMA output), range(raw pack)
553
+ var bcj2InputStart = 0;
554
+ for(var ci3 = 0; ci3 < bcj2CoderIndex; ci3++){
555
+ bcj2InputStart += folder.coders[ci3].numInStreams;
556
+ }
557
+ var bcj2Inputs = [];
558
+ for(var bi = 0; bi < 4; bi++){
559
+ var globalIdx = bcj2InputStart + bi;
560
+ // Check if this input is bound to a coder output
561
+ var boundOutput = -1;
562
+ for(var bp2 = 0; bp2 < folder.bindPairs.length; bp2++){
563
+ if (folder.bindPairs[bp2].inIndex === globalIdx) {
564
+ boundOutput = folder.bindPairs[bp2].outIndex;
565
+ break;
566
+ }
567
+ }
568
+ if (boundOutput >= 0) {
569
+ // Get from coder outputs
570
+ bcj2Inputs.push(coderOutputs[boundOutput]);
571
+ } else {
572
+ // Get from pack streams
573
+ var psIdx = inputToPackStream[globalIdx];
574
+ bcj2Inputs.push(packStreams[psIdx]);
575
+ }
576
+ }
577
+ // Get BCJ2 unpack size
578
+ var bcj2OutputStart = 0;
579
+ for(var co3 = 0; co3 < bcj2CoderIndex; co3++){
580
+ bcj2OutputStart += folder.coders[co3].numOutStreams;
581
+ }
582
+ var bcj2UnpackSize = folder.unpackSizes[bcj2OutputStart];
583
+ // Decode BCJ2
584
+ return decodeBcj2Multi(bcj2Inputs, undefined, bcj2UnpackSize);
585
+ }
586
+ /**
587
+ * Get processing order for coders (dependency order)
588
+ */ getCoderProcessOrder(folder, excludeIdx) {
589
+ var order = [];
590
+ var processed = {};
591
+ // Simple approach: process coders that don't depend on unprocessed outputs
592
+ var changed = true;
593
+ while(changed){
594
+ changed = false;
595
+ for(var c = 0; c < folder.coders.length; c++){
596
+ if (processed[c] || c === excludeIdx) continue;
597
+ // Check if all inputs are satisfied
598
+ var inputStart = 0;
599
+ for(var i = 0; i < c; i++){
600
+ inputStart += folder.coders[i].numInStreams;
601
+ }
602
+ var canProcess = true;
603
+ for(var inp = 0; inp < folder.coders[c].numInStreams; inp++){
604
+ var globalIdx = inputStart + inp;
605
+ // Check if bound to an unprocessed coder
606
+ for(var bp = 0; bp < folder.bindPairs.length; bp++){
607
+ if (folder.bindPairs[bp].inIndex === globalIdx) {
608
+ // Find which coder produces this output
609
+ var outIdx = folder.bindPairs[bp].outIndex;
610
+ var outStart = 0;
611
+ for(var oc = 0; oc < folder.coders.length; oc++){
612
+ var numOut = folder.coders[oc].numOutStreams;
613
+ if (outIdx < outStart + numOut) {
614
+ if (!processed[oc] && oc !== excludeIdx) {
615
+ canProcess = false;
616
+ }
617
+ break;
618
+ }
619
+ outStart += numOut;
620
+ }
621
+ }
622
+ }
623
+ }
624
+ if (canProcess) {
625
+ order.push(c);
626
+ processed[c] = true;
627
+ changed = true;
628
+ }
629
+ }
630
+ }
631
+ return order;
393
632
  }
394
633
  /**
395
634
  * Close the parser and release resources