scanoss 0.25.0 → 0.26.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.
- package/CHANGELOG.md +5 -0
- package/build/main/sdk/scanner/WfpProvider/WfpCalculator/WfpCalculator.js +123 -12
- package/build/main/tsconfig.tsbuildinfo +1 -1
- package/build/module/sdk/scanner/WfpProvider/WfpCalculator/WfpCalculator.js +123 -12
- package/build/module/tsconfig.module.tsbuildinfo +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [0.26.0] (2025-10-31)
|
|
6
|
+
### Added
|
|
7
|
+
- Added fh2 opposite line ending hash calculation
|
|
8
|
+
|
|
5
9
|
## [0.25.0] (2025-10-01)
|
|
6
10
|
### Changed
|
|
7
11
|
- Replaced `/v2/cryptography/hints/range/components` by `/v2/cryptography/hints/components`
|
|
@@ -165,3 +169,4 @@ All notable changes to this project will be documented in this file. See [standa
|
|
|
165
169
|
### [0.23.0](https://github.com/scanoss/scanoss.js/compare/v0.22.0...v0.23.0) (2025-09-19)
|
|
166
170
|
### [0.24.0](https://github.com/scanoss/scanoss.js/compare/v0.23.0...v0.24.0) (2025-09-23)
|
|
167
171
|
### [0.25.0](https://github.com/scanoss/scanoss.js/compare/v0.24.0...v0.25.0) (2025-10-01)
|
|
172
|
+
### [0.26.0](https://github.com/scanoss/scanoss.js/compare/v0.25.0...v0.26.0) (2025-10-30)
|
|
@@ -270,25 +270,24 @@ function calc_hpsm(content) {
|
|
|
270
270
|
* Create a wfp_hpsm package joining wfp (with md5 line) and a hpsm.
|
|
271
271
|
*
|
|
272
272
|
* Example:
|
|
273
|
-
* wfp = file=
|
|
274
|
-
*
|
|
273
|
+
* wfp = file=33d2b65d852100b7fc5e6dae95f07bde,118,/external/inc/crc32c.h
|
|
274
|
+
* fh2=91d5edea99e9cfcdeeb55e722d3aa67f
|
|
275
|
+
* 11=b19bdbfa
|
|
275
276
|
*
|
|
276
|
-
* hpsm = hpsm=
|
|
277
|
+
* hpsm = hpsm=5ac65706ff2d
|
|
277
278
|
*
|
|
278
|
-
* wfp_hpsm = file=
|
|
279
|
-
*
|
|
280
|
-
*
|
|
279
|
+
* wfp_hpsm = file=33d2b65d852100b7fc5e6dae95f07bde,118,/external/inc/crc32c.h
|
|
280
|
+
* fh2=91d5edea99e9cfcdeeb55e722d3aa67f
|
|
281
|
+
* hpsm=5ac65706ff2d
|
|
282
|
+
* 11=b19bdbfa
|
|
281
283
|
*
|
|
282
284
|
* @param {string} wfp Complete wfp string (with md5 line)
|
|
283
285
|
* @param {string} hpsm
|
|
284
286
|
* @returns {string}
|
|
285
287
|
*/
|
|
286
288
|
function join_wfp_hpsm(wfp, hpsm) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
header += hpsm;
|
|
290
|
-
wfp = wfp.replace(/file=.*/, "")
|
|
291
|
-
return header + wfp;
|
|
289
|
+
// Replace fh2= line with fh2= line + newline + hpsm line
|
|
290
|
+
return wfp.replace(/(fh2=.*)/, '$1' + String.fromCharCode(10) + hpsm);
|
|
292
291
|
}
|
|
293
292
|
|
|
294
293
|
/**
|
|
@@ -311,9 +310,121 @@ function wfp_for_content(content, contentSource, maxSize) {
|
|
|
311
310
|
return wfp;
|
|
312
311
|
}
|
|
313
312
|
|
|
313
|
+
/**
|
|
314
|
+
* Detect line ending types in buffer contents.
|
|
315
|
+
*
|
|
316
|
+
* @param {Buffer} contents - File contents as buffer
|
|
317
|
+
* @returns {Object} Object with has_crlf, has_standalone_lf, has_standalone_cr flags
|
|
318
|
+
*/
|
|
319
|
+
function detect_line_endings(contents) {
|
|
320
|
+
let has_crlf = false;
|
|
321
|
+
let has_standalone_lf = false;
|
|
322
|
+
let has_standalone_cr = false;
|
|
323
|
+
|
|
324
|
+
for (let i = 0; i < contents.length; i++) {
|
|
325
|
+
const byte = contents[i];
|
|
326
|
+
|
|
327
|
+
// Check for CRLF (\\r\\n) // Windows (CRLF)
|
|
328
|
+
if (byte === 0x0D && i + 1 < contents.length && contents[i + 1] === 0x0A) {
|
|
329
|
+
has_crlf = true;
|
|
330
|
+
i++; // Skip the next byte since we've already checked it
|
|
331
|
+
}
|
|
332
|
+
// Check for standalone LF (\\n) // Unix (LF) Linux
|
|
333
|
+
else if (byte === 0x0A) {
|
|
334
|
+
has_standalone_lf = true;
|
|
335
|
+
}
|
|
336
|
+
// Check for standalone CR (\\r) // Unix (CR) old MacOS
|
|
337
|
+
else if (byte === 0x0D) {
|
|
338
|
+
has_standalone_cr = true;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if(has_crlf && has_standalone_lf && has_standalone_cr) {
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return { has_crlf: has_crlf, has_standalone_lf: has_standalone_lf, has_standalone_cr: has_standalone_cr };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Calculate hash for contents with opposite line endings.
|
|
351
|
+
* If the file is primarily Unix (LF), calculates Windows (CRLF) hash.
|
|
352
|
+
* If the file is primarily Windows (CRLF), calculates Unix (LF) hash.
|
|
353
|
+
*
|
|
354
|
+
* @param {Buffer} contents - File contents as buffer
|
|
355
|
+
* @returns {string|null} Hash with opposite line endings as hex string, or null if no line endings detected
|
|
356
|
+
*/
|
|
357
|
+
function calculate_opposite_line_ending_hash(contents) {
|
|
358
|
+
const line_endings = detect_line_endings(contents);
|
|
359
|
+
const has_crlf = line_endings.has_crlf;
|
|
360
|
+
const has_standalone_lf = line_endings.has_standalone_lf;
|
|
361
|
+
const has_standalone_cr = line_endings.has_standalone_cr;
|
|
362
|
+
|
|
363
|
+
if (!has_crlf && !has_standalone_lf && !has_standalone_cr) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// First pass: normalize all line endings to LF
|
|
368
|
+
let normalized = [];
|
|
369
|
+
// Optimization: if file only has LF (no CR bytes at all), skip normalization
|
|
370
|
+
if (has_standalone_lf && !has_crlf && !has_standalone_cr) {
|
|
371
|
+
// File is pure Unix (LF only) - already normalized
|
|
372
|
+
normalized = Array.from(contents);
|
|
373
|
+
} else {
|
|
374
|
+
// File has CR bytes (CRLF or standalone CR) - need to normalize
|
|
375
|
+
normalized = [];
|
|
376
|
+
for (let i = 0; i < contents.length; i++) {
|
|
377
|
+
const byte = contents[i];
|
|
378
|
+
if (byte === 0x0D) {
|
|
379
|
+
// CR
|
|
380
|
+
if (i + 1 < contents.length && contents[i + 1] === 0x0A) {
|
|
381
|
+
// CRLF -> LF
|
|
382
|
+
normalized.push(0x0A);
|
|
383
|
+
i++; // Skip the LF
|
|
384
|
+
} else {
|
|
385
|
+
// Standalone CR -> LF
|
|
386
|
+
normalized.push(0x0A);
|
|
387
|
+
}
|
|
388
|
+
} else {
|
|
389
|
+
normalized.push(byte);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
let opposite_contents;
|
|
395
|
+
|
|
396
|
+
// Determine the dominant line ending type
|
|
397
|
+
if (has_crlf && !has_standalone_lf && !has_standalone_cr) {
|
|
398
|
+
// File is Windows (CRLF) - produce Unix (LF) hash
|
|
399
|
+
opposite_contents = Buffer.from(normalized);
|
|
400
|
+
} else {
|
|
401
|
+
// File is Unix (LF/CR) or mixed - produce Windows (CRLF) hash
|
|
402
|
+
const with_crlf = [];
|
|
403
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
404
|
+
if (normalized[i] === 0x0A) {
|
|
405
|
+
// LF -> CRLF
|
|
406
|
+
with_crlf.push(0x0D);
|
|
407
|
+
with_crlf.push(0x0A);
|
|
408
|
+
} else {
|
|
409
|
+
with_crlf.push(normalized[i]);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
opposite_contents = Buffer.from(with_crlf);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return crypto.createHash('md5').update(opposite_contents).digest('hex');
|
|
416
|
+
}
|
|
417
|
+
|
|
314
418
|
function wfp_only_md5(contents, contentSource) {
|
|
315
419
|
const file_md5 = crypto.createHash('md5').update(contents).digest('hex');
|
|
316
420
|
let wfp = 'file=' + String(file_md5) + ',' + String(contents.length) + ',' + String(contentSource)+ String.fromCharCode(10);
|
|
421
|
+
|
|
422
|
+
// Calculate and add opposite line ending hash if applicable
|
|
423
|
+
const opposite_hash = calculate_opposite_line_ending_hash(contents);
|
|
424
|
+
if (opposite_hash !== null) {
|
|
425
|
+
wfp += 'fh2=' + String(opposite_hash) + String.fromCharCode(10);
|
|
426
|
+
}
|
|
427
|
+
|
|
317
428
|
return wfp;
|
|
318
429
|
}
|
|
319
430
|
|
|
@@ -513,4 +624,4 @@ class WfpCalculator extends WfpProvider_1.WfpProvider {
|
|
|
513
624
|
}
|
|
514
625
|
}
|
|
515
626
|
exports.WfpCalculator = WfpCalculator;
|
|
516
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
627
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2ZwQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9zZGsvc2Nhbm5lci9XZnBQcm92aWRlci9XZnBDYWxjdWxhdG9yL1dmcENhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNENBQW9CO0FBQ3BCLG1EQUF3QztBQUV4QyxpRUFBOEQ7QUFDOUQsaURBQThDO0FBQzlDLHFEQUFnRjtBQUVoRiw4REFBMkQ7QUFDM0QsZ0RBQWdFO0FBRWhFLE1BQU0sWUFBWSxHQUFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0NBMGVwQixDQUFDO0FBRUYsTUFBYSxhQUFjLFNBQVEseUJBQVc7SUFPNUMsWUFBWSxVQUFVLEdBQUcsSUFBSSx1QkFBVSxFQUFFO1FBQ3ZDLEtBQUssRUFBRSxDQUFDO1FBQ1IsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFV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
|