rar-stream 3.1.0 → 3.2.0

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 (129) hide show
  1. package/README.md +7 -10
  2. package/dist/index.cjs +516 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +127 -0
  5. package/dist/index.d.ts +127 -2
  6. package/dist/index.js +516 -1
  7. package/dist/index.js.map +1 -0
  8. package/package.json +26 -14
  9. package/.github/workflows/test.yml +0 -38
  10. package/dist/index.d.ts.map +0 -1
  11. package/dist/inner-file-stream.d.ts +0 -14
  12. package/dist/inner-file-stream.d.ts.map +0 -1
  13. package/dist/inner-file-stream.js +0 -36
  14. package/dist/inner-file.d.ts +0 -24
  15. package/dist/inner-file.d.ts.map +0 -1
  16. package/dist/inner-file.js +0 -67
  17. package/dist/interfaces.d.ts +0 -21
  18. package/dist/interfaces.d.ts.map +0 -1
  19. package/dist/interfaces.js +0 -1
  20. package/dist/local-file-media.d.ts +0 -10
  21. package/dist/local-file-media.d.ts.map +0 -1
  22. package/dist/local-file-media.js +0 -15
  23. package/dist/parsing/__mocks__/mock-file-media.d.ts +0 -11
  24. package/dist/parsing/__mocks__/mock-file-media.d.ts.map +0 -1
  25. package/dist/parsing/__mocks__/mock-file-media.js +0 -16
  26. package/dist/parsing/__mocks__/mock-file-stream.d.ts +0 -11
  27. package/dist/parsing/__mocks__/mock-file-stream.d.ts.map +0 -1
  28. package/dist/parsing/__mocks__/mock-file-stream.js +0 -23
  29. package/dist/parsing/__mocks__/utils.d.ts +0 -10
  30. package/dist/parsing/__mocks__/utils.d.ts.map +0 -1
  31. package/dist/parsing/__mocks__/utils.js +0 -27
  32. package/dist/parsing/archive-header-parser.d.ts +0 -24
  33. package/dist/parsing/archive-header-parser.d.ts.map +0 -1
  34. package/dist/parsing/archive-header-parser.js +0 -30
  35. package/dist/parsing/archive-header-parser.test.d.ts +0 -2
  36. package/dist/parsing/archive-header-parser.test.d.ts.map +0 -1
  37. package/dist/parsing/archive-header-parser.test.js +0 -95
  38. package/dist/parsing/file-header-parser.d.ts +0 -42
  39. package/dist/parsing/file-header-parser.d.ts.map +0 -1
  40. package/dist/parsing/file-header-parser.js +0 -88
  41. package/dist/parsing/file-header-parser.test.d.ts +0 -2
  42. package/dist/parsing/file-header-parser.test.d.ts.map +0 -1
  43. package/dist/parsing/file-header-parser.test.js +0 -208
  44. package/dist/parsing/marker-header-parser.d.ts +0 -13
  45. package/dist/parsing/marker-header-parser.d.ts.map +0 -1
  46. package/dist/parsing/marker-header-parser.js +0 -18
  47. package/dist/parsing/marker-header-parser.test.d.ts +0 -2
  48. package/dist/parsing/marker-header-parser.test.d.ts.map +0 -1
  49. package/dist/parsing/marker-header-parser.test.js +0 -47
  50. package/dist/parsing/terminator-header-parser.d.ts +0 -13
  51. package/dist/parsing/terminator-header-parser.d.ts.map +0 -1
  52. package/dist/parsing/terminator-header-parser.js +0 -14
  53. package/dist/parsing/terminator-header-parser.test.d.ts +0 -2
  54. package/dist/parsing/terminator-header-parser.test.d.ts.map +0 -1
  55. package/dist/parsing/terminator-header-parser.test.js +0 -57
  56. package/dist/rar-file-bundle.d.ts +0 -23
  57. package/dist/rar-file-bundle.d.ts.map +0 -1
  58. package/dist/rar-file-bundle.js +0 -87
  59. package/dist/rar-file-bundle.test.d.ts +0 -2
  60. package/dist/rar-file-bundle.test.d.ts.map +0 -1
  61. package/dist/rar-file-bundle.test.js +0 -74
  62. package/dist/rar-file-chunk.d.ts +0 -13
  63. package/dist/rar-file-chunk.d.ts.map +0 -1
  64. package/dist/rar-file-chunk.js +0 -25
  65. package/dist/rar-file-chunk.test.d.ts +0 -2
  66. package/dist/rar-file-chunk.test.d.ts.map +0 -1
  67. package/dist/rar-file-chunk.test.js +0 -40
  68. package/dist/rar-files-package.d.ts +0 -22
  69. package/dist/rar-files-package.d.ts.map +0 -1
  70. package/dist/rar-files-package.js +0 -89
  71. package/dist/rar-files-package.test.d.ts +0 -2
  72. package/dist/rar-files-package.test.d.ts.map +0 -1
  73. package/dist/rar-files-package.test.js +0 -162
  74. package/dist/rar-stream.test.d.ts +0 -2
  75. package/dist/rar-stream.test.d.ts.map +0 -1
  76. package/dist/rar-stream.test.js +0 -38
  77. package/dist/stream-utils.d.ts +0 -5
  78. package/dist/stream-utils.d.ts.map +0 -1
  79. package/dist/stream-utils.js +0 -13
  80. package/dist/stream-utils.test.d.ts +0 -2
  81. package/dist/stream-utils.test.d.ts.map +0 -1
  82. package/dist/stream-utils.test.js +0 -10
  83. package/example/package.json +0 -20
  84. package/example/pnpm-lock.yaml +0 -948
  85. package/example/webtorrent.js +0 -34
  86. package/src/__fixtures__/multi/multi.r00 +0 -0
  87. package/src/__fixtures__/multi/multi.r01 +0 -0
  88. package/src/__fixtures__/multi/multi.rar +0 -0
  89. package/src/__fixtures__/multi/multi.txt +0 -9
  90. package/src/__fixtures__/multi-splitted/multi-splitted.r00 +0 -0
  91. package/src/__fixtures__/multi-splitted/multi-splitted.r01 +0 -0
  92. package/src/__fixtures__/multi-splitted/multi-splitted.rar +0 -0
  93. package/src/__fixtures__/multi-splitted/splitted1.txt +0 -1
  94. package/src/__fixtures__/multi-splitted/splitted2.txt +0 -1
  95. package/src/__fixtures__/multi-splitted/splitted3.txt +0 -1
  96. package/src/__fixtures__/multi-splitted/splitted4.txt +0 -3
  97. package/src/__fixtures__/rarFile +0 -9
  98. package/src/__fixtures__/single/single.rar +0 -0
  99. package/src/__fixtures__/single/single.txt +0 -9
  100. package/src/__fixtures__/single-splitted/single-splitted.rar +0 -0
  101. package/src/__fixtures__/single-splitted/splitted1.txt +0 -1
  102. package/src/__fixtures__/single-splitted/splitted2.txt +0 -1
  103. package/src/__fixtures__/single-splitted/splitted3.txt +0 -1
  104. package/src/index.ts +0 -1
  105. package/src/inner-file-stream.ts +0 -38
  106. package/src/inner-file.ts +0 -90
  107. package/src/interfaces.ts +0 -23
  108. package/src/local-file-media.ts +0 -15
  109. package/src/parsing/__mocks__/mock-file-media.ts +0 -17
  110. package/src/parsing/__mocks__/mock-file-stream.ts +0 -22
  111. package/src/parsing/__mocks__/utils.ts +0 -38
  112. package/src/parsing/archive-header-parser.test.ts +0 -169
  113. package/src/parsing/archive-header-parser.ts +0 -38
  114. package/src/parsing/file-header-parser.test.ts +0 -272
  115. package/src/parsing/file-header-parser.ts +0 -130
  116. package/src/parsing/marker-header-parser.test.ts +0 -54
  117. package/src/parsing/marker-header-parser.ts +0 -16
  118. package/src/parsing/terminator-header-parser.test.ts +0 -66
  119. package/src/parsing/terminator-header-parser.ts +0 -11
  120. package/src/rar-file-bundle.test.ts +0 -87
  121. package/src/rar-file-bundle.ts +0 -97
  122. package/src/rar-file-chunk.test.ts +0 -44
  123. package/src/rar-file-chunk.ts +0 -32
  124. package/src/rar-files-package.test.ts +0 -262
  125. package/src/rar-files-package.ts +0 -132
  126. package/src/rar-stream.test.ts +0 -46
  127. package/src/stream-utils.test.ts +0 -12
  128. package/src/stream-utils.ts +0 -16
  129. package/tsconfig.json +0 -44
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Library for _"unpacking"_ and reading files inside rar archives as node Readable streams.
6
6
 
