node-liblzma 2.1.0 → 3.0.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 (56) hide show
  1. package/README.md +431 -727
  2. package/index.d.ts +34 -0
  3. package/lib/cli/nxz.d.ts +7 -0
  4. package/lib/cli/nxz.d.ts.map +1 -0
  5. package/lib/cli/nxz.js +578 -0
  6. package/lib/cli/nxz.js.map +1 -0
  7. package/lib/lzma.browser.d.ts +24 -0
  8. package/lib/lzma.browser.d.ts.map +1 -0
  9. package/lib/lzma.browser.js +30 -0
  10. package/lib/lzma.browser.js.map +1 -0
  11. package/lib/lzma.d.ts +83 -0
  12. package/lib/lzma.d.ts.map +1 -1
  13. package/lib/lzma.inline.d.ts +30 -0
  14. package/lib/lzma.inline.d.ts.map +1 -0
  15. package/lib/lzma.inline.js +68 -0
  16. package/lib/lzma.inline.js.map +1 -0
  17. package/lib/lzma.js +78 -0
  18. package/lib/lzma.js.map +1 -1
  19. package/lib/wasm/bindings.d.ts +109 -0
  20. package/lib/wasm/bindings.d.ts.map +1 -0
  21. package/lib/wasm/bindings.js +307 -0
  22. package/lib/wasm/bindings.js.map +1 -0
  23. package/lib/wasm/compress.d.ts +32 -0
  24. package/lib/wasm/compress.d.ts.map +1 -0
  25. package/lib/wasm/compress.js +47 -0
  26. package/lib/wasm/compress.js.map +1 -0
  27. package/lib/wasm/decompress.d.ts +32 -0
  28. package/lib/wasm/decompress.d.ts.map +1 -0
  29. package/lib/wasm/decompress.js +45 -0
  30. package/lib/wasm/decompress.js.map +1 -0
  31. package/lib/wasm/index.d.ts +14 -0
  32. package/lib/wasm/index.d.ts.map +1 -0
  33. package/lib/wasm/index.js +18 -0
  34. package/lib/wasm/index.js.map +1 -0
  35. package/lib/wasm/liblzma.inline.d.ts +10 -0
  36. package/lib/wasm/liblzma.inline.d.ts.map +1 -0
  37. package/lib/wasm/liblzma.inline.js +10 -0
  38. package/lib/wasm/liblzma.inline.js.map +1 -0
  39. package/lib/wasm/memory.d.ts +57 -0
  40. package/lib/wasm/memory.d.ts.map +1 -0
  41. package/lib/wasm/memory.js +108 -0
  42. package/lib/wasm/memory.js.map +1 -0
  43. package/lib/wasm/stream.d.ts +35 -0
  44. package/lib/wasm/stream.d.ts.map +1 -0
  45. package/lib/wasm/stream.js +164 -0
  46. package/lib/wasm/stream.js.map +1 -0
  47. package/lib/wasm/types.d.ts +77 -0
  48. package/lib/wasm/types.d.ts.map +1 -0
  49. package/lib/wasm/types.js +55 -0
  50. package/lib/wasm/types.js.map +1 -0
  51. package/lib/wasm/utils.d.ts +62 -0
  52. package/lib/wasm/utils.d.ts.map +1 -0
  53. package/lib/wasm/utils.js +162 -0
  54. package/lib/wasm/utils.js.map +1 -0
  55. package/package.json +27 -3
  56. package/src/bindings/module.cpp +196 -0
@@ -17,6 +17,193 @@
17
17
  **/
18
18
 
19
19
  #include "node-liblzma.hpp"
