strc 1.0.0-a → 1.1.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/index.d.ts +11 -0
- package/index.js +288 -34
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -24,6 +24,17 @@ SOFTWARE.
|
|
|
24
24
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
+
/*
|
|
28
|
+
_______________
|
|
29
|
+
__ / / __/ __/ ___/
|
|
30
|
+
/ // /\ \_\ \/ /__
|
|
31
|
+
\___/___/___/\___/
|
|
32
|
+
|
|
33
|
+
JavaScript String Compressor
|
|
34
|
+
https://jssc.js.org/
|
|
35
|
+
|
|
36
|
+
*/
|
|
37
|
+
|
|
27
38
|
/**
|
|
28
39
|
* JavaScript String Compressor - compress function
|
|
29
40
|
* @param str - Input string to compress
|
package/index.js
CHANGED
|
@@ -24,6 +24,17 @@ SOFTWARE.
|
|
|
24
24
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
+
/*
|
|
28
|
+
_______________
|
|
29
|
+
__ / / __/ __/ ___/
|
|
30
|
+
/ // /\ \_\ \/ /__
|
|
31
|
+
\___/___/___/\___/
|
|
32
|
+
|
|
33
|
+
JavaScript String Compressor
|
|
34
|
+
https://jssc.js.org/
|
|
35
|
+
|
|
36
|
+
*/
|
|
37
|
+
|
|
27
38
|
(function (root, factory) {
|
|
28
39
|
if (typeof define === 'function' && define.amd) {
|
|
29
40
|
define([], factory); /* amd */
|
|
@@ -51,7 +62,7 @@ SOFTWARE.
|
|
|
51
62
|
maxCharCode = Math.max(maxCharCode, code);
|
|
52
63
|
min = Math.min(min, code.toString().length);
|
|
53
64
|
});
|
|
54
|
-
return {max, output, maxCharCode, min}
|
|
65
|
+
return {max, output, maxCharCode, min};
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
function codesString(cds) {
|
|
@@ -406,7 +417,7 @@ SOFTWARE.
|
|
|
406
417
|
function cryptCharCode(
|
|
407
418
|
code, get = false,
|
|
408
419
|
repeatBefore = false, repeatAfter = false,
|
|
409
|
-
beginId = -1,
|
|
420
|
+
beginId = -1, code2 = 0, sequences = false
|
|
410
421
|
) {
|
|
411
422
|
if (get) {
|
|
412
423
|
const codeBin = decToBin(code, 16);
|
|
@@ -418,12 +429,173 @@ SOFTWARE.
|
|
|
418
429
|
repeatBefore: codeSet[0] === '1',
|
|
419
430
|
repeatAfter: codeSet[1] === '1',
|
|
420
431
|
beginId: codeSet[2] === '1' ? begid : -1,
|
|
432
|
+
code2: binToDec(codeBin.slice(0,4)),
|
|
433
|
+
sequences: codeBin.slice(4,5) === '1',
|
|
434
|
+
code3: codeSet[2] === '0' ? begid : -1, /* currently unused */
|
|
435
|
+
bin: codeBin,
|
|
421
436
|
}
|
|
422
437
|
} else {
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
|
|
438
|
+
const sixteenBits = /* 16-bit Data/Header character */
|
|
439
|
+
|
|
440
|
+
decToBin(code2, 4) + /* Bits 0-3 : code2 */
|
|
441
|
+
(sequences ? '1' : '0') + /* Bit 4 : sequences? */
|
|
442
|
+
(beginId >= 0 ? decToBin(beginId, 3) : '000') + /* Bits 5-7 : beginID | code3 */
|
|
443
|
+
(repeatBefore ? '1' : '0') + /* Bit 8 : input RLE? */
|
|
444
|
+
(repeatAfter ? '1' : '0') + /* Bit 9 : output RLE? */
|
|
445
|
+
(beginId >= 0 ? '1' : '0') + /* Bit 10 : beginID? */
|
|
446
|
+
decToBin(code, 5); /* Bits 11-15 : code1 */
|
|
447
|
+
|
|
448
|
+
return binToDec(sixteenBits);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const SEQUENCE_MARKER = '\uDBFF'; /* Private Use Area */
|
|
453
|
+
|
|
454
|
+
function findSequences(str, minLength = 2, minCount = 3) {
|
|
455
|
+
const repeats = [];
|
|
456
|
+
const n = str.length;
|
|
457
|
+
|
|
458
|
+
for (let i = 0; i < n - minLength * minCount + 1; i++) {
|
|
459
|
+
for (let len = 2; len <= Math.min(30, Math.floor((n - i) / minCount)); len++) {
|
|
460
|
+
const pattern = str.substr(i, len);
|
|
461
|
+
if (pattern.includes(SEQUENCE_MARKER)) continue;
|
|
462
|
+
|
|
463
|
+
let count = 1;
|
|
464
|
+
for (let j = i + len; j <= n - len; j += len) {
|
|
465
|
+
if (str.substr(j, len) === pattern) {
|
|
466
|
+
count++;
|
|
467
|
+
} else {
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (count >= minCount) {
|
|
473
|
+
const end = i + len * count;
|
|
474
|
+
let overlaps = false;
|
|
475
|
+
for (const r of repeats) {
|
|
476
|
+
if (i < r.end && end > r.start) {
|
|
477
|
+
overlaps = true;
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (!overlaps) {
|
|
483
|
+
repeats.push({
|
|
484
|
+
start: i,
|
|
485
|
+
end: end,
|
|
486
|
+
length: len,
|
|
487
|
+
pattern: pattern,
|
|
488
|
+
count: count,
|
|
489
|
+
saved: (len * count) - (len + 3)
|
|
490
|
+
});
|
|
491
|
+
i = end - 1;
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
426
496
|
}
|
|
497
|
+
|
|
498
|
+
return repeats.sort((a, b) => b.saved - a.saved);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function compressSequences(str) {
|
|
502
|
+
if (str.length < 20) return {compressed: str, sequences: false};
|
|
503
|
+
|
|
504
|
+
if (str.includes(SEQUENCE_MARKER)) {
|
|
505
|
+
return {compressed: str, sequences: false};
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
const repeats = findSequences(str, 2, 3);
|
|
509
|
+
if (repeats.length === 0) return {compressed: str, sequences: false};
|
|
510
|
+
|
|
511
|
+
const selected = [];
|
|
512
|
+
let covered = new Array(str.length).fill(false);
|
|
513
|
+
|
|
514
|
+
for (const repeat of repeats) {
|
|
515
|
+
let canUse = true;
|
|
516
|
+
for (let i = repeat.start; i < repeat.end; i++) {
|
|
517
|
+
if (covered[i]) {
|
|
518
|
+
canUse = false;
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
if (canUse && repeat.saved > 0) {
|
|
524
|
+
selected.push(repeat);
|
|
525
|
+
for (let i = repeat.start; i < repeat.end; i++) {
|
|
526
|
+
covered[i] = true;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (selected.length === 0) return {compressed: str, sequences: false};
|
|
532
|
+
|
|
533
|
+
let result = '';
|
|
534
|
+
let pos = 0;
|
|
535
|
+
|
|
536
|
+
for (const repeat of selected) {
|
|
537
|
+
if (pos < repeat.start) {
|
|
538
|
+
result += str.slice(pos, repeat.start);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/* sequence encoding: [marker][length][count][pattern] */
|
|
542
|
+
const lengthChar = String.fromCharCode(Math.min(repeat.length, 30) + 32);
|
|
543
|
+
const countChar = String.fromCharCode(Math.min(repeat.count, 65535) + 32);
|
|
544
|
+
result += SEQUENCE_MARKER + lengthChar + countChar + repeat.pattern;
|
|
545
|
+
|
|
546
|
+
pos = repeat.end;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (pos < str.length) {
|
|
550
|
+
result += str.slice(pos);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/* check if it's worth it */
|
|
554
|
+
if (result.length < str.length * 0.9) { /* at least 10% */
|
|
555
|
+
return {compressed: result, sequences: true};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return {compressed: str, sequences: false};
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function decompressSequences(str) {
|
|
562
|
+
let result = '';
|
|
563
|
+
let i = 0;
|
|
564
|
+
|
|
565
|
+
while (i < str.length) {
|
|
566
|
+
if (str.charCodeAt(i) === 0xDBFF) {
|
|
567
|
+
i++;
|
|
568
|
+
|
|
569
|
+
if (i + 2 >= str.length) {
|
|
570
|
+
result += SEQUENCE_MARKER;
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const length = str.charCodeAt(i) - 32;
|
|
575
|
+
const count = str.charCodeAt(i + 1) - 32;
|
|
576
|
+
i += 2;
|
|
577
|
+
|
|
578
|
+
if (i + length > str.length) {
|
|
579
|
+
result += SEQUENCE_MARKER +
|
|
580
|
+
String.fromCharCode(length + 32) +
|
|
581
|
+
String.fromCharCode(count + 32) +
|
|
582
|
+
str.slice(i);
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const pattern = str.substr(i, length);
|
|
587
|
+
i += length;
|
|
588
|
+
|
|
589
|
+
for (let j = 0; j < count; j++) {
|
|
590
|
+
result += pattern;
|
|
591
|
+
}
|
|
592
|
+
} else {
|
|
593
|
+
result += str.charAt(i);
|
|
594
|
+
i++;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return result;
|
|
427
599
|
}
|
|
428
600
|
|
|
429
601
|
/**
|
|
@@ -455,18 +627,27 @@ SOFTWARE.
|
|
|
455
627
|
const strdata = stringCodes(str);
|
|
456
628
|
const ascii = strdata.maxCharCode < 256;
|
|
457
629
|
let repeatAfter = false;
|
|
458
|
-
|
|
459
|
-
|
|
630
|
+
let sequences = false;
|
|
631
|
+
|
|
632
|
+
function processCompression(output) {
|
|
633
|
+
const hasDigits = /\d/.test(output);
|
|
634
|
+
if (!hasDigits) {
|
|
460
635
|
repeatAfter = true;
|
|
636
|
+
output = repeatChars(output);
|
|
461
637
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
638
|
+
|
|
639
|
+
if (true) {
|
|
640
|
+
const compressed = compressSequences(output);
|
|
641
|
+
if (compressed.sequences) {
|
|
642
|
+
sequences = true;
|
|
643
|
+
return compressed.compressed;
|
|
644
|
+
}
|
|
468
645
|
}
|
|
646
|
+
|
|
647
|
+
return output;
|
|
469
648
|
}
|
|
649
|
+
|
|
650
|
+
const UniqueCodes = [...new Set(strdata.output)];
|
|
470
651
|
if (/^\d+$/.test(str)) { /* Numbers */
|
|
471
652
|
/* Up to 8:1 compression ratio */
|
|
472
653
|
const convertNums = {
|
|
@@ -500,10 +681,10 @@ SOFTWARE.
|
|
|
500
681
|
for (const character of chunkArray(binOut, 4)) {
|
|
501
682
|
output += String.fromCharCode(binToDec(binPadStart(character.join(''))));
|
|
502
683
|
}
|
|
503
|
-
|
|
504
|
-
return charCode(cryptCharCode(3, false, false, repeatAfter, -1))+
|
|
684
|
+
output = processCompression(output);
|
|
685
|
+
return charCode(cryptCharCode(3, false, false, repeatAfter, -1, 0, sequences)) + output;
|
|
686
|
+
|
|
505
687
|
} else if (strdata.max === 2 && strdata.min === 2) {
|
|
506
|
-
/* Up to 3:1 compression ratio */
|
|
507
688
|
let chars = strdata.output;
|
|
508
689
|
let output = '';
|
|
509
690
|
function addChar(codee) {
|
|
@@ -536,8 +717,9 @@ SOFTWARE.
|
|
|
536
717
|
}
|
|
537
718
|
}
|
|
538
719
|
}
|
|
539
|
-
|
|
540
|
-
return charCode(cryptCharCode(1, false, repeatBefore, repeatAfter, beginId))+
|
|
720
|
+
output = processCompression(output);
|
|
721
|
+
return charCode(cryptCharCode(1, false, repeatBefore, repeatAfter, beginId, 0, sequences)) + output;
|
|
722
|
+
|
|
541
723
|
} else if (ascii) {
|
|
542
724
|
/* Up to 2:1 compression ratio */
|
|
543
725
|
/*
|
|
@@ -567,21 +749,24 @@ SOFTWARE.
|
|
|
567
749
|
for (const char of twoChars) {
|
|
568
750
|
output += String.fromCharCode(binToDec(char));
|
|
569
751
|
}
|
|
570
|
-
|
|
571
|
-
return charCode(cryptCharCode(2, false, repeatBefore, repeatAfter, beginId))+
|
|
752
|
+
output = processCompression(output);
|
|
753
|
+
return charCode(cryptCharCode(2, false, repeatBefore, repeatAfter, beginId, 0, sequences)) + output;
|
|
754
|
+
|
|
572
755
|
} else {
|
|
573
756
|
const characterEncodings = new _JSSC.use();
|
|
574
757
|
const stringArray = str.split('');
|
|
575
758
|
let useCharacterEncoding;
|
|
576
759
|
let charEncodingID = NaN;
|
|
760
|
+
|
|
577
761
|
for (const [characterEncodingName, characterEncoding] of Object.entries(characterEncodings)) {
|
|
578
762
|
const table = characterEncoding();
|
|
579
|
-
table.length= 256;
|
|
580
|
-
const arrayy= Array.from(table);
|
|
763
|
+
table.length = 256;
|
|
764
|
+
const arrayy = Array.from(table);
|
|
581
765
|
let usethisone = true;
|
|
582
766
|
for (const character of stringArray) {
|
|
583
767
|
if (!arrayy.includes(character)) {
|
|
584
768
|
usethisone = false;
|
|
769
|
+
break;
|
|
585
770
|
}
|
|
586
771
|
}
|
|
587
772
|
if (usethisone) {
|
|
@@ -590,6 +775,7 @@ SOFTWARE.
|
|
|
590
775
|
break;
|
|
591
776
|
}
|
|
592
777
|
}
|
|
778
|
+
|
|
593
779
|
if (useCharacterEncoding) {
|
|
594
780
|
const reverseCharacterEncoding = {};
|
|
595
781
|
for (const [charCode, character] of Object.entries(useCharacterEncoding)) {
|
|
@@ -608,13 +794,47 @@ SOFTWARE.
|
|
|
608
794
|
outputStr += String.fromCharCode(binToDec(characterCode))
|
|
609
795
|
}
|
|
610
796
|
/* Up to 2:1 compression ratio */
|
|
611
|
-
|
|
612
|
-
return charCode(cryptCharCode(charEncodingID + 5, false, repeatBefore, repeatAfter, beginId))+
|
|
797
|
+
outputStr = processCompression(outputStr);
|
|
798
|
+
return charCode(cryptCharCode(charEncodingID + 5, false, repeatBefore, repeatAfter, beginId, 0, sequences)) + outputStr;
|
|
799
|
+
|
|
800
|
+
} else if (UniqueCodes.length < 16) {
|
|
801
|
+
/* Up to 4:1 compression ratio */
|
|
802
|
+
const chars = UniqueCodes;
|
|
803
|
+
let output = '';
|
|
804
|
+
for (const char of chars) {
|
|
805
|
+
output += String.fromCharCode(char);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
let char_ = [];
|
|
809
|
+
for (const charCode of strdata.output) {
|
|
810
|
+
const index = UniqueCodes.indexOf(charCode);
|
|
811
|
+
|
|
812
|
+
if (char_.length === 4) {
|
|
813
|
+
let outchar = '';
|
|
814
|
+
for (const index of char_) {
|
|
815
|
+
outchar += decToBin(index, 4);
|
|
816
|
+
}
|
|
817
|
+
output += String.fromCharCode(binToDec(outchar));
|
|
818
|
+
char_ = [];
|
|
819
|
+
}
|
|
820
|
+
char_.push(index);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (char_.length > 0) {
|
|
824
|
+
let outchar = '';
|
|
825
|
+
for (const index of char_) {
|
|
826
|
+
outchar += decToBin(index, 4);
|
|
827
|
+
}
|
|
828
|
+
output += String.fromCharCode(binToDec(outchar.padStart(16, '1')));
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
output = processCompression(output);
|
|
832
|
+
return charCode(cryptCharCode(4, false, repeatBefore, repeatAfter, beginId, UniqueCodes.length, sequences)) + output;
|
|
613
833
|
}
|
|
614
834
|
|
|
615
835
|
/* 1:1 compression ratio (no compression) */
|
|
616
|
-
|
|
617
|
-
return charCode(cryptCharCode(0, false, repeatBefore, repeatAfter, beginId))+
|
|
836
|
+
let output = processCompression(str);
|
|
837
|
+
return charCode(cryptCharCode(0, false, repeatBefore, repeatAfter, beginId, 0, sequences)) + output;
|
|
618
838
|
}
|
|
619
839
|
}
|
|
620
840
|
|
|
@@ -654,29 +874,43 @@ SOFTWARE.
|
|
|
654
874
|
*/
|
|
655
875
|
function decompress(str) {
|
|
656
876
|
if (typeof str != 'string') throw new Error('Invalid input.');
|
|
657
|
-
const strcodes= cryptCharCode(str.charCodeAt(0) - 32, true);
|
|
877
|
+
const strcodes = cryptCharCode(str.charCodeAt(0) - 32, true);
|
|
658
878
|
const strcode = strcodes.code;
|
|
879
|
+
|
|
659
880
|
function repeatChars(txt) {
|
|
660
881
|
return txt.replace(/(\D)(\d+)/g, (_, g1, g2) => g1.repeat(g2));
|
|
661
882
|
}
|
|
662
|
-
|
|
883
|
+
|
|
884
|
+
/* sequences */
|
|
885
|
+
let realstr = str.slice(1);
|
|
886
|
+
if (strcodes.sequences) {
|
|
887
|
+
realstr = decompressSequences(realstr);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/* RLE */
|
|
891
|
+
if (strcodes.repeatAfter) {
|
|
892
|
+
realstr = repeatChars(realstr);
|
|
893
|
+
}
|
|
894
|
+
|
|
663
895
|
function begin(out) {
|
|
664
896
|
if (strcodes.beginId >= 0) {
|
|
665
897
|
return _JSSC._begin[strcodes.beginId] + out;
|
|
666
|
-
} else return out
|
|
898
|
+
} else return out;
|
|
667
899
|
}
|
|
900
|
+
|
|
668
901
|
function processOutput(out) {
|
|
669
902
|
if (strcodes.repeatBefore) {
|
|
670
903
|
return repeatChars(begin(out));
|
|
671
904
|
} else return begin(out);
|
|
672
905
|
}
|
|
906
|
+
|
|
673
907
|
let output = '';
|
|
674
908
|
switch (strcode) {
|
|
675
909
|
case 0:
|
|
676
910
|
return processOutput(realstr);
|
|
677
911
|
case 1:
|
|
678
912
|
function addChar(cde) {
|
|
679
|
-
output += String.fromCharCode(cde)
|
|
913
|
+
output += String.fromCharCode(cde);
|
|
680
914
|
}
|
|
681
915
|
for (const char of realstr.split('')) {
|
|
682
916
|
const charcde = String(char.charCodeAt(0));
|
|
@@ -717,14 +951,34 @@ SOFTWARE.
|
|
|
717
951
|
}
|
|
718
952
|
}
|
|
719
953
|
return processOutput(output);
|
|
954
|
+
case 4:
|
|
955
|
+
const chars = [];
|
|
956
|
+
for (const char of realstr.slice(0, strcodes.code2).split('')) {
|
|
957
|
+
chars.push(char);
|
|
958
|
+
}
|
|
959
|
+
for (const char of realstr.slice(strcodes.code2).split('')) {
|
|
960
|
+
const binCodes = stringChunks(decToBin(char.charCodeAt(0), 16), 4);
|
|
961
|
+
for (const binCode of binCodes) {
|
|
962
|
+
if (binCode != '1111') {
|
|
963
|
+
const numm = binToDec(binCode);
|
|
964
|
+
output += chars[numm];
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return processOutput(output);
|
|
720
969
|
default:
|
|
721
|
-
const
|
|
722
|
-
|
|
970
|
+
const decoded = characterEncodings(strcode, realstr);
|
|
971
|
+
if (decoded) {
|
|
972
|
+
return processOutput(decoded);
|
|
973
|
+
}
|
|
974
|
+
throw new Error('Invalid compressed string');
|
|
723
975
|
}
|
|
724
976
|
}
|
|
725
977
|
|
|
726
|
-
return {
|
|
727
|
-
|
|
978
|
+
return {
|
|
979
|
+
compress,
|
|
980
|
+
decompress,
|
|
981
|
+
get [Symbol.toStringTag]() {
|
|
728
982
|
return 'JSSC';
|
|
729
983
|
}
|
|
730
984
|
};
|