7
- **Note: Requires node version >= 8.0.0**
7
+ **Note: Requires node version >= 18.0.0**
8
8
 
9
9
  **Note: Decompression is not implemented at the moment**
10
10
 
@@ -13,16 +13,17 @@ Library for _"unpacking"_ and reading files inside rar archives as node Readable
13
13
  Below example shows how to unpack local rar files by piping the inner files to the file system.
14
14
 
15
15
  ```javascript
16
- const fs = require("fs");
17
- const path = require("path");
18
- const { RarFilesPackage } = require("rar-stream");
16
+ import fs from "fs";
17
+ import path from "path";
18
+ import { RarFilesPackage, LocalFileMedia } from "rar-stream";
19
19
  const CWD = process.cwd();
20
+
20
21
  const localRarFiles = [
21
22
  path.resolve(CWD, "./file.r00"),
22
23
  path.resolve(CWD, "./file.r01"),
23
24
  path.resolve(CWD, "./file.r02"),
24
25
  path.resolve(CWD, "./file.rar"),
25
- ];
26
+ ].map((p) => new LocalFileMedia(p));
26
27
 
27
28
  const rarFilesPackage = new RarFilesPackage(localRarFiles);
28
29
 
@@ -35,7 +36,7 @@ async function writeInnerRarFilesToDisk() {
35
36
  }
36
37
  }
37
38
 
38
- writeInnerRarFilesToDisk();
39
+ await writeInnerRarFilesToDisk();
39
40
  ```
40
41
 
41
42
  See [example/webtorrent.js](example/webtorrent.js) for a more advanced example.
@@ -134,10 +135,6 @@ Run tests with:
134
135
  npm test
