@jamiephan/casclib 0.0.0-dev.0 → 0.0.0-dev.2
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.
- package/README.md +585 -37
- package/build/Release/casclib.node +0 -0
- package/dist/bindings.d.ts +128 -40
- package/dist/bindings.d.ts.map +1 -1
- package/dist/bindings.js +86 -23
- package/dist/bindings.js.map +1 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/@jamiephan+casclib.node +0 -0
- package/prebuilds/linux-x64/@jamiephan+casclib.node +0 -0
- package/prebuilds/win32-x64/@jamiephan+casclib.node +0 -0
- package/src/addon.cpp +126 -3
- package/src/file.cpp +11 -11
- package/src/storage.cpp +116 -15
- package/src/storage.h +1 -0
package/README.md
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
# @jamiephan/casclib
|
|
2
2
|
|
|
3
|
-
Node.js native bindings for [CascLib](https://github.com/ladislav-zezula/CascLib) - A library to read CASC
|
|
3
|
+
Node.js native bindings for [CascLib](https://github.com/ladislav-zezula/CascLib) - A library to read CASC (Content Addressable Storage Container) from modern Blizzard games.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ Read CASC storage archives (local and online)
|
|
8
|
+
- ✅ Extract files from modern Blizzard games
|
|
9
|
+
- ✅ TypeScript support with full type definitions
|
|
10
|
+
- ✅ Cross-platform (Windows, macOS, Linux)
|
|
11
|
+
- ✅ Both CommonJS and ES Module support
|
|
12
|
+
- ✅ High-level wrapper API for ease of use
|
|
13
|
+
- ✅ Low-level bindings for advanced usage
|
|
14
|
+
|
|
15
|
+
## Supported Games
|
|
16
|
+
|
|
17
|
+
Any game using CASC storage format, including:
|
|
18
|
+
- Heroes of the Storm
|
|
19
|
+
- World of Warcraft
|
|
20
|
+
- Diablo III & IV
|
|
21
|
+
- Overwatch
|
|
22
|
+
- Starcraft II
|
|
23
|
+
- Warcraft III: Reforged
|
|
4
24
|
|
|
5
25
|
## Installation
|
|
6
26
|
|
|
@@ -14,6 +34,17 @@ Or with pnpm:
|
|
|
14
34
|
pnpm add @jamiephan/casclib
|
|
15
35
|
```
|
|
16
36
|
|
|
37
|
+
## Architecture
|
|
38
|
+
|
|
39
|
+
This package provides two layers of API:
|
|
40
|
+
|
|
41
|
+
1. **High-level Wrapper API** (Recommended) - `Storage` and `File` classes with simplified method names
|
|
42
|
+
2. **Low-level Bindings API** (Advanced) - Direct access to native bindings with CascLib.h names (interfaces: `CascStorage`, `CascFile`)
|
|
43
|
+
|
|
44
|
+
Most users should use the high-level wrapper API as shown in all examples below. The low-level bindings use exact function names from CascLib.h (e.g., `CascOpenStorage`, `CascOpenFile`).
|
|
45
|
+
|
|
46
|
+
For more details, see [BINDING_NAMING_CONVENTION.md](BINDING_NAMING_CONVENTION.md).
|
|
47
|
+
|
|
17
48
|
## Usage
|
|
18
49
|
|
|
19
50
|
### Import
|
|
@@ -22,27 +53,30 @@ The package supports both CommonJS and ES Module imports:
|
|
|
22
53
|
|
|
23
54
|
```javascript
|
|
24
55
|
// ES Module (recommended)
|
|
25
|
-
import {
|
|
56
|
+
import { Storage, File } from '@jamiephan/casclib';
|
|
26
57
|
|
|
27
58
|
// CommonJS
|
|
28
|
-
const {
|
|
59
|
+
const { Storage, File } = require('@jamiephan/casclib');
|
|
60
|
+
|
|
61
|
+
// Advanced: Direct binding access
|
|
62
|
+
import { CascStorageBinding, CascStorage, CascFile } from '@jamiephan/casclib/bindings';
|
|
29
63
|
```
|
|
30
64
|
|
|
31
65
|
### Opening a CASC Storage
|
|
32
66
|
|
|
33
67
|
```typescript
|
|
34
|
-
import {
|
|
68
|
+
import { Storage } from '@jamiephan/casclib';
|
|
35
69
|
|
|
36
|
-
const storage = new
|
|
37
|
-
storage.open('/path/to/
|
|
70
|
+
const storage = new Storage();
|
|
71
|
+
storage.open('/path/to/heroes/HeroesData');
|
|
38
72
|
|
|
39
73
|
// Check if a file exists
|
|
40
|
-
if (storage.fileExists('
|
|
74
|
+
if (storage.fileExists('mods/heroesdata.stormmod/base.stormdata/GameData/HeroData.xml')) {
|
|
41
75
|
console.log('File exists!');
|
|
42
76
|
}
|
|
43
77
|
|
|
44
78
|
// Get file information
|
|
45
|
-
const info = storage.getFileInfo('
|
|
79
|
+
const info = storage.getFileInfo('mods/heroesdata.stormmod/base.stormdata/GameData/HeroData.xml');
|
|
46
80
|
if (info) {
|
|
47
81
|
console.log(`File: ${info.name}, Size: ${info.size} bytes`);
|
|
48
82
|
}
|
|
@@ -52,7 +86,7 @@ if (info) {
|
|
|
52
86
|
|
|
53
87
|
```typescript
|
|
54
88
|
// Open and read a file
|
|
55
|
-
const file = storage.openFile('
|
|
89
|
+
const file = storage.openFile('mods/heroesdata.stormmod/base.stormdata/GameData/HeroData.xml');
|
|
56
90
|
|
|
57
91
|
// Read all content at once
|
|
58
92
|
const content = file.readAll();
|
|
@@ -62,26 +96,100 @@ console.log(content.toString());
|
|
|
62
96
|
file.setPosition(0); // Reset to beginning
|
|
63
97
|
const chunk = file.read(1024); // Read 1024 bytes
|
|
64
98
|
|
|
99
|
+
// Check file size and position
|
|
100
|
+
console.log(`Size: ${file.getSize()}, Position: ${file.getPosition()}`);
|
|
101
|
+
|
|
65
102
|
// Close the file when done
|
|
66
103
|
file.close();
|
|
67
104
|
```
|
|
68
105
|
|
|
106
|
+
### Online Storage
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// Connect to online CASC storage
|
|
110
|
+
// Format: local_cache_folder[*cdn_server_url]*code_name[*region]
|
|
111
|
+
const storage = new Storage();
|
|
112
|
+
|
|
113
|
+
// Windows - Basic usage with cache folder and product code
|
|
114
|
+
storage.openOnline('C:/Temp/CASC/Cache*hero');
|
|
115
|
+
|
|
116
|
+
// Linux/macOS - Basic usage
|
|
117
|
+
storage.openOnline('/tmp/casc/cache*hero');
|
|
118
|
+
|
|
119
|
+
// With CDN server specified
|
|
120
|
+
storage.openOnline('C:/Temp/CASC/Cache*http://us.patch.battle.net:1119*hero');
|
|
121
|
+
|
|
122
|
+
// With region specified (uses default CDN)
|
|
123
|
+
storage.openOnline('/tmp/casc/cache*hero*us');
|
|
124
|
+
|
|
125
|
+
// Full format with all parameters
|
|
126
|
+
storage.openOnline('C:/Temp/CASC/Cache*http://us.patch.battle.net:1119*hero*us');
|
|
127
|
+
|
|
128
|
+
if (storage.fileExists('mods/heroesdata.stormmod/base.stormdata/UI/Layout.xml')) {
|
|
129
|
+
const file = storage.openFile('mods/heroesdata.stormmod/base.stormdata/UI/Layout.xml');
|
|
130
|
+
const data = file.readAll();
|
|
131
|
+
file.close();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
storage.close();
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Finding Files
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// Find files matching a pattern
|
|
141
|
+
const findData = storage.findFirstFile('*.xml');
|
|
142
|
+
if (findData) {
|
|
143
|
+
console.log(`Found: ${findData.fileName} (${findData.fileSize} bytes)`);
|
|
144
|
+
|
|
145
|
+
// Continue finding
|
|
146
|
+
let nextFile = storage.findNextFile();
|
|
147
|
+
while (nextFile) {
|
|
148
|
+
console.log(`Found: ${nextFile.fileName}`);
|
|
149
|
+
nextFile = storage.findNextFile();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
storage.findClose();
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Encryption Keys
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// Add encryption key (for encrypted files)
|
|
160
|
+
storage.addEncryptionKey(0x12345678, Buffer.from('your-key-data'));
|
|
161
|
+
|
|
162
|
+
// Or add from string
|
|
163
|
+
storage.addStringEncryptionKey(0x12345678, 'your-key-string');
|
|
164
|
+
|
|
165
|
+
// Import keys from file
|
|
166
|
+
storage.importKeysFromFile('/path/to/keys.txt');
|
|
167
|
+
|
|
168
|
+
// Find a key
|
|
169
|
+
const keyData = storage.findEncryptionKey(0x12345678);
|
|
170
|
+
if (keyData) {
|
|
171
|
+
console.log('Key found:', keyData);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
69
175
|
### Complete Example
|
|
70
176
|
|
|
71
177
|
```typescript
|
|
72
|
-
import {
|
|
178
|
+
import { Storage } from '@jamiephan/casclib';
|
|
73
179
|
|
|
74
180
|
async function readGameFile() {
|
|
75
|
-
const storage = new
|
|
181
|
+
const storage = new Storage();
|
|
76
182
|
|
|
77
183
|
try {
|
|
78
|
-
storage.open('/path/to/
|
|
184
|
+
storage.open('/path/to/heroes/HeroesData');
|
|
79
185
|
|
|
80
|
-
|
|
81
|
-
|
|
186
|
+
const heroDataPath = 'mods/heroesdata.stormmod/base.stormdata/GameData/HeroData.xml';
|
|
187
|
+
if (storage.fileExists(heroDataPath)) {
|
|
188
|
+
const file = storage.openFile(heroDataPath);
|
|
82
189
|
const content = file.readAll();
|
|
83
190
|
|
|
84
191
|
console.log(`File size: ${file.getSize()} bytes`);
|
|
192
|
+
console.log(`Position: ${file.getPosition()}`);
|
|
85
193
|
console.log('Content:', content.toString());
|
|
86
194
|
|
|
87
195
|
file.close();
|
|
@@ -94,47 +202,487 @@ async function readGameFile() {
|
|
|
94
202
|
readGameFile();
|
|
95
203
|
```
|
|
96
204
|
|
|
97
|
-
## API
|
|
205
|
+
## API Reference
|
|
206
|
+
|
|
207
|
+
### Storage
|
|
98
208
|
|
|
99
|
-
|
|
209
|
+
#### Constructor
|
|
210
|
+
|
|
211
|
+
##### `constructor()`
|
|
212
|
+
Creates a new Storage instance.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const storage = new Storage();
|
|
216
|
+
```
|
|
100
217
|
|
|
101
|
-
####
|
|
102
|
-
Creates a new CascStorage instance.
|
|
218
|
+
#### Storage Operations
|
|
103
219
|
|
|
104
|
-
|
|
220
|
+
##### `open(path: string, options?: StorageOpenOptions): void`
|
|
105
221
|
Opens a CASC storage at the specified path.
|
|
106
222
|
|
|
107
|
-
|
|
108
|
-
|
|
223
|
+
**Parameters:**
|
|
224
|
+
- `path`: Path to the CASC storage directory (e.g., `/path/to/game/Data`)
|
|
225
|
+
- `options`: Optional opening options
|
|
226
|
+
- `flags`: Opening flags (number)
|
|
227
|
+
|
|
228
|
+
**Example:**
|
|
229
|
+
```typescript
|
|
230
|
+
storage.open('/path/to/heroes/HeroesData');
|
|
231
|
+
storage.open('/path/to/heroes/HeroesData', { flags: 0 });
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
##### `openOnline(path: string, options?: StorageOpenOptions): void`
|
|
235
|
+
Opens an online CASC storage.
|
|
236
|
+
|
|
237
|
+
**Parameters:**
|
|
238
|
+
- `path`: Connection string in the format: `local_cache_folder[*cdn_server_url]*code_name[*region]`
|
|
239
|
+
- `local_cache_folder`: Local cache directory for downloaded game data (reusable across runs)
|
|
240
|
+
- Windows: `C:/Temp/CASC/Cache`
|
|
241
|
+
- Linux/macOS: `/tmp/casc/cache`
|
|
242
|
+
- `cdn_server_url`: Optional CDN server URL (e.g., `http://us.patch.battle.net:1119`). If omitted, uses default CDN
|
|
243
|
+
- `code_name`: TACT product code - see [TACT documentation](https://wowdev.wiki/TACT) for available codes
|
|
244
|
+
- Examples: `hero` (Heroes of the Storm), `wow` (World of Warcraft), `s2` (StarCraft II), `d3` (Diablo III)
|
|
245
|
+
- `region`: Optional server region (e.g., `us`, `eu`, `kr`, `tw`, `cn`). If omitted, defaults to `us`
|
|
246
|
+
- `options`: Optional opening options
|
|
247
|
+
|
|
248
|
+
**Examples:**
|
|
249
|
+
```typescript
|
|
250
|
+
// Windows - Minimal format: cache folder and product code
|
|
251
|
+
storage.openOnline('C:/Temp/CASC/Cache*hero');
|
|
252
|
+
|
|
253
|
+
// Linux/macOS - Minimal format
|
|
254
|
+
storage.openOnline('/tmp/casc/cache*hero');
|
|
255
|
+
|
|
256
|
+
// With CDN server specified
|
|
257
|
+
storage.openOnline('C:/Temp/CASC/Cache*http://us.patch.battle.net:1119*hero');
|
|
258
|
+
|
|
259
|
+
// With region specified (uses default CDN)
|
|
260
|
+
storage.openOnline('/tmp/casc/cache*hero*us');
|
|
261
|
+
|
|
262
|
+
// Full format with all parameters
|
|
263
|
+
storage.openOnline('C:/Temp/CASC/Cache*http://us.patch.battle.net:1119*hero*us');
|
|
264
|
+
|
|
265
|
+
// World of Warcraft EU region
|
|
266
|
+
storage.openOnline('/tmp/casc/cache*wow*eu');
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
##### `close(): boolean`
|
|
270
|
+
Closes the storage and releases resources.
|
|
271
|
+
|
|
272
|
+
**Returns:** `true` if closed successfully, `false` otherwise.
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
const closed = storage.close();
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
##### `getStorageInfo(infoClass: number): StorageInfo`
|
|
279
|
+
Gets storage information.
|
|
280
|
+
|
|
281
|
+
**Parameters:**
|
|
282
|
+
- `infoClass`: The type of information to retrieve
|
|
109
283
|
|
|
110
|
-
|
|
284
|
+
**Returns:** Storage information object
|
|
285
|
+
|
|
286
|
+
#### File Operations
|
|
287
|
+
|
|
288
|
+
##### `openFile(filename: string, options?: FileOpenOptions): File`
|
|
111
289
|
Opens a file from the storage.
|
|
112
290
|
|
|
113
|
-
|
|
114
|
-
|
|
291
|
+
**Parameters:**
|
|
292
|
+
- `filename`: Name of the file to open (use backslashes for paths)
|
|
293
|
+
- `options`: Optional opening options
|
|
294
|
+
- `flags`: Open flags (number)
|
|
295
|
+
|
|
296
|
+
**Returns:** A `File` object
|
|
115
297
|
|
|
116
|
-
|
|
298
|
+
**Example:**
|
|
299
|
+
```typescript
|
|
300
|
+
const file = storage.openFile('mods/heroesdata.stormmod/base.stormdata/GameData/HeroData.xml');
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
##### `fileExists(filename: string): boolean`
|
|
117
304
|
Checks if a file exists in the storage.
|
|
118
305
|
|
|
119
|
-
|
|
306
|
+
**Parameters:**
|
|
307
|
+
- `filename`: Name of the file to check
|
|
308
|
+
|
|
309
|
+
**Returns:** `true` if file exists, `false` otherwise
|
|
310
|
+
|
|
311
|
+
**Example:**
|
|
312
|
+
```typescript
|
|
313
|
+
if (storage.fileExists('some-file.txt')) {
|
|
314
|
+
console.log('File exists!');
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
##### `getFileInfo(filename: string): FileInfo | null`
|
|
319
|
+
Gets information about a file.
|
|
320
|
+
|
|
321
|
+
**Parameters:**
|
|
322
|
+
- `filename`: Name of the file
|
|
323
|
+
|
|
324
|
+
**Returns:** File information object or `null` if file doesn't exist
|
|
325
|
+
|
|
326
|
+
**TypeScript Interface:**
|
|
327
|
+
```typescript
|
|
328
|
+
interface FileInfo {
|
|
329
|
+
name: string;
|
|
330
|
+
size: number;
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Example:**
|
|
335
|
+
```typescript
|
|
336
|
+
const info = storage.getFileInfo('some-file.txt');
|
|
337
|
+
if (info) {
|
|
338
|
+
console.log(`Name: ${info.name}, Size: ${info.size} bytes`);
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
#### File Finding
|
|
343
|
+
|
|
344
|
+
##### `findFirstFile(mask?: string, listFile?: string): FindData | null`
|
|
345
|
+
Finds the first file matching the mask.
|
|
346
|
+
|
|
347
|
+
**Parameters:**
|
|
348
|
+
- `mask`: File mask pattern (e.g., `*.lua`, `Interface\\*`)
|
|
349
|
+
- `listFile`: Optional list file path
|
|
350
|
+
|
|
351
|
+
**Returns:** Find data object or `null` if no files found
|
|
352
|
+
|
|
353
|
+
**Example:**
|
|
354
|
+
```typescript
|
|
355
|
+
const findData = storage.findFirstFile('*.xml');
|
|
356
|
+
if (findData) {
|
|
357
|
+
console.log(`Found: ${findData.fileName}`);
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
##### `findNextFile(): FindData | null`
|
|
362
|
+
Finds the next file in the search.
|
|
363
|
+
|
|
364
|
+
**Returns:** Find data object or `null` if no more files
|
|
365
|
+
|
|
366
|
+
**Example:**
|
|
367
|
+
```typescript
|
|
368
|
+
let nextFile = storage.findNextFile();
|
|
369
|
+
while (nextFile) {
|
|
370
|
+
console.log(`Found: ${nextFile.fileName}`);
|
|
371
|
+
nextFile = storage.findNextFile();
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
##### `findClose(): boolean`
|
|
376
|
+
Closes the current find operation.
|
|
377
|
+
|
|
378
|
+
**Returns:** `true` if closed successfully
|
|
379
|
+
|
|
380
|
+
**Example:**
|
|
381
|
+
```typescript
|
|
382
|
+
storage.findClose();
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
#### Encryption Key Management
|
|
386
|
+
|
|
387
|
+
##### `addEncryptionKey(keyName: number, key: Buffer): boolean`
|
|
388
|
+
Adds an encryption key to the storage.
|
|
389
|
+
|
|
390
|
+
**Parameters:**
|
|
391
|
+
- `keyName`: Name/ID of the key
|
|
392
|
+
- `key`: Key data as Buffer
|
|
393
|
+
|
|
394
|
+
**Returns:** `true` if added successfully
|
|
395
|
+
|
|
396
|
+
**Example:**
|
|
397
|
+
```typescript
|
|
398
|
+
const keyData = Buffer.from('your-key-bytes');
|
|
399
|
+
storage.addEncryptionKey(0x12345678, keyData);
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
##### `addStringEncryptionKey(keyName: number, keyStr: string): boolean`
|
|
403
|
+
Adds an encryption key from a string.
|
|
404
|
+
|
|
405
|
+
**Parameters:**
|
|
406
|
+
- `keyName`: Name/ID of the key
|
|
407
|
+
- `keyStr`: Key as string
|
|
120
408
|
|
|
121
|
-
|
|
122
|
-
Reads data from the file. Default: 4096 bytes.
|
|
409
|
+
**Returns:** `true` if added successfully
|
|
123
410
|
|
|
124
|
-
|
|
411
|
+
**Example:**
|
|
412
|
+
```typescript
|
|
413
|
+
storage.addStringEncryptionKey(0x12345678, 'your-key-string');
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
##### `importKeysFromString(keyList: string): boolean`
|
|
417
|
+
Imports encryption keys from a string.
|
|
418
|
+
|
|
419
|
+
**Parameters:**
|
|
420
|
+
- `keyList`: String containing key list
|
|
421
|
+
|
|
422
|
+
**Returns:** `true` if imported successfully
|
|
423
|
+
|
|
424
|
+
##### `importKeysFromFile(filePath: string): boolean`
|
|
425
|
+
Imports encryption keys from a file.
|
|
426
|
+
|
|
427
|
+
**Parameters:**
|
|
428
|
+
- `filePath`: Path to the key file
|
|
429
|
+
|
|
430
|
+
**Returns:** `true` if imported successfully
|
|
431
|
+
|
|
432
|
+
**Example:**
|
|
433
|
+
```typescript
|
|
434
|
+
storage.importKeysFromFile('/path/to/keys.txt');
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
##### `findEncryptionKey(keyName: number): Buffer | null`
|
|
438
|
+
Finds an encryption key by name.
|
|
439
|
+
|
|
440
|
+
**Parameters:**
|
|
441
|
+
- `keyName`: Name/ID of the key
|
|
442
|
+
|
|
443
|
+
**Returns:** Key data or `null` if not found
|
|
444
|
+
|
|
445
|
+
**Example:**
|
|
446
|
+
```typescript
|
|
447
|
+
const key = storage.findEncryptionKey(0x12345678);
|
|
448
|
+
if (key) {
|
|
449
|
+
console.log('Key found:', key);
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
##### `getNotFoundEncryptionKey(): number | null`
|
|
454
|
+
Gets the name of an encryption key that was not found.
|
|
455
|
+
|
|
456
|
+
**Returns:** Key name or `null`
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
### File
|
|
461
|
+
|
|
462
|
+
#### Constructor
|
|
463
|
+
|
|
464
|
+
The `File` class is instantiated by calling `storage.openFile()`. Do not construct it directly.
|
|
465
|
+
|
|
466
|
+
#### File Reading
|
|
467
|
+
|
|
468
|
+
##### `read(bytesToRead?: number): Buffer`
|
|
469
|
+
Reads data from the file at the current position.
|
|
470
|
+
|
|
471
|
+
**Parameters:**
|
|
472
|
+
- `bytesToRead`: Number of bytes to read (default: 4096)
|
|
473
|
+
|
|
474
|
+
**Returns:** Buffer containing the read data
|
|
475
|
+
|
|
476
|
+
**Example:**
|
|
477
|
+
```typescript
|
|
478
|
+
const chunk = file.read(1024); // Read 1024 bytes
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
##### `readAll(): Buffer`
|
|
125
482
|
Reads all data from the file.
|
|
126
483
|
|
|
127
|
-
|
|
128
|
-
|
|
484
|
+
**Returns:** Buffer containing all file data
|
|
485
|
+
|
|
486
|
+
**Example:**
|
|
487
|
+
```typescript
|
|
488
|
+
const content = file.readAll();
|
|
489
|
+
console.log(content.toString());
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
#### File Information
|
|
493
|
+
|
|
494
|
+
##### `getSize(): number`
|
|
495
|
+
Gets the file size in bytes (32-bit).
|
|
496
|
+
|
|
497
|
+
**Returns:** File size as a 32-bit number
|
|
498
|
+
|
|
499
|
+
**Example:**
|
|
500
|
+
```typescript
|
|
501
|
+
const size = file.getSize();
|
|
502
|
+
console.log(`File size: ${size} bytes`);
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
##### `getSize64(): number`
|
|
506
|
+
Gets the file size in bytes (64-bit).
|
|
507
|
+
|
|
508
|
+
**Returns:** File size as a 64-bit number
|
|
509
|
+
|
|
510
|
+
**Example:**
|
|
511
|
+
```typescript
|
|
512
|
+
const size = file.getSize64();
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
##### `getFileInfo(infoClass: number): FileInfoResult`
|
|
516
|
+
Gets detailed file information.
|
|
517
|
+
|
|
518
|
+
**Parameters:**
|
|
519
|
+
- `infoClass`: The type of information to retrieve
|
|
520
|
+
|
|
521
|
+
**Returns:** File information result object
|
|
522
|
+
|
|
523
|
+
#### File Position
|
|
524
|
+
|
|
525
|
+
##### `getPosition(): number`
|
|
526
|
+
Gets the current file position (32-bit).
|
|
527
|
+
|
|
528
|
+
**Returns:** Current position in bytes
|
|
529
|
+
|
|
530
|
+
**Example:**
|
|
531
|
+
```typescript
|
|
532
|
+
const pos = file.getPosition();
|
|
533
|
+
console.log(`Current position: ${pos}`);
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
##### `getPosition64(): number`
|
|
537
|
+
Gets the current file position (64-bit).
|
|
538
|
+
|
|
539
|
+
**Returns:** Current position in bytes
|
|
129
540
|
|
|
130
|
-
|
|
131
|
-
|
|
541
|
+
##### `setPosition(position: number): number`
|
|
542
|
+
Sets the file position (32-bit).
|
|
132
543
|
|
|
133
|
-
|
|
134
|
-
|
|
544
|
+
**Parameters:**
|
|
545
|
+
- `position`: New position in bytes
|
|
135
546
|
|
|
136
|
-
|
|
137
|
-
|
|
547
|
+
**Returns:** The new position
|
|
548
|
+
|
|
549
|
+
**Example:**
|
|
550
|
+
```typescript
|
|
551
|
+
file.setPosition(0); // Reset to beginning
|
|
552
|
+
file.setPosition(100); // Jump to byte 100
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
##### `setPosition64(position: number, moveMethod?: number): number`
|
|
556
|
+
Sets the file position (64-bit) with move method.
|
|
557
|
+
|
|
558
|
+
**Parameters:**
|
|
559
|
+
- `position`: New position in bytes
|
|
560
|
+
- `moveMethod`: Optional move method (FILE_BEGIN, FILE_CURRENT, FILE_END)
|
|
561
|
+
|
|
562
|
+
**Returns:** The new position
|
|
563
|
+
|
|
564
|
+
**Example:**
|
|
565
|
+
```typescript
|
|
566
|
+
file.setPosition64(0); // Reset to beginning
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
#### File Operations
|
|
570
|
+
|
|
571
|
+
##### `setFileFlags(flags: number): boolean`
|
|
572
|
+
Sets file flags.
|
|
573
|
+
|
|
574
|
+
**Parameters:**
|
|
575
|
+
- `flags`: Flags to set
|
|
576
|
+
|
|
577
|
+
**Returns:** `true` if set successfully
|
|
578
|
+
|
|
579
|
+
##### `close(): boolean`
|
|
580
|
+
Closes the file and releases resources.
|
|
581
|
+
|
|
582
|
+
**Returns:** `true` if closed successfully, `false` otherwise
|
|
583
|
+
|
|
584
|
+
**Example:**
|
|
585
|
+
```typescript
|
|
586
|
+
file.close();
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
---
|
|
590
|
+
|
|
591
|
+
## TypeScript Interfaces
|
|
592
|
+
|
|
593
|
+
```typescript
|
|
594
|
+
interface StorageOpenOptions {
|
|
595
|
+
flags?: number;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
interface FileOpenOptions {
|
|
599
|
+
flags?: number;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
interface FileInfo {
|
|
603
|
+
name: string;
|
|
604
|
+
size: number;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
interface FindData {
|
|
608
|
+
fileName: string;
|
|
609
|
+
fileSize: number;
|
|
610
|
+
localeFlags: number;
|
|
611
|
+
fileDataId: number;
|
|
612
|
+
contentFlags: number;
|
|
613
|
+
// ... additional fields
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
interface StorageInfo {
|
|
617
|
+
// Storage-specific information
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
interface FileInfoResult {
|
|
621
|
+
// File-specific information
|
|
622
|
+
}
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
## Advanced Usage
|
|
626
|
+
|
|
627
|
+
### Direct Binding Access
|
|
628
|
+
|
|
629
|
+
For advanced users who need direct access to the native bindings:
|
|
630
|
+
|
|
631
|
+
```typescript
|
|
632
|
+
import { CascStorageBinding, CascStorage, CascFile } from '@jamiephan/casclib/bindings';
|
|
633
|
+
import * as constants from '@jamiephan/casclib';
|
|
634
|
+
|
|
635
|
+
const storage: CascStorage = new CascStorageBinding();
|
|
636
|
+
storage.CascOpenStorage('/path/to/storage', 0);
|
|
637
|
+
|
|
638
|
+
const file: CascFile = storage.CascOpenFile('filename.txt', constants.CASC_OPEN_BY_NAME);
|
|
639
|
+
const size = file.CascGetFileSize64();
|
|
640
|
+
const content = file.readFileAll();
|
|
641
|
+
file.CascCloseFile();
|
|
642
|
+
|
|
643
|
+
storage.CascCloseStorage();
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### Binding Naming Convention
|
|
647
|
+
|
|
648
|
+
The low-level bindings use **exact names from CascLib.h**:
|
|
649
|
+
- C++ function: `CascOpenStorageEx` → JS binding: `CascOpenStorageEx`
|
|
650
|
+
- C++ function: `CascGetFileSize64` → JS binding: `CascGetFileSize64`
|
|
651
|
+
- Interfaces are prefixed with `CASC`: `CascStorage`, `CascFile`, `CascFindData`, etc.
|
|
652
|
+
|
|
653
|
+
The high-level wrapper simplifies these names:
|
|
654
|
+
- Binding: `CascOpenStorageEx` → Wrapper: `openEx()`
|
|
655
|
+
- Binding: `CascGetFileSize64` → Wrapper: `getSize64()`
|
|
656
|
+
|
|
657
|
+
See [BINDING_NAMING_CONVENTION.md](BINDING_NAMING_CONVENTION.md) for complete details.
|
|
658
|
+
|
|
659
|
+
## Performance Tips
|
|
660
|
+
|
|
661
|
+
1. **Use `readAll()` for small files**: More efficient than multiple `read()` calls
|
|
662
|
+
2. **Use `read(size)` for large files**: Better memory management for streaming
|
|
663
|
+
3. **Close files and storage**: Always close resources when done to prevent memory leaks
|
|
664
|
+
4. **Online storage caching**: First access downloads data to temp directory for better subsequent performance
|
|
665
|
+
|
|
666
|
+
## Error Handling
|
|
667
|
+
|
|
668
|
+
All methods that can fail will throw exceptions. Always use try-catch blocks:
|
|
669
|
+
|
|
670
|
+
```typescript
|
|
671
|
+
try {
|
|
672
|
+
const storage = new Storage();
|
|
673
|
+
storage.open('/path/to/storage');
|
|
674
|
+
|
|
675
|
+
if (storage.fileExists('some-file.txt')) {
|
|
676
|
+
const file = storage.openFile('some-file.txt');
|
|
677
|
+
const content = file.readAll();
|
|
678
|
+
file.close();
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
storage.close();
|
|
682
|
+
} catch (error) {
|
|
683
|
+
console.error('Error processing storage:', error);
|
|
684
|
+
}
|
|
685
|
+
```
|
|
138
686
|
|
|
139
687
|
## License
|
|
140
688
|
|
|
Binary file
|