@cj-tech-master/excelts 6.1.1 → 6.1.2

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @cj-tech-master/excelts v6.1.1
2
+ * @cj-tech-master/excelts v6.1.2
3
3
  * TypeScript Excel Workbook Manager - Read and Write xlsx and csv Files.
4
4
  * (c) 2026 cjnoname
5
5
  * Released under the MIT License
@@ -18865,11 +18865,27 @@ var ExcelTS = (function(exports) {
18865
18865
  }
18866
18866
  return output.subarray(0, outPos);
18867
18867
  }
18868
+ const HASH_SIZE = 32768;
18869
+ const HASH_MASK = HASH_SIZE - 1;
18870
+ const MAX_CHAIN_LEN = 64;
18871
+ const MIN_MATCH = 3;
18872
+ const MAX_MATCH = 258;
18873
+ const MAX_DIST = 32768;
18868
18874
  /**
18869
- * Compress data using DEFLATE with fixed Huffman codes
18875
+ * Hash function for 3-byte sequences.
18876
+ * Uses a multiplicative hash for better distribution than the naive
18877
+ * shift-or approach. The constant 0x1e35a7bd is chosen for good avalanche
18878
+ * properties in the lower bits.
18879
+ */
18880
+ function hash3(a, b, c) {
18881
+ return (a << 16 | b << 8 | c) * 506832829 >>> 17 & HASH_MASK;
18882
+ }
18883
+ /**
18884
+ * Compress data using DEFLATE with fixed Huffman codes.
18870
18885
  *
18871
- * This provides real compression using LZ77 + fixed Huffman codes.
18872
- * Not as efficient as full DEFLATE but much better than STORE mode.
18886
+ * Uses LZ77 with hash chains and lazy matching for significantly better
18887
+ * compression than a single-entry hash table. The algorithm is modelled
18888
+ * after zlib's "fast" and "slow" deflate strategies.
18873
18889
  *
18874
18890
  * @param data - Data to compress
18875
18891
  * @returns Compressed data in deflate-raw format
@@ -18880,35 +18896,75 @@ var ExcelTS = (function(exports) {
18880
18896
  const output = new BitWriter();
18881
18897
  output.writeBits(1, 1);
18882
18898
  output.writeBits(1, 2);
18883
- const hashTable = /* @__PURE__ */ new Map();
18899
+ const head = new Int32Array(HASH_SIZE);
18900
+ const prev = new Int32Array(MAX_DIST);
18884
18901
  let pos = 0;