135
136
  ```
136
137
 
137
- ### Built With
138
-
139
- - [binary](https://www.npmjs.com/package/binary) - For parsing rar headers.
140
-
141
138
  ### Contributing
142
139
 
143
140
  Post a new issue if you'd like to contribute in any way.
package/dist/index.cjs ADDED
@@ -0,0 +1,516 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4;// src/rar-files-package.ts
2
+ var _events = require('events');
3
+
4
+ // src/rar-file-bundle.ts
5
+ var RXX_EXTENSION = /\.R(\d\d)$|.RAR$/i;
6
+ var RAR_EXTENSION = /.RAR$/i;
7
+ var PARTXX_RAR_EXTENSION = /.PART(\d\d).RAR/i;
8
+ var isPartXXExtension = (fileMedias = []) => {
9
+ let anyPartXXTypes = fileMedias.filter(
10
+ (file) => file.name && file.name.match(PARTXX_RAR_EXTENSION)
11
+ );
12
+ if (anyPartXXTypes.length > 0) {
13
+ return true;
14
+ } else {
15
+ return false;
16
+ }
17
+ };
18
+ var NumericRarFileBundle = class {
19
+ constructor(fileMedias = []) {
20
+ this.fileMedias = fileMedias;
21
+ if (this.fileMedias.length > 0) {
22
+ this.filter();
23
+ this.sort();
24
+ }
25
+ }
26
+ filter() {
27
+ this.fileMedias = this.fileMedias.filter(
28
+ (file) => file.name && file.name.match(RXX_EXTENSION)
29
+ );
30
+ }
31
+ sort() {
32
+ this.fileMedias.sort((first, second) => {
33
+ if (first.name.match(RAR_EXTENSION)) {
34
+ return -1;
35
+ } else if (second.name.match(RAR_EXTENSION)) {
36
+ return 1;
37
+ } else {
38
+ const firstMatch = first.name.match(RXX_EXTENSION);
39
+ const secondMatch = second.name.match(RXX_EXTENSION);
40
+ const firstNumber = +(firstMatch && firstMatch[1] || 0);
41
+ const secondNumber = +(secondMatch && secondMatch[1] || 0);
42
+ return firstNumber - secondNumber;
43
+ }
44
+ });
45
+ }
46
+ get length() {
47
+ return this.fileMedias.length;
48
+ }
49
+ get fileNames() {
50
+ return this.fileMedias.map((file) => file.name);
51
+ }
52
+ get files() {
53
+ return this.fileMedias;
54
+ }
55
+ };
56
+ var PartXXRarBundle = class {
57
+ constructor(fileMedias = []) {
58
+ this.fileMedias = fileMedias;
59
+ if (this.fileMedias.length > 0) {
60
+ this.filter();
61
+ this.sort();
62
+ }
63
+ }
64
+ filter() {
65
+ this.fileMedias = this.fileMedias.filter(
66
+ (file) => file.name.match(PARTXX_RAR_EXTENSION)
67
+ );
68
+ }
69
+ sort() {
70
+ this.fileMedias.sort((first, second) => {
71
+ const firstMatch = first.name.match(PARTXX_RAR_EXTENSION);
72
+ const secondMatch = second.name.match(PARTXX_RAR_EXTENSION);
73
+ const firstNumber = +(firstMatch && firstMatch[1] || 0);
74
+ const secondNumber = +(secondMatch && secondMatch[1] || 0);
75
+ return firstNumber - secondNumber;
76
+ });
77
+ }
78
+ get length() {
79
+ return this.fileMedias.length;
80
+ }
81
+ get fileNames() {
82
+ return this.fileMedias.map((file) => file.name);
83
+ }
84
+ get files() {
85
+ return this.fileMedias;
86
+ }
87
+ };
88
+ var makeRarFileBundle = (fileMedias = []) => {
89
+ return isPartXXExtension(fileMedias) ? new PartXXRarBundle(fileMedias) : new NumericRarFileBundle(fileMedias);
90
+ };
91
+
92
+ // src/rar-file-chunk.ts
93
+ var RarFileChunk = class _RarFileChunk {
94
+ constructor(fileMedia, startOffset, endOffset) {
95
+ this.fileMedia = fileMedia;
96
+ this.startOffset = startOffset;
97
+ this.endOffset = endOffset;
98
+ }
99
+ padEnd(endPadding) {
100
+ return new _RarFileChunk(
101
+ this.fileMedia,
102
+ this.startOffset,
103
+ this.endOffset - endPadding
104
+ );
105
+ }
106
+ padStart(startPadding) {
107
+ return new _RarFileChunk(
108
+ this.fileMedia,
109
+ this.startOffset + startPadding,
110
+ this.endOffset
111
+ );
112
+ }
113
+ get length() {
114
+ return Math.max(0, this.endOffset - this.startOffset);
115
+ }
116
+ getStream() {
117
+ return this.fileMedia.createReadStream({
118
+ start: this.startOffset,
119
+ end: this.endOffset
120
+ });
121
+ }
122
+ };
123
+
124
+ // src/inner-file-stream.ts
125
+ var _stream = require('stream');
126
+ var InnerFileStream = class extends _stream.Readable {
127
+ constructor(rarFileChunks, options) {
128
+ super(options);
129
+ this.rarFileChunks = rarFileChunks;
130
+ }
131
+
132
+ pushData(data) {
133
+ if (!this.push(data)) {
134
+ _optionalChain([this, 'access', _ => _.stream, 'optionalAccess', _2 => _2.pause, 'call', _3 => _3()]);
135
+ }
136
+ }
137
+ get isStarted() {
138
+ return !!this.stream;
139
+ }
140
+ next() {
141
+ const chunk = this.rarFileChunks.shift();
142
+ if (!chunk) {
143
+ this.push(null);
144
+ } else {
145
+ this.stream = chunk.getStream();
146
+ _optionalChain([this, 'access', _4 => _4.stream, 'optionalAccess', _5 => _5.on, 'call', _6 => _6("data", (data) => this.pushData(data))]);
147
+ _optionalChain([this, 'access', _7 => _7.stream, 'optionalAccess', _8 => _8.on, 'call', _9 => _9("end", () => this.next())]);
148
+ }
149
+ }
150
+ _read() {
151
+ if (!this.isStarted) {
152
+ this.next();
153
+ } else {
154
+ _optionalChain([this, 'access', _10 => _10.stream, 'optionalAccess', _11 => _11.resume, 'call', _12 => _12()]);
155
+ }
156
+ }
157
+ };
158
+
159
+ // src/stream-utils.ts
160
+ var streamToBuffer = async (stream) => new Promise((resolve, reject) => {
161
+ const buffers = [];
162
+ stream.on("error", reject);
163
+ stream.on("data", (data) => buffers.push(data));
164
+ stream.on("end", () => resolve(Buffer.concat(buffers)));
165
+ });
166
+
167
+ // src/utils.ts
168
+ function groupBy(arr, fn) {
169
+ return arr.reduce((prev, curr) => {
170
+ const groupKey = fn(curr);
171
+ const group = prev[groupKey] || [];
172
+ group.push(curr);
173
+ return { ...prev, [groupKey]: group };
174
+ }, {});
175
+ }
176
+ function sum(arr) {
177
+ return arr.reduce((s, n) => s + n);
178
+ }
179
+ function mapValues(object, mapper) {
180
+ return Object.fromEntries(
181
+ Object.entries(object).map(([key, value]) => [key, mapper(value)])
182
+ );
183
+ }
184
+
185
+ // src/inner-file.ts
186
+ var InnerFile = class {
187
+ constructor(name, rarFileChunks) {
188
+ this.name = name;
189
+ this.rarFileChunks = rarFileChunks;
190
+ this.length = sum(rarFileChunks.map((c) => c.length));
191
+ this.chunkMap = this.calculateChunkMap(rarFileChunks);
192
+ this.name = name;
193
+ }
194
+
195
+
196
+ readToEnd() {
197
+ return streamToBuffer(
198
+ this.createReadStream({ start: 0, end: this.length - 1 })
199
+ );
200
+ }
201
+ getChunksToStream(fileStart, fileEnd) {
202
+ const { index: startIndex, start: startOffset } = this.findMappedChunk(fileStart);
203
+ let { index: endIndex, end: endOffset } = this.findMappedChunk(fileEnd);
204
+ const chunksToStream = this.rarFileChunks.slice(startIndex, endIndex + 1);
205
+ const last = chunksToStream.length - 1;
206
+ const first = 0;
207
+ chunksToStream[first] = chunksToStream[first].padStart(
208
+ Math.abs(startOffset - fileStart)
209
+ );
210
+ let diff = Math.abs(endOffset - fileEnd);
211
+ if (diff === this.rarFileChunks.length) {
212
+ diff = 0;
213
+ }
214
+ if (diff !== 0) {
215
+ chunksToStream[last] = chunksToStream[last].padEnd(diff);
216
+ }
217
+ return chunksToStream;
218
+ }
219
+ createReadStream(interval) {
220
+ if (!interval) {
221
+ interval = { start: 0, end: this.length - 1 };
222
+ }
223
+ let { start, end } = interval;
224
+ if (start < 0 || end >= this.length) {
225
+ throw Error("Illegal start/end offset");
226
+ }
227
+ return new InnerFileStream(this.getChunksToStream(start, end));
228
+ }
229
+ calculateChunkMap(rarFileChunks) {
230
+ const chunkMap = [];
231
+ let index = 0;
232
+ let fileOffset = 0;
233
+ for (const chunk of rarFileChunks) {
234
+ const start = fileOffset;
235
+ const end = fileOffset + chunk.length;
236
+ fileOffset = end + 1;
237
+ chunkMap.push({ index, start, end, chunk });
238
+ index++;
239
+ }
240
+ return chunkMap;
241
+ }
242
+ findMappedChunk(offset) {
243
+ let selectedMap = this.chunkMap[0];
244
+ for (const chunkMapping of this.chunkMap) {
245
+ if (offset >= chunkMapping.start && offset <= chunkMapping.end) {
246
+ selectedMap = chunkMapping;
247
+ break;
248
+ }
249
+ }
250
+ return selectedMap;
251
+ }
252
+ };
253
+
254
+ // src/parsing/marker-header-parser.ts
255
+ var MarkerHeaderParser = (_class = class {
256
+ constructor(headerBuffer) {
257
+ this.headerBuffer = headerBuffer;
258
+ }
259
+ static __initStatic() {this.HEADER_SIZE = 11}
260
+ parse() {
261
+ const crc = this.headerBuffer.readUInt16LE(0);
262
+ const type = this.headerBuffer.readUInt8(2);
263
+ const flags = this.headerBuffer.readUInt16LE(3);
264
+ let size = this.headerBuffer.readUInt16LE(5);
265
+ if ((flags & 32768) !== 0) {
266
+ let addSize = this.headerBuffer.readUint32LE(7);
267
+ size += addSize || 0;
268
+ }
269
+ return { crc, type, flags, size };
270
+ }
271
+ }, _class.__initStatic(), _class);
272
+
273
+ // src/parsing/archive-header-parser.ts
274
+ function parseFlags(parsedVars) {
275
+ return {
276
+ hasVolumeAttributes: (parsedVars.flags & 1) !== 0,
277
+ hasComment: (parsedVars.flags & 2) !== 0,
278
+ isLocked: (parsedVars.flags & 4) !== 0,
279
+ hasSolidAttributes: (parsedVars.flags & 8) !== 0,
280
+ isNewNameScheme: (parsedVars.flags & 16) !== 0,
281
+ hasAuthInfo: (parsedVars.flags & 32) !== 0,
282
+ hasRecovery: (parsedVars.flags & 64) !== 0,
283
+ isBlockEncoded: (parsedVars.flags & 128) !== 0,
284
+ isFirstVolume: (parsedVars.flags & 256) !== 0
285
+ };
286
+ }
287
+ var ArchiveHeaderParser = (_class2 = class {
288
+ constructor(buffer) {
289
+ this.buffer = buffer;
290
+ }
291
+ static __initStatic2() {this.HEADER_SIZE = 13}
292
+ parse() {
293
+ const crc = this.buffer.readUInt16LE(0);
294
+ const type = this.buffer.readUInt8(2);
295
+ const flags = this.buffer.readUInt16LE(3);
296
+ let size = this.buffer.readUInt16LE(5);
297
+ const reserved1 = this.buffer.readUInt16LE(7);
298
+ const reserved2 = this.buffer.readUInt32LE(9);
299
+ let vars = { crc, type, flags, size, reserved1, reserved2 };
300
+ return { ...parseFlags(vars), ...vars };
301
+ }
302
+ }, _class2.__initStatic2(), _class2);
303
+
304
+ // src/parsing/file-header-parser.ts
305
+ var FileHeaderParser = (_class3 = class {
306
+ constructor(buffer) {;_class3.prototype.__init.call(this);
307
+ this.buffer = buffer;
308
+ }
309
+ static __initStatic3() {this.HEADER_SIZE = 280}
310
+ __init() {this.offset = 0}
311
+ handleHighFileSize(parsedVars) {
312
+ if (parsedVars.hasHighSize) {
313
+ const highPackSize = this.buffer.readInt32LE(this.offset);
314
+ this.offset += 4;
315
+ const highUnpackSize = this.buffer.readInt32LE(this.offset);
316
+ this.offset += 4;
317
+ parsedVars.size = highPackSize * 4294967296 + parsedVars.size;
318
+ parsedVars.unpackedSize = highUnpackSize * 4294967296 + parsedVars.unpackedSize;
319
+ }
320
+ }
321
+ parseFileName(parsedVars) {
322
+ parsedVars.name = this.buffer.subarray(this.offset, this.offset + parsedVars.nameSize).toString("utf-8");
323
+ }
324
+ parseFlags(parsedVars) {
325
+ return {
326
+ continuesFromPrevious: (parsedVars.flags & 1) !== 0,
327
+ continuesInNext: (parsedVars.flags & 2) !== 0,
328
+ isEncrypted: (parsedVars.flags & 4) !== 0,
329
+ hasComment: (parsedVars.flags & 8) !== 0,
330
+ hasInfoFromPrevious: (parsedVars.flags & 16) !== 0,
331
+ hasHighSize: (parsedVars.flags & 256) !== 0,
332
+ hasSpecialName: (parsedVars.flags & 512) !== 0,
333
+ hasSalt: (parsedVars.flags & 1024) !== 0,
334
+ isOldVersion: (parsedVars.flags & 2048) !== 0,
335
+ hasExtendedTime: (parsedVars.flags & 4096) !== 0
336
+ };
337
+ }
338
+ parse() {
339
+ const crc = this.buffer.readUInt16LE(this.offset);
340
+ this.offset += 2;
341
+ const type = this.buffer.readUInt8(this.offset);
342
+ this.offset += 1;
343
+ const flags = this.buffer.readUInt16LE(this.offset);
344
+ this.offset += 2;
345
+ const headSize = this.buffer.readUInt16LE(this.offset);
346
+ this.offset += 2;
347
+ const size = this.buffer.readUInt32LE(this.offset);
348
+ this.offset += 4;
349
+ const unpackedSize = this.buffer.readUInt32LE(this.offset);
350
+ this.offset += 4;
351
+ const host = this.buffer.readUInt8(this.offset);
352
+ this.offset += 1;
353
+ const fileCrc = this.buffer.readUInt32LE(this.offset);
354
+ this.offset += 4;
355
+ const timestamp = this.buffer.readUInt32LE(this.offset);
356
+ this.offset += 4;
357
+ const version = this.buffer.readUInt8(this.offset);
358
+ this.offset += 1;
359
+ const method = this.buffer.readUInt8(this.offset);
360
+ this.offset += 1;
361
+ const nameSize = this.buffer.readUInt16LE(this.offset);
362
+ this.offset += 2;
363
+ const attributes = this.buffer.readUInt32LE(this.offset);
364
+ this.offset += 4;
365
+ let vars = {
366
+ crc,
367
+ type,
368
+ flags,
369
+ headSize,
370
+ size,
371
+ unpackedSize,
372
+ host,
373
+ fileCrc,
374
+ timestamp,
375
+ version,
376
+ method,
377
+ nameSize,
378
+ attributes,
379
+ name: ""
380
+ };
381
+ const boolFlags = this.parseFlags(vars);
382
+ const header = { ...vars, ...boolFlags };
383
+ this.handleHighFileSize(header);
384
+ this.parseFileName(header);
385
+ this.offset = 0;
386
+ return header;
387
+ }
388
+ }, _class3.__initStatic3(), _class3);
389
+
390
+ // src/parsing/terminator-header-parser.ts
391
+ var TerminatorHeaderParser = (_class4 = class {
392
+ constructor(headerBuffer) {
393
+ this.headerBuffer = headerBuffer;
394
+ }
395
+ static __initStatic4() {this.HEADER_SIZE = 27}
396
+ parse() {
397
+ const crc = this.headerBuffer.readUInt16LE(0);
398
+ const type = this.headerBuffer.readUInt8(2);
399
+ const flags = this.headerBuffer.readUInt16LE(3);
400
+ const size = this.headerBuffer.readUInt16LE(5);
401
+ return { crc, type, flags, size };
402
+ }
403
+ }, _class4.__initStatic4(), _class4);
404
+
405
+ // src/rar-files-package.ts
406
+ var parseHeader = async (Parser, fileMedia, offset = 0) => {
407
+ const stream = fileMedia.createReadStream({
408
+ start: offset,
409
+ end: offset + Parser.HEADER_SIZE
410
+ });
411
+ const headerBuffer = await streamToBuffer(stream);
412
+ const parser = new Parser(headerBuffer);
413
+ return parser.parse();
414
+ };
415
+ var RarFilesPackage = class extends _events.EventEmitter {
416
+
417
+ constructor(fileMedias) {
418
+ super();
419
+ this.rarFileBundle = makeRarFileBundle(fileMedias);
420
+ }
421
+ async parseFile(rarFile) {
422
+ const fileChunks = [];
423
+ let fileOffset = 0;
424
+ const markerHead = await parseHeader(MarkerHeaderParser, rarFile);
425
+ fileOffset += markerHead.size;
426
+ const archiveHeader = await parseHeader(
427
+ ArchiveHeaderParser,
428
+ rarFile,
429
+ fileOffset
430
+ );
431
+ fileOffset += archiveHeader.size;
432
+ while (fileOffset < rarFile.length - TerminatorHeaderParser.HEADER_SIZE) {
433
+ const fileHead = await parseHeader(FileHeaderParser, rarFile, fileOffset);
434
+ if (fileHead.type !== 116) {
435
+ break;
436
+ }
437
+ if (fileHead.method !== 48) {
438
+ throw new Error("Decompression is not implemented");
439
+ }
440
+ fileOffset += fileHead.headSize;
441
+ fileChunks.push({
442
+ name: fileHead.name,
443
+ fileHead,
444
+ chunk: new RarFileChunk(
445
+ rarFile,
446
+ fileOffset,
447
+ fileOffset + fileHead.size - 1
448
+ )
449
+ });
450
+ fileOffset += fileHead.size;
451
+ }
452
+ this.emit("file-parsed", rarFile);
453
+ return fileChunks;
454
+ }
455
+ async parse() {
456
+ this.emit("parsing-start", this.rarFileBundle);
457
+ const parsedFileChunks = [];
458
+ const { files } = this.rarFileBundle;
459
+ for (let i = 0; i < files.length; ++i) {
460
+ const file = files[i];
461
+ const chunks = await this.parseFile(file);
462
+ const { fileHead, chunk } = chunks[chunks.length - 1];
463
+ const chunkSize = Math.abs(chunk.endOffset - chunk.startOffset);
464
+ let innerFileSize = fileHead.unpackedSize;
465
+ parsedFileChunks.push(chunks);
466
+ if (fileHead.continuesInNext) {
467
+ while (Math.abs(innerFileSize - chunkSize) >= chunkSize) {
468
+ const nextFile = files[++i];
469
+ parsedFileChunks.push([
470
+ {
471
+ name: fileHead.name,
472
+ chunk: new RarFileChunk(
473
+ nextFile,
474
+ chunk.startOffset,
475
+ chunk.endOffset
476
+ )
477
+ }
478
+ ]);
479
+ this.emit("file-parsed", nextFile);
480
+ innerFileSize -= chunkSize;
481
+ }
482
+ }
483
+ }
484
+ const fileChunks = parsedFileChunks.flat();
485
+ const grouped = mapValues(
486
+ groupBy(fileChunks, (f) => f.name),
487
+ (value) => value.map((v) => v.chunk)
488
+ );
489
+ const innerFiles = Object.entries(grouped).map(
490
+ ([name, chunks]) => new InnerFile(name, chunks)
491
+ );
492
+ this.emit("parsing-complete", innerFiles);
493
+ return innerFiles;
494
+ }
495
+ };
496
+
497
+ // src/local-file-media.ts
498
+ var _path = require('path');
499
+ var _fs = require('fs');
500
+ var LocalFileMedia = class {
501
+ constructor(path) {
502
+ this.path = path;
503
+ this.name = _path.basename.call(void 0, path);
504
+ this.length = _fs.statSync.call(void 0, path).size;
505
+ }
506
+
507
+
508
+ createReadStream(interval) {
509
+ return _fs.createReadStream.call(void 0, this.path, interval);
510
+ }
511
+ };
512
+
513
+
514
+
515
+ exports.LocalFileMedia = LocalFileMedia; exports.RarFilesPackage = RarFilesPackage;
516
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/rar-files-package.ts","../src/rar-file-bundle.ts","../src/rar-file-chunk.ts","../src/inner-file-stream.ts","../src/stream-utils.ts","../src/utils.ts","../src/inner-file.ts","../src/parsing/marker-header-parser.ts","../src/parsing/archive-header-parser.ts","../src/parsing/file-header-parser.ts","../src/parsing/terminator-header-parser.ts","../src/local-file-media.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from \"events\";\nimport { makeRarFileBundle, RarFileBundle } from \"./rar-file-bundle.js\";\nimport { RarFileChunk } from \"./rar-file-chunk.js\";\nimport { InnerFile } from \"./inner-file.js\";\n\nimport { MarkerHeaderParser } from \"./parsing/marker-header-parser.js\";\nimport { ArchiveHeaderParser } from \"./parsing/archive-header-parser.js\";\nimport { FileHeaderParser, IFileHeader } from \"./parsing/file-header-parser.js\";\nimport { TerminatorHeaderParser } from \"./parsing/terminator-header-parser.js\";\n\nimport { streamToBuffer } from \"./stream-utils.js\";\nimport { IFileMedia, IParser, IParsers } from \"./interfaces.js\";\nimport { groupBy, mapValues } from \"./utils.js\";\n\nconst parseHeader = async <T extends IParsers>(\n Parser: IParser<T>,\n fileMedia: IFileMedia,\n offset = 0\n) => {\n const stream = fileMedia.createReadStream({\n start: offset,\n end: offset + Parser.HEADER_SIZE,\n });\n const headerBuffer = await streamToBuffer(stream);\n const parser = new Parser(headerBuffer);\n return parser.parse() as ReturnType<T[\"parse\"]>;\n};\ninterface ParsedFileChunkMapping {\n name: string;\n chunk: RarFileChunk;\n}\ninterface FileChunkMapping extends ParsedFileChunkMapping {\n fileHead: IFileHeader;\n}\n\nexport class RarFilesPackage extends EventEmitter {\n rarFileBundle: RarFileBundle;\n constructor(fileMedias: IFileMedia[]) {\n super();\n this.rarFileBundle = makeRarFileBundle(fileMedias);\n }\n async parseFile(rarFile: IFileMedia) {\n const fileChunks: FileChunkMapping[] = [];\n let fileOffset = 0;\n const markerHead = await parseHeader(MarkerHeaderParser, rarFile);\n fileOffset += markerHead.size;\n\n const archiveHeader = await parseHeader(\n ArchiveHeaderParser,\n rarFile,\n fileOffset\n );\n fileOffset += archiveHeader.size;\n\n while (fileOffset < rarFile.length - TerminatorHeaderParser.HEADER_SIZE) {\n const fileHead = await parseHeader(FileHeaderParser, rarFile, fileOffset);\n if (fileHead.type !== 116) {\n break;\n }\n if (fileHead.method !== 0x30) {\n throw new Error(\"Decompression is not implemented\");\n }\n fileOffset += fileHead.headSize;\n\n fileChunks.push({\n name: fileHead.name,\n fileHead,\n chunk: new RarFileChunk(\n rarFile,\n fileOffset,\n fileOffset + fileHead.size - 1\n ),\n });\n fileOffset += fileHead.size;\n }\n this.emit(\"file-parsed\", rarFile);\n return fileChunks;\n }\n async parse(): Promise<InnerFile[]> {\n this.emit(\"parsing-start\", this.rarFileBundle);\n const parsedFileChunks: ParsedFileChunkMapping[][] = [];\n const { files } = this.rarFileBundle;\n for (let i = 0; i < files.length; ++i) {\n const file = files[i]!;\n\n const chunks = await this.parseFile(file);\n const { fileHead, chunk } = chunks[chunks.length - 1]!;\n const chunkSize = Math.abs(chunk.endOffset - chunk.startOffset);\n let innerFileSize = fileHead.unpackedSize;\n parsedFileChunks.push(chunks);\n\n if (fileHead.continuesInNext) {\n while (Math.abs(innerFileSize - chunkSize) >= chunkSize) {\n const nextFile = files[++i]!;\n\n parsedFileChunks.push([\n {\n name: fileHead.name,\n chunk: new RarFileChunk(\n nextFile,\n chunk.startOffset,\n chunk.endOffset\n ),\n },\n ]);\n this.emit(\"file-parsed\", nextFile);\n innerFileSize -= chunkSize;\n }\n }\n }\n\n const fileChunks = parsedFileChunks.flat();\n\n const grouped = mapValues(\n groupBy(fileChunks, (f) => f.name),\n (value) => value.map((v) => v.chunk)\n );\n\n const innerFiles = Object.entries(grouped).map(\n ([name, chunks]) => new InnerFile(name, chunks)\n );\n\n this.emit(\"parsing-complete\", innerFiles);\n return innerFiles;\n }\n}\n","const RXX_EXTENSION = /\\.R(\\d\\d)$|.RAR$/i;\nconst RAR_EXTENSION = /.RAR$/i;\nconst PARTXX_RAR_EXTENSION = /.PART(\\d\\d).RAR/i;\nimport { IFileMedia } from \"./interfaces.js\";\n\nconst isPartXXExtension = (fileMedias: IFileMedia[] = []) => {\n let anyPartXXTypes = fileMedias.filter(\n (file) => file.name && file.name.match(PARTXX_RAR_EXTENSION)\n );\n\n if (anyPartXXTypes.length > 0) {\n return true;\n } else {\n return false;\n }\n};\n\nclass NumericRarFileBundle {\n constructor(private fileMedias: IFileMedia[] = []) {\n if (this.fileMedias.length > 0) {\n this.filter();\n this.sort();\n }\n }\n filter() {\n this.fileMedias = this.fileMedias.filter(\n (file) => file.name && file.name.match(RXX_EXTENSION)\n );\n }\n sort() {\n this.fileMedias.sort((first, second) => {\n if (first.name.match(RAR_EXTENSION)) {\n return -1;\n } else if (second.name.match(RAR_EXTENSION)) {\n return 1;\n } else {\n const firstMatch = first.name.match(RXX_EXTENSION);\n const secondMatch = second.name.match(RXX_EXTENSION);\n const firstNumber = +((firstMatch && firstMatch[1]) || 0);\n const secondNumber = +((secondMatch && secondMatch[1]) || 0);\n return firstNumber - secondNumber;\n }\n });\n }\n\n get length() {\n return this.fileMedias.length;\n }\n get fileNames() {\n return this.fileMedias.map((file) => file.name);\n }\n get files() {\n return this.fileMedias;\n }\n}\n\nclass PartXXRarBundle {\n constructor(private fileMedias: IFileMedia[] = []) {\n if (this.fileMedias.length > 0) {\n this.filter();\n this.sort();\n }\n }\n filter() {\n this.fileMedias = this.fileMedias.filter((file) =>\n file.name.match(PARTXX_RAR_EXTENSION)\n );\n }\n sort() {\n this.fileMedias.sort((first, second) => {\n const firstMatch = first.name.match(PARTXX_RAR_EXTENSION);\n const secondMatch = second.name.match(PARTXX_RAR_EXTENSION);\n const firstNumber = +((firstMatch && firstMatch[1]) || 0);\n const secondNumber = +((secondMatch && secondMatch[1]) || 0);\n return firstNumber - secondNumber;\n });\n }\n\n get length() {\n return this.fileMedias.length;\n }\n get fileNames() {\n return this.fileMedias.map((file) => file.name);\n }\n get files() {\n return this.fileMedias;\n }\n}\n\nexport type RarFileBundle = PartXXRarBundle | NumericRarFileBundle;\nexport const makeRarFileBundle = (\n fileMedias: IFileMedia[] = []\n): RarFileBundle => {\n return isPartXXExtension(fileMedias)\n ? new PartXXRarBundle(fileMedias)\n : new NumericRarFileBundle(fileMedias);\n};\n","import { IFileMedia } from \"./interfaces.js\";\n\nexport class RarFileChunk {\n constructor(\n private fileMedia: IFileMedia,\n public startOffset: number,\n public endOffset: number\n ) {}\n padEnd(endPadding: number) {\n return new RarFileChunk(\n this.fileMedia,\n this.startOffset,\n this.endOffset - endPadding\n );\n }\n padStart(startPadding: number) {\n return new RarFileChunk(\n this.fileMedia,\n this.startOffset + startPadding,\n this.endOffset\n );\n }\n get length() {\n return Math.max(0, this.endOffset - this.startOffset);\n }\n getStream() {\n return this.fileMedia.createReadStream({\n start: this.startOffset,\n end: this.endOffset,\n });\n }\n}\n","import { Readable, ReadableOptions } from \"stream\";\nimport { RarFileChunk } from \"./rar-file-chunk.js\";\n\nexport class InnerFileStream extends Readable {\n stream?: NodeJS.ReadableStream;\n constructor(\n private rarFileChunks: RarFileChunk[],\n options?: ReadableOptions\n ) {\n super(options);\n }\n pushData(data: Uint16Array) {\n if (!this.push(data)) {\n this.stream?.pause();\n }\n }\n get isStarted() {\n return !!this.stream;\n }\n next() {\n const chunk = this.rarFileChunks.shift();\n\n if (!chunk) {\n this.push(null);\n } else {\n this.stream = chunk.getStream();\n this.stream?.on(\"data\", (data) => this.pushData(data));\n this.stream?.on(\"end\", () => this.next());\n }\n }\n override _read() {\n if (!this.isStarted) {\n this.next();\n } else {\n this.stream?.resume();\n }\n }\n}\n","import { Stream, Duplex } from \"stream\";\n\nexport const streamToBuffer = async (stream: Stream | NodeJS.ReadableStream): Promise<Buffer> =>\n new Promise((resolve, reject) => {\n const buffers: Uint8Array[] = [];\n stream.on(\"error\", reject);\n stream.on(\"data\", (data) => buffers.push(data));\n stream.on(\"end\", () => resolve(Buffer.concat(buffers)));\n });\n\nexport const bufferToStream = (buffer: Buffer): Stream => {\n const stream = new Duplex();\n stream.push(buffer);\n stream.push(null);\n return stream;\n};\n","export function groupBy<T>(arr: T[], fn: (item: T) => any) {\n return arr.reduce<Record<string, T[]>>((prev, curr) => {\n const groupKey = fn(curr);\n const group = prev[groupKey] || [];\n group.push(curr);\n return { ...prev, [groupKey]: group };\n }, {});\n}\n\nexport function sum(arr: number[]) {\n return arr.reduce((s, n) => s + n);\n}\nexport function mapValues<T extends Object, S>(\n object: T,\n mapper: (value: T[keyof T]) => S\n) {\n return Object.fromEntries(\n Object.entries(object).map(([key, value]) => [key, mapper(value)])\n ) as { [key in keyof T]: S };\n}\n","import { IFileMedia, IReadInterval } from \"./interfaces.js\";\nimport { InnerFileStream } from \"./inner-file-stream.js\";\nimport { RarFileChunk } from \"./rar-file-chunk.js\";\nimport { streamToBuffer } from \"./stream-utils.js\";\nimport { sum } from \"./utils.js\";\ntype ChunkMapEntry = {\n index: number;\n start: number;\n end: number;\n chunk: RarFileChunk;\n};\n\nexport class InnerFile implements IFileMedia {\n length: number;\n\n chunkMap: ChunkMapEntry[];\n constructor(public name: string, private rarFileChunks: RarFileChunk[]) {\n this.length = sum(rarFileChunks.map((c) => c.length));\n this.chunkMap = this.calculateChunkMap(rarFileChunks);\n\n this.name = name;\n }\n readToEnd() {\n return streamToBuffer(\n this.createReadStream({ start: 0, end: this.length - 1 })\n );\n }\n getChunksToStream(fileStart: number, fileEnd: number) {\n const { index: startIndex, start: startOffset } =\n this.findMappedChunk(fileStart);\n let { index: endIndex, end: endOffset } = this.findMappedChunk(fileEnd);\n\n const chunksToStream = this.rarFileChunks.slice(startIndex, endIndex + 1);\n\n const last = chunksToStream.length - 1;\n const first = 0;\n chunksToStream[first] = chunksToStream[first]!.padStart(\n Math.abs(startOffset - fileStart)\n );\n\n let diff = Math.abs(endOffset - fileEnd);\n if (diff === this.rarFileChunks.length) {\n diff = 0;\n }\n if (diff !== 0) {\n chunksToStream[last] = chunksToStream[last]!.padEnd(diff);\n }\n\n return chunksToStream;\n }\n createReadStream(interval: IReadInterval) {\n if (!interval) {\n interval = { start: 0, end: this.length - 1 };\n }\n let { start, end } = interval;\n\n if (start < 0 || end >= this.length) {\n throw Error(\"Illegal start/end offset\");\n }\n\n return new InnerFileStream(this.getChunksToStream(start, end));\n }\n calculateChunkMap(rarFileChunks: RarFileChunk[]) {\n const chunkMap: ChunkMapEntry[] = [];\n let index = 0;\n let fileOffset = 0;\n for (const chunk of rarFileChunks) {\n const start = fileOffset;\n const end = fileOffset + chunk.length;\n fileOffset = end + 1;\n\n chunkMap.push({ index, start, end, chunk });\n index++;\n }\n\n return chunkMap;\n }\n findMappedChunk(offset: number) {\n let selectedMap = this.chunkMap[0]!;\n for (const chunkMapping of this.chunkMap) {\n if (offset >= chunkMapping.start && offset <= chunkMapping.end) {\n selectedMap = chunkMapping;\n break;\n }\n }\n return selectedMap;\n }\n}\n","export class MarkerHeaderParser {\n static HEADER_SIZE = 11;\n constructor(private headerBuffer: Buffer) {}\n\n parse() {\n const crc = this.headerBuffer.readUInt16LE(0);\n const type = this.headerBuffer.readUInt8(2);\n const flags = this.headerBuffer.readUInt16LE(3);\n let size = this.headerBuffer.readUInt16LE(5);\n if ((flags & 0x8000) !== 0) {\n let addSize = this.headerBuffer.readUint32LE(7);\n size += addSize || 0;\n }\n return { crc, type, flags, size };\n }\n}\n","interface IArchiveHeader {\n crc: number;\n type: number;\n flags: number;\n size: number;\n reserved1: number;\n reserved2: number;\n}\n\nfunction parseFlags(parsedVars: IArchiveHeader) {\n return {\n hasVolumeAttributes: (parsedVars.flags & 0x0001) !== 0,\n hasComment: (parsedVars.flags & 0x0002) !== 0,\n isLocked: (parsedVars.flags & 0x0004) !== 0,\n hasSolidAttributes: (parsedVars.flags & 0x0008) !== 0,\n isNewNameScheme: (parsedVars.flags & 0x00010) !== 0,\n hasAuthInfo: (parsedVars.flags & 0x0020) !== 0,\n hasRecovery: (parsedVars.flags & 0x0040) !== 0,\n isBlockEncoded: (parsedVars.flags & 0x0080) !== 0,\n isFirstVolume: (parsedVars.flags & 0x0100) !== 0,\n };\n}\nexport class ArchiveHeaderParser {\n static HEADER_SIZE = 13;\n constructor(private buffer: Buffer) {}\n parse() {\n const crc = this.buffer.readUInt16LE(0);\n const type = this.buffer.readUInt8(2);\n const flags = this.buffer.readUInt16LE(3);\n let size = this.buffer.readUInt16LE(5);\n const reserved1 = this.buffer.readUInt16LE(7);\n const reserved2 = this.buffer.readUInt32LE(9);\n\n let vars = { crc, type, flags, size, reserved1, reserved2 };\n\n return { ...parseFlags(vars), ...vars };\n }\n}\n","interface IFileHeaderFlags {\n continuesFromPrevious: boolean;\n continuesInNext: boolean;\n isEncrypted: boolean;\n hasComment: boolean;\n hasInfoFromPrevious: boolean;\n hasHighSize: boolean;\n hasSpecialName: boolean;\n hasSalt: boolean;\n isOldVersion: boolean;\n hasExtendedTime: boolean;\n}\n\ninterface IFileHeaderRaw {\n crc: number;\n type: number;\n flags: number;\n headSize: number;\n size: number;\n unpackedSize: number;\n host: number;\n fileCrc: number;\n timestamp: number;\n version: number;\n method: number;\n nameSize: number;\n attributes: number;\n name: string;\n}\n\nexport type IFileHeader = IFileHeaderRaw & IFileHeaderFlags;\nexport class FileHeaderParser {\n static HEADER_SIZE = 280;\n offset = 0;\n constructor(private buffer: Buffer) {}\n private handleHighFileSize(parsedVars: IFileHeader) {\n if (parsedVars.hasHighSize) {\n const highPackSize = this.buffer.readInt32LE(this.offset);\n this.offset += 4;\n const highUnpackSize = this.buffer.readInt32LE(this.offset);\n this.offset += 4;\n parsedVars.size = highPackSize * 0x100000000 + parsedVars.size;\n parsedVars.unpackedSize =\n highUnpackSize * 0x100000000 + parsedVars.unpackedSize;\n }\n }\n private parseFileName(parsedVars: IFileHeaderRaw) {\n parsedVars.name = this.buffer\n .subarray(this.offset, this.offset + parsedVars.nameSize)\n .toString(\"utf-8\");\n }\n private parseFlags(parsedVars: IFileHeaderRaw): IFileHeaderFlags {\n return {\n continuesFromPrevious: (parsedVars.flags & 0x01) !== 0,\n continuesInNext: (parsedVars.flags & 0x02) !== 0,\n isEncrypted: (parsedVars.flags & 0x04) !== 0,\n hasComment: (parsedVars.flags & 0x08) !== 0,\n hasInfoFromPrevious: (parsedVars.flags & 0x10) !== 0,\n hasHighSize: (parsedVars.flags & 0x100) !== 0,\n hasSpecialName: (parsedVars.flags & 0x200) !== 0,\n hasSalt: (parsedVars.flags & 0x400) !== 0,\n isOldVersion: (parsedVars.flags & 0x800) !== 0,\n hasExtendedTime: (parsedVars.flags & 0x1000) !== 0,\n };\n }\n parse(): IFileHeader {\n const crc = this.buffer.readUInt16LE(this.offset);\n this.offset += 2;\n\n const type = this.buffer.readUInt8(this.offset);\n this.offset += 1;\n\n const flags = this.buffer.readUInt16LE(this.offset);\n this.offset += 2;\n\n const headSize = this.buffer.readUInt16LE(this.offset);\n this.offset += 2;\n\n const size = this.buffer.readUInt32LE(this.offset);\n this.offset += 4;\n\n const unpackedSize = this.buffer.readUInt32LE(this.offset);\n this.offset += 4;\n\n const host = this.buffer.readUInt8(this.offset);\n this.offset += 1;\n\n const fileCrc = this.buffer.readUInt32LE(this.offset);\n this.offset += 4;\n\n const timestamp = this.buffer.readUInt32LE(this.offset);\n this.offset += 4;\n\n const version = this.buffer.readUInt8(this.offset);\n this.offset += 1;\n\n const method = this.buffer.readUInt8(this.offset);\n this.offset += 1;\n\n const nameSize = this.buffer.readUInt16LE(this.offset);\n this.offset += 2;\n\n const attributes = this.buffer.readUInt32LE(this.offset);\n this.offset += 4;\n\n let vars: IFileHeaderRaw = {\n crc,\n type,\n flags,\n headSize,\n size,\n unpackedSize,\n host,\n fileCrc,\n timestamp,\n version,\n method,\n nameSize,\n attributes,\n name: \"\",\n };\n\n const boolFlags = this.parseFlags(vars);\n const header = { ...vars, ...boolFlags };\n this.handleHighFileSize(header);\n this.parseFileName(header);\n this.offset = 0;\n return header;\n }\n}\n","export class TerminatorHeaderParser {\n static HEADER_SIZE = 27;\n constructor(private headerBuffer: Buffer) {}\n parse() {\n const crc = this.headerBuffer.readUInt16LE(0);\n const type = this.headerBuffer.readUInt8(2);\n const flags = this.headerBuffer.readUInt16LE(3);\n const size = this.headerBuffer.readUInt16LE(5);\n return { crc, type, flags, size };\n }\n}\n","import { basename } from \"path\";\nimport { statSync, createReadStream } from \"fs\";\nimport { IFileMedia, IReadInterval } from \"./interfaces.js\";\n\nexport class LocalFileMedia implements IFileMedia {\n name: string;\n length: number;\n constructor(private path: string) {\n this.name = basename(path);\n this.length = statSync(path).size;\n }\n createReadStream(interval: IReadInterval) {\n return createReadStream(this.path, interval);\n }\n}\n"]}