| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| 'use strict'; | ||
|
|
||
| const fs = require('fs'); | ||
| const lzma = require('lzma-native'); | ||
| const utils = require('../utils'); | ||
| const streamifier = require('streamifier'); | ||
| const stream = require('stream'); | ||
|
|
||
| class XzFileStream extends stream.Transform { | ||
| constructor(opts) { | ||
| opts = opts || {}; | ||
| super(opts); | ||
|
|
||
| const sourceType = utils.sourceType(opts.source); | ||
| const compressor = lzma.createCompressor(opts.lzma); | ||
|
|
||
| compressor.on('error', err => this.emit('error', err)); | ||
| compressor.on('end', () => this.push(null)); | ||
| compressor.on('data', chunk => this.push(chunk)); | ||
|
|
||
| if (sourceType === 'file') { | ||
| const stream = fs.createReadStream(opts.source, opts.fs); | ||
| stream.on('error', err => this.emit('error', err)); | ||
| stream.pipe(compressor); | ||
| return; | ||
| } | ||
|
|
||
| if (sourceType === 'buffer') { | ||
| const stream = streamifier.createReadStream(opts.source, opts.streamifier); | ||
| stream.on('error', err => this.emit('error', err)); | ||
| stream.pipe(compressor); | ||
| return; | ||
| } | ||
|
|
||
| if (sourceType === 'stream') { | ||
| opts.source.on('error', err => this.emit('error', err)); | ||
| opts.source.pipe(compressor); | ||
| return; | ||
| } | ||
|
|
||
| // For streaming input | ||
| this.on('pipe', srcStream => { | ||
| srcStream.unpipe(this); | ||
| srcStream.pipe(compressor); | ||
| }); | ||
| } | ||
|
|
||
| _transform(chunk, encoding, callback) { | ||
| // This will be handled by the compressor stream | ||
| callback(); | ||
| } | ||
|
Comment thread
Comment on lines
+42
to
+51
Copy link
Copy Markdown
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThe XzFileStream class extends stream.Transform, but its _transform method is a no-op, and the on('pipe') handler effectively bypasses the stream's writable side by redirecting the input directly to the internal compressor. This is an unconventional and misleading use of a Transform stream. If the stream is primarily intended to encapsulate a source and produce compressed output (as implied by index.d.ts defining it as ReadStream), it should extend stream.Readable and manage its input via opts.source or its _read method, without accepting piped input in this manner.
Sorry, something went wrong.
All reactions
|
||
| } | ||
|
|
||
| module.exports = XzFileStream; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| 'use strict'; | ||
|
|
||
| const utils = require('../utils'); | ||
|
|
||
| let XzFileStream; | ||
| let XzUncompressStream; | ||
|
|
||
| function checkDependency() { | ||
| try { | ||
| require('lzma-native'); | ||
| return true; | ||
| } catch (err) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| function throwIfNoDependency() { | ||
| if (!checkDependency()) { | ||
| throw new Error('lzma-native is required for xz compression/decompression. Please install it with: npm install lzma-native'); | ||
| } | ||
| } | ||
|
|
||
| // Lazy load the implementation | ||
| function getImplementation() { | ||
| if (!XzFileStream) { | ||
| throwIfNoDependency(); | ||
| XzFileStream = require('./file_stream'); | ||
| XzUncompressStream = require('./uncompress_stream'); | ||
| } | ||
| return { XzFileStream, XzUncompressStream }; | ||
| } | ||
|
|
||
| exports.FileStream = function(opts) { | ||
| const { XzFileStream } = getImplementation(); | ||
| return new XzFileStream(opts); | ||
| }; | ||
|
|
||
| exports.UncompressStream = function(opts) { | ||
| const { XzUncompressStream } = getImplementation(); | ||
| return new XzUncompressStream(opts); | ||
| }; | ||
|
|
||
| exports.compressFile = function(source, dest, opts) { | ||
| throwIfNoDependency(); | ||
| const { XzFileStream } = getImplementation(); | ||
| return utils.makeFileProcessFn(XzFileStream)(source, dest, opts); | ||
| }; | ||
|
|
||
| exports.uncompress = function(source, dest, opts) { | ||
| throwIfNoDependency(); | ||
| const { XzUncompressStream } = getImplementation(); | ||
| return utils.makeFileProcessFn(XzUncompressStream)(source, dest, opts); | ||
| }; | ||
|
|
||
| exports.decompress = exports.uncompress; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| 'use strict'; | ||
|
|
||
| const fs = require('fs'); | ||
| const lzma = require('lzma-native'); | ||
| const utils = require('../utils'); | ||
| const streamifier = require('streamifier'); | ||
| const { PassThrough } = require('stream'); | ||
|
|
||
| class XzUncompressStream extends PassThrough { | ||
| constructor(opts) { | ||
| opts = opts || {}; | ||
| super(opts); | ||
|
|
||
| const sourceType = utils.sourceType(opts.source); | ||
| // Set text mode to true to handle line endings correctly on Windows | ||
| const decompressor = lzma.createDecompressor({ | ||
| ...opts.lzma, | ||
| textMode: true, | ||
| }); | ||
|
|
||
| decompressor.on('error', err => this.emit('error', err)); | ||
| decompressor.on('end', () => this.end()); | ||
|
|
||
| // Handle single file decompression | ||
| if (sourceType === 'file') { | ||
| const stream = fs.createReadStream(opts.source, opts.fs); | ||
| stream.on('error', err => this.emit('error', err)); | ||
| stream.pipe(decompressor).pipe(this); | ||
| return; | ||
| } | ||
|
|
||
| if (sourceType === 'buffer') { | ||
| const stream = streamifier.createReadStream(opts.source, opts.streamifier); | ||
| stream.on('error', err => this.emit('error', err)); | ||
| stream.pipe(decompressor).pipe(this); | ||
| return; | ||
| } | ||
|
|
||
| if (sourceType === 'stream') { | ||
| opts.source.on('error', err => this.emit('error', err)); | ||
| opts.source.pipe(decompressor).pipe(this); | ||
| return; | ||
| } | ||
|
|
||
| // For streaming input | ||
| this.on('pipe', srcStream => { | ||
| srcStream.unpipe(this); | ||
| srcStream.pipe(decompressor).pipe(this); | ||
| }); | ||
|
Comment thread
Comment on lines
+46
to
+49
Copy link
Copy Markdown
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualitySimilar to XzFileStream, the on('pipe') handler in XzUncompressStream is problematic. If this stream is intended to be a Readable stream (as implied by the corrected index.d.ts type), it should not accept piped input in this manner. This pattern bypasses the stream's primary role and can lead to confusing behavior and misuse.
Sorry, something went wrong.
All reactions
|
||
| } | ||
| } | ||
|
|
||
| module.exports = XzUncompressStream; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const assert = require('assert'); | ||
| const compressing = require('../..'); | ||
|
|
||
| describe('test/xz/file_stream.test.js', () => { | ||
| const sourceFile = path.join(__dirname, '../fixtures/xx.log'); | ||
| const xzFile = path.join(__dirname, '../fixtures/xx.log.xz'); | ||
|
|
||
| it('should compress file to xz', done => { | ||
| const dest = path.join(__dirname, '../fixtures/xx.log.xz.tmp'); | ||
| compressing.xz.compressFile(sourceFile, dest) | ||
| .then(() => { | ||
| assert(fs.existsSync(dest)); | ||
| // 文件大小应该小于原始文件 | ||
| assert(fs.statSync(dest).size < fs.statSync(sourceFile).size); | ||
| fs.unlinkSync(dest); | ||
| done(); | ||
| }) | ||
| .catch(done); | ||
| }); | ||
|
|
||
| it('should decompress xz file to log', done => { | ||
| const dest = path.join(__dirname, '../fixtures/xx.log.tmp'); | ||
| compressing.xz.uncompress(xzFile, dest) | ||
| .then(() => { | ||
| assert(fs.existsSync(dest)); | ||
| // 内容应该一致 | ||
| const raw = fs.readFileSync(sourceFile); | ||
| const out = fs.readFileSync(dest); | ||
| assert.equal(out.length, raw.length); | ||
| assert.deepEqual(out, raw); | ||
| fs.unlinkSync(dest); | ||
| done(); | ||
| }) | ||
| .catch(done); | ||
| }); | ||
|
|
||
| it('should compress buffer to xz', done => { | ||
| const buf = fs.readFileSync(sourceFile); | ||
| const dest = path.join(__dirname, '../fixtures/xx.log.xz.tmp'); | ||
| compressing.xz.compressFile(buf, dest) | ||
| .then(() => { | ||
| assert(fs.existsSync(dest)); | ||
| fs.unlinkSync(dest); | ||
| done(); | ||
| }) | ||
| .catch(done); | ||
| }); | ||
|
|
||
| it('should decompress xz buffer to log', done => { | ||
| const buf = fs.readFileSync(xzFile); | ||
| const dest = path.join(__dirname, '../fixtures/xx.log.tmp'); | ||
| compressing.xz.uncompress(buf, dest) | ||
| .then(() => { | ||
| assert(fs.existsSync(dest)); | ||
| const raw = fs.readFileSync(sourceFile); | ||
| const out = fs.readFileSync(dest); | ||
| assert.equal(out.length, raw.length); | ||
| assert.deepEqual(out, raw); | ||
| fs.unlinkSync(dest); | ||
| done(); | ||
| }) | ||
| .catch(done); | ||
| }); | ||
|
|
||
| it('should compress/decompress utf-8 text to xz', async () => { | ||
| const buf = Buffer.from('你好\nhello xz\nWindows\r\n'); | ||
| const dest = path.join(__dirname, '../fixtures/xx.log.xz.utf8.tmp'); | ||
| await compressing.xz.compressFile(buf, dest); | ||
| assert(fs.existsSync(dest)); | ||
|
|
||
| const dest2 = path.join(__dirname, '../fixtures/xx.log.utf8.tmp'); | ||
| const xzBuf = fs.readFileSync(dest); | ||
| await compressing.xz.uncompress(xzBuf, dest2); | ||
| const outBuf = fs.readFileSync(dest2); | ||
| assert.deepEqual(outBuf.toString(), buf.toString()); | ||
|
|
||
| fs.unlinkSync(dest); | ||
| fs.unlinkSync(dest2); | ||
| }); | ||
|
|
||
| it('should compress stream to xz', done => { | ||
| const src = fs.createReadStream(sourceFile); | ||
| const dest = path.join(__dirname, '../fixtures/xx.log.xz.tmp'); | ||
| compressing.xz.compressFile(src, dest) | ||
| .then(() => { | ||
| assert(fs.existsSync(dest)); | ||
| fs.unlinkSync(dest); | ||
| done(); | ||
| }) | ||
| .catch(done); | ||
| }); | ||
|
|
||
| it('should decompress xz stream to log', done => { | ||
| const src = fs.createReadStream(xzFile); | ||
| const dest = path.join(__dirname, '../fixtures/xx.log.tmp'); | ||
| compressing.xz.uncompress(src, dest) | ||
| .then(() => { | ||
| assert(fs.existsSync(dest)); | ||
| const raw = fs.readFileSync(sourceFile); | ||
| const out = fs.readFileSync(dest); | ||
| assert.equal(out.length, raw.length); | ||
| assert.equal(out.toString(), raw.toString()); | ||
| fs.unlinkSync(dest); | ||
| done(); | ||
| }) | ||
| .catch(done); | ||
| }); | ||
| }); |
| Back | FazBrowse Home | New Git URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThe xz.UncompressStream is defined as extending WriteStream. However, its JavaScript implementation (lib/xz/uncompress_stream.js) pipes the decompressed data out of itself (decompressor.pipe(this)), making it behave as a Readable stream. To ensure type correctness and consistency with its runtime behavior, this type definition should extend ReadStream.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.