20
+ #include <cstring>
21
+
22
+ // XZ magic bytes: 0xFD + "7zXZ" + 0x00
23
+ static const uint8_t XZ_MAGIC[6] = {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00};
24
+
25
+ /**
26
+ * Check if a buffer starts with the XZ magic bytes.
27
+ * @param info[0] Buffer to check
28
+ * @returns true if the buffer is an XZ stream, false otherwise
29
+ */
30
+ Napi::Value IsXZ(const Napi::CallbackInfo &info)
31
+ {
32
+ Napi::Env env = info.Env();
33
+
34
+ if (info.Length() < 1 || !info[0].IsBuffer())
35
+ {
36
+ Napi::TypeError::New(env, "Expected a Buffer argument").ThrowAsJavaScriptException();
37
+ return env.Null();
38
+ }
39
+
40
+ Napi::Buffer<uint8_t> buf = info[0].As<Napi::Buffer<uint8_t>>();
41
+
42
+ // Need at least 6 bytes for XZ magic
43
+ if (buf.Length() < 6)
44
+ {
45
+ return Napi::Boolean::New(env, false);
46
+ }
47
+
48
+ bool isXz = std::memcmp(buf.Data(), XZ_MAGIC, 6) == 0;
49
+ return Napi::Boolean::New(env, isXz);
50
+ }
51
+
52
+ /**
53
+ * Get liblzma version string (runtime).
54
+ * @returns Version string like "5.4.1"
55
+ */
56
+ Napi::Value VersionString(const Napi::CallbackInfo &info)
57
+ {
58
+ Napi::Env env = info.Env();
59
+ return Napi::String::New(env, lzma_version_string());
60
+ }
61
+
62
+ /**
63
+ * Get liblzma version number (runtime).
64
+ * @returns Version as integer (e.g., 50040010 for 5.4.1)
65
+ */
66
+ Napi::Value VersionNumber(const Napi::CallbackInfo &info)
67
+ {
68
+ Napi::Env env = info.Env();
69
+ return Napi::Number::New(env, static_cast<double>(lzma_version_number()));
70
+ }
71
+
72
+ /**
73
+ * Get memory usage for easy encoder with given preset.
74
+ * @param info[0] Preset level (0-9, optionally OR'd with LZMA_PRESET_EXTREME)
75
+ * @returns Memory usage in bytes, or 0 if preset is invalid
76
+ */
77
+ Napi::Value EasyEncoderMemusage(const Napi::CallbackInfo &info)
78
+ {
79
+ Napi::Env env = info.Env();
80
+
81
+ if (info.Length() < 1 || !info[0].IsNumber())
82
+ {
83
+ Napi::TypeError::New(env, "Expected a preset number argument").ThrowAsJavaScriptException();
84
+ return env.Null();
85
+ }
86
+
87
+ uint32_t preset = info[0].As<Napi::Number>().Uint32Value();
88
+ uint64_t memusage = lzma_easy_encoder_memusage(preset);
89
+
90
+ return Napi::Number::New(env, static_cast<double>(memusage));
91
+ }
92
+
93
+ /**
94
+ * Get memory usage for easy decoder.
95
+ * @returns Memory usage in bytes
96
+ */
97
+ Napi::Value EasyDecoderMemusage(const Napi::CallbackInfo &info)
98
+ {
99
+ Napi::Env env = info.Env();
100
+
101
+ // lzma_easy_decoder_memusage takes a preset for memlimit estimation
102
+ // but the actual decoder doesn't need a preset. Use default preset.
103
+ uint64_t memusage = lzma_easy_decoder_memusage(LZMA_PRESET_DEFAULT);
104
+
105
+ return Napi::Number::New(env, static_cast<double>(memusage));
106
+ }
107
+
108
+ /**
109
+ * Parse the Stream Footer and Index from an XZ file to get metadata.
110
+ * @param info[0] Buffer containing the XZ file (must be complete)
111
+ * @returns Object with uncompressed_size, compressed_size, stream_count, block_count, check
112
+ */
113
+ Napi::Value ParseFileIndex(const Napi::CallbackInfo &info)
114
+ {
115
+ Napi::Env env = info.Env();
116
+
117
+ if (info.Length() < 1 || !info[0].IsBuffer())
118
+ {
119
+ Napi::TypeError::New(env, "Expected a Buffer argument").ThrowAsJavaScriptException();
120
+ return env.Null();
121
+ }
122
+
123
+ Napi::Buffer<uint8_t> buf = info[0].As<Napi::Buffer<uint8_t>>();
124
+ const uint8_t *data = buf.Data();
125
+ size_t size = buf.Length();
126
+
127
+ // Minimum XZ file: header (12) + block (varies) + index (varies) + footer (12)
128
+ // Stream header is 12 bytes, footer is 12 bytes
129
+ if (size < LZMA_STREAM_HEADER_SIZE * 2)
130
+ {
131
+ Napi::Error::New(env, "Buffer too small for XZ stream").ThrowAsJavaScriptException();
132
+ return env.Null();
133
+ }
134
+
135
+ // Verify XZ magic
136
+ if (std::memcmp(data, XZ_MAGIC, 6) != 0)
137
+ {
138
+ Napi::Error::New(env, "Not an XZ stream (invalid magic)").ThrowAsJavaScriptException();
139
+ return env.Null();
140
+ }
141
+
142
+ // Parse stream header
143
+ lzma_stream_flags header_flags;
144
+ lzma_ret ret = lzma_stream_header_decode(&header_flags, data);
145
+ if (ret != LZMA_OK)
146
+ {
147
+ Napi::Error::New(env, "Failed to decode stream header").ThrowAsJavaScriptException();
148
+ return env.Null();
149
+ }
150
+
151
+ // Parse stream footer (last 12 bytes)
152
+ lzma_stream_flags footer_flags;
153
+ ret = lzma_stream_footer_decode(&footer_flags, data + size - LZMA_STREAM_HEADER_SIZE);
154
+ if (ret != LZMA_OK)
155
+ {
156
+ Napi::Error::New(env, "Failed to decode stream footer").ThrowAsJavaScriptException();
157
+ return env.Null();
158
+ }
159
+
160
+ // Verify header and footer match
161
+ ret = lzma_stream_flags_compare(&header_flags, &footer_flags);
162
+ if (ret != LZMA_OK)
163
+ {
164
+ Napi::Error::New(env, "Stream header and footer do not match").ThrowAsJavaScriptException();
165
+ return env.Null();
166
+ }
167
+
168
+ // Calculate index position: footer starts at (size - 12), index is backward_size bytes before that
169
+ size_t footer_pos = size - LZMA_STREAM_HEADER_SIZE;
170
+ size_t index_size = footer_flags.backward_size;
171
+
172
+ if (index_size > footer_pos - LZMA_STREAM_HEADER_SIZE)
173
+ {
174
+ Napi::Error::New(env, "Invalid index size in footer").ThrowAsJavaScriptException();
175
+ return env.Null();
176
+ }
177
+
178
+ size_t index_pos = footer_pos - index_size;
179
+
180
+ // Decode the index
181
+ lzma_index *index = nullptr;
182
+ uint64_t memlimit = UINT64_MAX;
183
+ size_t in_pos = 0;
184
+
185
+ ret = lzma_index_buffer_decode(&index, &memlimit, nullptr,
186
+ data + index_pos, &in_pos, index_size);
187
+ if (ret != LZMA_OK || index == nullptr)
188
+ {
189
+ Napi::Error::New(env, "Failed to decode index").ThrowAsJavaScriptException();
190
+ return env.Null();
191
+ }
192
+
193
+ // Extract metadata from index
194
+ Napi::Object result = Napi::Object::New(env);
195
+ result.Set("uncompressedSize", Napi::Number::New(env, static_cast<double>(lzma_index_uncompressed_size(index))));
196
+ result.Set("compressedSize", Napi::Number::New(env, static_cast<double>(lzma_index_total_size(index))));
197
+ result.Set("streamCount", Napi::Number::New(env, static_cast<double>(lzma_index_stream_count(index))));
198
+ result.Set("blockCount", Napi::Number::New(env, static_cast<double>(lzma_index_block_count(index))));
199
+ result.Set("check", Napi::Number::New(env, static_cast<double>(footer_flags.check)));
200
+ result.Set("memoryUsage", Napi::Number::New(env, static_cast<double>(lzma_index_memused(index))));
201
+
202
+ // Clean up
203
+ lzma_index_end(index, nullptr);
204
+
205
+ return result;
206
+ }
20
207
 