18902
+ let prevMatchLen = 0;
18903
+ let prevMatchDist = 0;
18904
+ let prevLiteral = 0;
18905
+ let hasPrevMatch = false;
18885
18906
  while (pos < data.length) {
18886
18907
  let bestLen = 0;
18887
18908
  let bestDist = 0;
18888
18909
  if (pos + 2 < data.length) {
18889
- const hash = data[pos] << 16 | data[pos + 1] << 8 | data[pos + 2];
18890
- const matchPos = hashTable.get(hash);
18891
- if (matchPos !== void 0 && pos - matchPos <= 32768) {
18892
- const dist = pos - matchPos;
18910
+ const h = hash3(data[pos], data[pos + 1], data[pos + 2]);
18911
+ let chainLen = MAX_CHAIN_LEN;
18912
+ let matchHead = head[h];
18913
+ while (matchHead > 0 && chainLen-- > 0) {
18914
+ const mPos = matchHead - 1;
18915
+ const dist = pos - mPos;
18916
+ if (dist > MAX_DIST || dist <= 0) break;
18917
+ if (bestLen >= MIN_MATCH && data[mPos + bestLen] !== data[pos + bestLen]) {
18918
+ matchHead = prev[mPos & MAX_DIST - 1];
18919
+ continue;
18920
+ }
18893
18921
  let len = 0;
18894
- const maxLen = Math.min(258, data.length - pos);
18895
- while (len < maxLen && data[matchPos + len] === data[pos + len]) len++;
18896
- if (len >= 3) {
18922
+ const maxLen = Math.min(MAX_MATCH, data.length - pos);
18923
+ while (len < maxLen && data[mPos + len] === data[pos + len]) len++;
18924
+ if (len > bestLen) {
18897
18925
  bestLen = len;
18898
18926
  bestDist = dist;
18927
+ if (len >= MAX_MATCH) break;
18899
18928
  }
18929
+ matchHead = prev[mPos & MAX_DIST - 1];
18900
18930
  }
18901
- hashTable.set(hash, pos);
18931
+ prev[pos & MAX_DIST - 1] = head[h];
18932
+ head[h] = pos + 1;
18902
18933
  }
18903
- if (bestLen >= 3) {
18904
- writeLengthCode(output, bestLen);
18905
- writeDistanceCode(output, bestDist);
18906
- pos += bestLen;
18934
+ if (hasPrevMatch) if (bestLen > prevMatchLen) {
18935
+ writeLiteralCode(output, prevLiteral);
18936
+ prevMatchLen = bestLen;
18937
+ prevMatchDist = bestDist;
18938
+ prevLiteral = data[pos];
18939
+ pos++;
18940
+ } else {
18941
+ writeLengthCode(output, prevMatchLen);
18942
+ writeDistanceCode(output, prevMatchDist);
18943
+ const matchEnd = pos - 1 + prevMatchLen;
18944
+ for (let i = pos; i < matchEnd && i + 2 < data.length; i++) {
18945
+ const h = hash3(data[i], data[i + 1], data[i + 2]);
18946
+ prev[i & MAX_DIST - 1] = head[h];
18947
+ head[h] = i + 1;
18948
+ }
18949
+ pos = matchEnd;
18950
+ hasPrevMatch = false;
18951
+ prevMatchLen = 0;
18952
+ }
18953
+ else if (bestLen >= MIN_MATCH) {
18954
+ hasPrevMatch = true;
18955
+ prevMatchLen = bestLen;
18956
+ prevMatchDist = bestDist;
18957
+ prevLiteral = data[pos];
18958
+ pos++;
18907
18959
  } else {
18908
18960
  writeLiteralCode(output, data[pos]);
18909
18961
  pos++;
18910
18962
  }
18911
18963
  }
18964
+ if (hasPrevMatch) {
18965
+ writeLengthCode(output, prevMatchLen);
18966
+ writeDistanceCode(output, prevMatchDist);
18967
+ }
18912
18968
  writeLiteralCode(output, 256);
18913
18969
  return output.finish();
18914
18970
  }
@@ -19066,7 +19122,10 @@ var ExcelTS = (function(exports) {
19066
19122
  * maintains state across multiple `write()` calls:
19067
19123
  *
19068
19124
  * - **LZ77 sliding window**: back-references can span across chunks.
19069
- * - **Hash table**: match positions persist across chunks.
19125
+ * - **Hash chains**: match positions persist across chunks with typed-array
19126
+ * hash tables for fast lookup.
19127
+ * - **Lazy matching**: each match is compared with the next position's match
19128
+ * to pick the longer one.
19070
19129
  * - **Bit writer**: bit position is preserved, so consecutive blocks form
19071
19130
  * a single valid DEFLATE bit-stream without alignment issues.
19072
19131
  *
@@ -19080,10 +19139,15 @@ var ExcelTS = (function(exports) {
19080
19139
  var SyncDeflater = class {
19081
19140
  constructor() {
19082
19141
  this._output = new BitWriter();
19083
- this._hashTable = /* @__PURE__ */ new Map();
19142
+ this._head = new Int32Array(HASH_SIZE);
19143
+ this._prev = new Int32Array(MAX_DIST);
19084
19144
  this._window = new Uint8Array(WINDOW_SIZE);
19085
19145
  this._windowLen = 0;
19086
19146
  this._totalIn = 0;
19147
+ this._hasPrevMatch = false;
19148
+ this._prevMatchLen = 0;
19149
+ this._prevMatchDist = 0;
19150
+ this._prevLiteral = 0;
19087
19151
  }
19088
19152
  /**
19089
19153
  * Compress a chunk and return the compressed bytes produced so far.
@@ -19096,50 +19160,119 @@ var ExcelTS = (function(exports) {
19096
19160
  out.writeBits(1, 2);
19097
19161
  const window = this._window;
19098
19162
  let wLen = this._windowLen;
19099
- const hashTable = this._hashTable;
19163
+ const head = this._head;
19164
+ const prevArr = this._prev;
19100
19165
  const totalIn = this._totalIn;
19101
- for (let pos = 0; pos < data.length;) {
19166
+ let hasPrevMatch = this._hasPrevMatch;
19167
+ let prevMatchLen = this._prevMatchLen;
19168
+ let prevMatchDist = this._prevMatchDist;
19169
+ let prevLiteral = this._prevLiteral;
19170
+ /**
19171
+ * Insert a global position into the hash chain and the sliding window.
19172
+ */
19173
+ const insertHash = (localPos) => {
19174
+ if (localPos + 2 >= data.length) return;
19175
+ const h = hash3(data[localPos], data[localPos + 1], data[localPos + 2]);
19176
+ const globalPos = totalIn + localPos;
19177
+ prevArr[globalPos & MAX_DIST - 1] = head[h];
19178
+ head[h] = globalPos + 1;
19179
+ };
19180
+ const insertWindow = (localPos, count) => {
19181
+ for (let i = 0; i < count; i++) window[wLen + i & WINDOW_SIZE - 1] = data[localPos + i];
19182
+ wLen += count;
19183
+ };
19184
+ let pos = 0;
19185
+ for (; pos < data.length;) {
19102
19186
  let bestLen = 0;
19103
19187
  let bestDist = 0;
19104
19188
  if (pos + 2 < data.length) {
19105
- const h = data[pos] << 16 | data[pos + 1] << 8 | data[pos + 2];
19106
- const matchGlobalPos = hashTable.get(h);
19107
- if (matchGlobalPos !== void 0) {
19108
- const dist = totalIn + pos - matchGlobalPos;
19109
- if (dist > 0 && dist <= WINDOW_SIZE) {
19110
- const wStart = ((wLen - dist) % WINDOW_SIZE + WINDOW_SIZE) % WINDOW_SIZE;
19111
- const maxLen = Math.min(258, data.length - pos);
19112
- let len = 0;
19113
- while (len < maxLen) {
19114
- if (window[(wStart + len) % WINDOW_SIZE] !== data[pos + len]) break;
19115
- len++;
19116
- }
19117
- if (len >= 3) {
19118
- bestLen = len;
19119
- bestDist = dist;
19189
+ const h = hash3(data[pos], data[pos + 1], data[pos + 2]);
19190
+ const globalPos = totalIn + pos;
19191
+ let chainLen = MAX_CHAIN_LEN;
19192
+ let matchHead = head[h];
19193
+ while (matchHead > 0 && chainLen-- > 0) {
19194
+ const mGlobalPos = matchHead - 1;
19195
+ const dist = globalPos - mGlobalPos;
19196
+ if (dist > MAX_DIST || dist <= 0) break;
19197
+ const maxLen = Math.min(MAX_MATCH, data.length - pos);
19198
+ let len = 0;
19199
+ if (bestLen >= MIN_MATCH) {
19200
+ const checkOffset = mGlobalPos + bestLen;
19201
+ let checkByte;
19202
+ const checkLocal = checkOffset - totalIn;
19203
+ if (checkLocal >= 0 && checkLocal < data.length) checkByte = data[checkLocal];
19204
+ else checkByte = window[checkOffset & WINDOW_SIZE - 1];
19205
+ if (checkByte !== data[pos + bestLen]) {
19206
+ matchHead = prevArr[mGlobalPos & MAX_DIST - 1];
19207
+ continue;
19120
19208
  }
19121
19209
  }
19210
+ while (len < maxLen) {
19211
+ const matchOffset = mGlobalPos + len;
19212
+ let matchByte;
19213
+ const matchLocal = matchOffset - totalIn;
19214
+ if (matchLocal >= 0 && matchLocal < data.length) matchByte = data[matchLocal];
19215
+ else matchByte = window[matchOffset & WINDOW_SIZE - 1];
19216
+ if (matchByte !== data[pos + len]) break;
19217
+ len++;
19218
+ }
19219
+ if (len > bestLen) {
19220
+ bestLen = len;
19221
+ bestDist = dist;
19222
+ if (len >= MAX_MATCH) break;
19223
+ }
19224
+ matchHead = prevArr[mGlobalPos & MAX_DIST - 1];
19122
19225
  }
19123
- hashTable.set(h, totalIn + pos);
19124
- }
19125
- if (bestLen >= 3) {
19126
- writeLengthCode(out, bestLen);
19127
- writeDistanceCode(out, bestDist);
19128
- for (let i = 0; i < bestLen; i++) {
19129
- window[wLen % WINDOW_SIZE] = data[pos + i];
19130
- wLen++;
19131
- }
19132
- pos += bestLen;
19226
+ prevArr[globalPos & MAX_DIST - 1] = head[h];
19227
+ head[h] = globalPos + 1;
19228
+ }
19229
+ if (hasPrevMatch) if (bestLen > prevMatchLen) {
19230
+ writeLiteralCode(out, prevLiteral);
19231
+ prevMatchLen = bestLen;
19232
+ prevMatchDist = bestDist;
19233
+ prevLiteral = data[pos];
19234
+ insertWindow(pos, 1);
19235
+ pos++;
19236
+ } else {
19237
+ writeLengthCode(out, prevMatchLen);
19238
+ writeDistanceCode(out, prevMatchDist);
19239
+ const matchEnd = pos - 1 + prevMatchLen;
19240
+ const insertEnd = Math.min(matchEnd, data.length);
19241
+ for (let i = pos; i < insertEnd; i++) insertHash(i);
19242
+ insertWindow(pos, insertEnd - pos);
19243
+ pos = insertEnd;
19244
+ hasPrevMatch = false;
19245
+ prevMatchLen = 0;
19246
+ }
19247
+ else if (bestLen >= MIN_MATCH) {
19248
+ hasPrevMatch = true;
19249
+ prevMatchLen = bestLen;
19250
+ prevMatchDist = bestDist;
19251
+ prevLiteral = data[pos];
19252
+ insertWindow(pos, 1);
19253
+ pos++;
19133
19254
  } else {
19134
19255
  writeLiteralCode(out, data[pos]);
19135
- window[wLen % WINDOW_SIZE] = data[pos];
19136
- wLen++;
19256
+ insertWindow(pos, 1);
19137
19257
  pos++;
19138
19258
  }
19139
19259
  }
19260
+ if (hasPrevMatch) {
19261
+ writeLengthCode(out, prevMatchLen);
19262
+ writeDistanceCode(out, prevMatchDist);
19263
+ const matchEnd = Math.min(pos - 1 + prevMatchLen, data.length);
19264
+ for (let i = pos; i < matchEnd; i++) insertHash(i);
19265
+ insertWindow(pos, matchEnd - pos);
19266
+ hasPrevMatch = false;
19267
+ prevMatchLen = 0;
19268
+ }
19140
19269
  writeLiteralCode(out, 256);
19141
19270
  this._windowLen = wLen;
19142
19271
  this._totalIn = totalIn + data.length;
19272
+ this._hasPrevMatch = hasPrevMatch;
19273
+ this._prevMatchLen = prevMatchLen;
19274
+ this._prevMatchDist = prevMatchDist;
19275
+ this._prevLiteral = prevLiteral;
19143
19276
  return out.flushBytes();
19144
19277
  }
19145
19278
  /**
@@ -22783,7 +22916,7 @@ self.onmessage = async function(event) {
22783
22916
  this._uncompressedSize += data.length;
22784
22917
  }
22785
22918
  if (this._deflateWanted) {
22786
- if (!this._syncDeflater) this._syncDeflater = new SyncDeflater();
22919
+ if (!this._syncDeflater) this._syncDeflater = new SyncDeflater(this.level);
22787
22920
  if (data.length > 0) {
22788
22921
  const compressed = this._syncDeflater.write(data);
22789
22922
  if (compressed.length > 0) {