node-pkware 0.7.0 → 1.0.0-alpha.1

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.
@@ -0,0 +1,125 @@
1
+ const fs = require('fs')
2
+ const { repeat, test } = require('ramda')
3
+ const { isNumber, isString } = require('ramda-adjunct')
4
+
5
+ const isBetween = (min, max, num) => {
6
+ if (!isNumber(min) || !isNumber(max) || !isNumber(num)) {
7
+ return null
8
+ }
9
+ if (min > max) {
10
+ ;[min, max] = [max, min]
11
+ }
12
+
13
+ return num >= min && num <= max
14
+ }
15
+
16
+ const nBitsOfOnes = numberOfBits => {
17
+ if (!Number.isInteger(numberOfBits) || numberOfBits < 0) {
18
+ return null
19
+ }
20
+ return (1 << numberOfBits) - 1
21
+ }
22
+
23
+ const maskBits = (numberOfBits, number) => {
24
+ const bits = nBitsOfOnes(numberOfBits)
25
+ if (bits === null) {
26
+ return null
27
+ }
28
+ if (!Number.isInteger(number) || number < 0) {
29
+ return null
30
+ }
31
+ return number & nBitsOfOnes(numberOfBits)
32
+ }
33
+
34
+ const getLowestNBits = (numberOfBits, number) => {
35
+ return number & nBitsOfOnes(numberOfBits)
36
+ }
37
+
38
+ const isDecimalString = test(/^\d+$/)
39
+
40
+ const isFullHexString = str => {
41
+ if (isString(str)) {
42
+ return /^\s*0x[0-9a-f]+\s*$/.test(str)
43
+ } else {
44
+ return false
45
+ }
46
+ }
47
+
48
+ const toHex = (num, digits = 0, withoutPrefix = false) => {
49
+ const prefix = withoutPrefix ? '' : '0x'
50
+ if (!Number.isInteger(digits) || digits < 0) {
51
+ return null
52
+ }
53
+ if (isFullHexString(num)) {
54
+ const number = num.trim().replace(/^0x0*/, '')
55
+ return `${prefix}${number.padStart(digits, '0')}`
56
+ }
57
+ if (!Number.isInteger(num)) {
58
+ return null
59
+ }
60
+ return `${prefix}${num.toString(16).padStart(digits, '0')}`
61
+ }
62
+
63
+ const mergeSparseArrays = (a, b) => {
64
+ if (!Array.isArray(a) || !Array.isArray(b)) {
65
+ return []
66
+ }
67
+
68
+ const result = [...b, ...(b.length < a.length ? repeat(undefined, a.length - b.length) : [])]
69
+ for (let i = 0; i < a.length; i++) {
70
+ if (a[i] !== undefined) {
71
+ result[i] = a[i]
72
+ }
73
+ }
74
+ return result
75
+ }
76
+
77
+ /*
78
+ export const dumpBytes = bytes => {
79
+ const formattedBytes = Array.from(bytes)
80
+ .map(byte => toHex(byte, 2, true))
81
+ .join(' ')
82
+ return `<${formattedBytes}>`
83
+ }
84
+ */
85
+
86
+ const parseNumberString = (n, defaultValue = 0) => {
87
+ if (isDecimalString(n)) {
88
+ return parseInt(n)
89
+ } else if (isFullHexString(n)) {
90
+ return parseInt(n.replace(/^0x/, ''), 16)
91
+ } else {
92
+ return defaultValue
93
+ }
94
+ }
95
+
96
+ const getPackageVersion = async () => {
97
+ try {
98
+ const { version } = require('../../package.json')
99
+ return version
100
+ } catch (error) {
101
+ return 'unknown'
102
+ }
103
+ }
104
+
105
+ const fileExists = async filename => {
106
+ try {
107
+ await fs.promises.access(filename, fs.constants.R_OK)
108
+ return true
109
+ } catch (error) {
110
+ return false
111
+ }
112
+ }
113
+
114
+ module.exports = {
115
+ isBetween,
116
+ nBitsOfOnes,
117
+ maskBits,
118
+ getLowestNBits,
119
+ isFullHexString,
120
+ toHex,
121
+ mergeSparseArrays,
122
+ parseNumberString,
123
+ getPackageVersion,
124
+ fileExists
125
+ }
@@ -0,0 +1,190 @@
1
+ const { Transform, Writable } = require('stream')
2
+ const { promisify } = require('util')
3
+ const { isFunction } = require('ramda-adjunct')
4
+ const ExpandingBuffer = require('./ExpandingBuffer.js')
5
+
6
+ const emptyBuffer = Buffer.from([])
7
+
8
+ class QuasiTransform {
9
+ constructor(handler) {
10
+ this.handler = handler
11
+ }
12
+
13
+ handle(chunk, encoding) {
14
+ return promisify(this.handler).call(this, chunk, encoding)
15
+ }
16
+ }
17
+
18
+ const splitAt = index => {
19
+ let cntr = 0
20
+
21
+ if (!Number.isInteger(index) || index < 0) {
22
+ return () => {
23
+ return null
24
+ }
25
+ }
26
+
27
+ return chunk => {
28
+ let left
29
+ let right
30
+ let isLeftDone = true
31
+
32
+ if (!Buffer.isBuffer(chunk)) {
33
+ return null
34
+ }
35
+
36
+ if (index <= cntr) {
37
+ // index ..... cntr ..... chunk.length
38
+ left = emptyBuffer
39
+ right = chunk
40
+ } else if (index >= cntr + chunk.length) {
41
+ // cntr ..... chunk.length ..... index
42
+ left = chunk
43
+ right = emptyBuffer
44
+ isLeftDone = index === cntr + chunk.length
45
+ } else {
46
+ // cntr ..... index ..... chunk.length
47
+ left = chunk.slice(0, index - cntr)
48
+ right = chunk.slice(index - cntr)
49
+ }
50
+
51
+ cntr += chunk.length
52
+
53
+ return [left, right, isLeftDone]
54
+ }
55
+ }
56
+
57
+ const transformIdentity = () => {
58
+ return function (chunk, encoding, callback) {
59
+ callback(null, chunk)
60
+ }
61
+ }
62
+
63
+ const transformEmpty = () => {
64
+ return function (chunk, encoding, callback) {
65
+ callback(null, emptyBuffer)
66
+ }
67
+ }
68
+
69
+ const through = handler => {
70
+ return new Transform({
71
+ transform: handler
72
+ })
73
+ }
74
+
75
+ const transformSplitBy = (predicate, leftHandler, rightHandler) => {
76
+ let isFirstChunk = true
77
+ let wasLeftFlushCalled = false
78
+ const damChunkSize = 0x10000
79
+ const dam = new ExpandingBuffer()
80
+
81
+ const leftTransform = new QuasiTransform(leftHandler)
82
+ const rightTransform = new QuasiTransform(rightHandler)
83
+
84
+ return function (chunk, encoding, callback) {
85
+ const [left, right, isLeftDone] = predicate(chunk)
86
+
87
+ const _left = leftTransform.handle(left, encoding)
88
+ const _right = rightTransform.handle(right, encoding)
89
+
90
+ if (isFirstChunk) {
91
+ isFirstChunk = false
92
+ this._flush = flushCallback => {
93
+ if (!dam.isEmpty()) {
94
+ this.push(dam.read())
95
+ }
96
+
97
+ let leftFiller = Promise.resolve(emptyBuffer)
98
+ let rightFiller = Promise.resolve(emptyBuffer)
99
+
100
+ if (!wasLeftFlushCalled && isFunction(leftTransform._flush)) {
101
+ leftFiller = new Promise((resolve, reject) => {
102
+ leftTransform._flush((err, data) => {
103
+ if (err) {
104
+ reject(err)
105
+ } else {
106
+ resolve(data)
107
+ }
108
+ })
109
+ })
110
+ }
111
+
112
+ if (isFunction(rightTransform._flush)) {
113
+ rightFiller = new Promise((resolve, reject) => {
114
+ rightTransform._flush((err, data) => {
115
+ if (err) {
116
+ reject(err)
117
+ } else {
118
+ resolve(data)
119
+ }
120
+ })
121
+ })
122
+ }
123
+
124
+ Promise.all([leftFiller, rightFiller])
125
+ .then(buffers => {
126
+ flushCallback(null, Buffer.concat(buffers))
127
+ })
128
+ .catch(err => {
129
+ flushCallback(err)
130
+ })
131
+ }
132
+ }
133
+
134
+ let filler = Promise.resolve(emptyBuffer)
135
+ if (isLeftDone && !wasLeftFlushCalled && isFunction(leftTransform._flush)) {
136
+ wasLeftFlushCalled = true
137
+ filler = new Promise((resolve, reject) => {
138
+ leftTransform._flush((err, data) => {
139
+ if (err) {
140
+ reject(err)
141
+ } else {
142
+ resolve(data)
143
+ }
144
+ })
145
+ })
146
+ }
147
+
148
+ Promise.all([_left, filler, _right])
149
+ .then(buffers => {
150
+ dam.append(Buffer.concat(buffers))
151
+ if (dam.size() > damChunkSize) {
152
+ const chunks = Math.floor(dam.size() / damChunkSize)
153
+ const data = Buffer.from(dam.read(0, chunks * damChunkSize))
154
+ dam.flushStart(chunks * damChunkSize)
155
+ for (let i = 0; i < chunks - 1; i++) {
156
+ this.push(data.slice(i * damChunkSize, i * damChunkSize + damChunkSize))
157
+ }
158
+ callback(null, data.slice((chunks - 1) * damChunkSize))
159
+ } else {
160
+ callback(null, emptyBuffer)
161
+ }
162
+ })
163
+ .catch(err => {
164
+ callback(err)
165
+ })
166
+ }
167
+ }
168
+
169
+ const streamToBuffer = done => {
170
+ const buffer = new ExpandingBuffer()
171
+ return new Writable({
172
+ write(chunk, encoding, callback) {
173
+ buffer.append(chunk)
174
+ callback()
175
+ },
176
+ final(callback) {
177
+ done(buffer.getHeap())
178
+ callback()
179
+ }
180
+ })
181
+ }
182
+
183
+ module.exports = {
184
+ splitAt,
185
+ transformIdentity,
186
+ transformEmpty,
187
+ through,
188
+ transformSplitBy,
189
+ streamToBuffer
190
+ }
@@ -0,0 +1,78 @@
1
+ // const { EOL } = require('os')
2
+ // const fs = require('fs')
3
+ const assert = require('assert')
4
+ const { compare, report } = require('binary-comparator')
5
+
6
+ /*
7
+ const isPromise = promise => {
8
+ return typeof promise === 'object' && promise.constructor.name === 'Promise'
9
+ }
10
+
11
+ const toConsole = () => (chunk, encoding, callback) => {
12
+ process.stdout.write(chunk)
13
+ process.stdout.write(Buffer.from(EOL))
14
+ callback(null, chunk)
15
+ }
16
+
17
+ const readToBuffer = (fileName, chunkSizeInBytes = 1024) => {
18
+ return new Promise((resolve, reject) => {
19
+ const chunks = []
20
+ fs.createReadStream(fileName, { highWaterMark: chunkSizeInBytes })
21
+ .on('error', reject)
22
+ .on('data', chunk => {
23
+ chunks.push(chunk)
24
+ })
25
+ .on('end', function () {
26
+ resolve(Buffer.concat(chunks))
27
+ })
28
+ })
29
+ }
30
+ */
31
+
32
+ // source: https://stackoverflow.com/a/43197340/1806628
33
+ const isClass = obj => {
34
+ const isCtorClass = obj.constructor && obj.constructor.toString().substring(0, 5) === 'class'
35
+ if (obj.prototype === undefined) {
36
+ return isCtorClass
37
+ }
38
+ const isPrototypeCtorClass =
39
+ obj.prototype.constructor &&
40
+ obj.prototype.constructor.toString &&
41
+ obj.prototype.constructor.toString().substring(0, 5) === 'class'
42
+ return isCtorClass || isPrototypeCtorClass
43
+ }
44
+
45
+ // https://stackoverflow.com/a/48845122/1806628
46
+ const bufferToString = (buffer, limit = 20) => {
47
+ const ellipsisNecessary = buffer.length > limit
48
+ let hexString = buffer.slice(0, limit).toString('hex')
49
+ hexString = hexString.length > 2 ? hexString.match(/../g).join(' ') : hexString
50
+ return `<Buffer ${hexString}${ellipsisNecessary ? '...' : ''}>`
51
+ }
52
+
53
+ const buffersShouldEqual = (expected, result, offset = 0, displayAsHex = false) => {
54
+ if (!Buffer.isBuffer(expected)) {
55
+ throw new Error('expected is not a Buffer')
56
+ }
57
+
58
+ if (!Buffer.isBuffer(result)) {
59
+ throw new Error('result is not a Buffer')
60
+ }
61
+
62
+ const diff = report(expected, result, compare(expected, result, offset), displayAsHex)
63
+ assert.ok(expected.equals(result), diff)
64
+ }
65
+
66
+ const transformToABC = () => {
67
+ let cntr = 0
68
+ return function (chunk, encoding, callback) {
69
+ callback(null, Buffer.from([65 + (cntr++ % 26)]))
70
+ }
71
+ }
72
+
73
+ module.exports = {
74
+ isClass,
75
+ buffersShouldEqual,
76
+ bufferToString,
77
+ transformToABC
78
+ }