21
208
  Napi::Object Init(Napi::Env env, Napi::Object exports)
22
209
  {
@@ -101,6 +288,15 @@ Napi::Object Init(Napi::Env env, Napi::Object exports)
101
288
 
102
289
  // Tell companion script if we are thread-able or not
103
290
  exports.Set(Napi::String::New(env, "HAS_THREADS_SUPPORT"), Napi::Boolean::New(env, HAS_THREADS_SUPPORT));
291
+
292
+ // Utility functions
293
+ exports.Set(Napi::String::New(env, "isXZ"), Napi::Function::New(env, IsXZ));
294
+ exports.Set(Napi::String::New(env, "versionString"), Napi::Function::New(env, VersionString));
295
+ exports.Set(Napi::String::New(env, "versionNumber"), Napi::Function::New(env, VersionNumber));
296
+ exports.Set(Napi::String::New(env, "easyEncoderMemusage"), Napi::Function::New(env, EasyEncoderMemusage));
297
+ exports.Set(Napi::String::New(env, "easyDecoderMemusage"), Napi::Function::New(env, EasyDecoderMemusage));
298
+ exports.Set(Napi::String::New(env, "parseFileIndex"), Napi::Function::New(env, ParseFileIndex));
299
+
104
300
  return exports;
105
301
  }
106
302