koffi 2.3.10-beta.2 → 2.3.10

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/build/2.3.10/koffi_darwin_arm64/koffi.node +0 -0
  3. package/build/2.3.10/koffi_darwin_x64/koffi.node +0 -0
  4. package/build/2.3.10/koffi_freebsd_arm64/koffi.node +0 -0
  5. package/build/2.3.10/koffi_freebsd_ia32/koffi.node +0 -0
  6. package/build/2.3.10/koffi_freebsd_x64/koffi.node +0 -0
  7. package/build/2.3.10/koffi_linux_arm32hf/koffi.node +0 -0
  8. package/build/2.3.10/koffi_linux_arm64/koffi.node +0 -0
  9. package/build/2.3.10/koffi_linux_ia32/koffi.node +0 -0
  10. package/build/2.3.10/koffi_linux_riscv64hf64/koffi.node +0 -0
  11. package/build/2.3.10/koffi_linux_x64/koffi.node +0 -0
  12. package/build/2.3.10/koffi_openbsd_ia32/koffi.node +0 -0
  13. package/build/2.3.10/koffi_openbsd_x64/koffi.node +0 -0
  14. package/build/2.3.10/koffi_win32_arm64/koffi.node +0 -0
  15. package/build/2.3.10/koffi_win32_ia32/koffi.node +0 -0
  16. package/build/2.3.10/koffi_win32_x64/koffi.node +0 -0
  17. package/package.json +2 -2
  18. package/src/cnoke/package.json +2 -8
  19. package/src/cnoke/src/builder.js +5 -7
  20. package/src/core/libcc/brotli.cc +194 -0
  21. package/src/core/libcc/libcc.cc +111 -615
  22. package/src/core/libcc/libcc.hh +102 -28
  23. package/src/core/libcc/lz4.cc +204 -0
  24. package/src/core/libcc/miniz.cc +361 -0
  25. package/src/koffi/CMakeLists.txt +1 -1
  26. package/src/koffi/src/call.cc +18 -0
  27. package/build/2.3.10-beta.2/koffi_darwin_arm64/koffi.node +0 -0
  28. package/build/2.3.10-beta.2/koffi_darwin_x64/koffi.node +0 -0
  29. package/build/2.3.10-beta.2/koffi_freebsd_arm64/koffi.node +0 -0
  30. package/build/2.3.10-beta.2/koffi_freebsd_ia32/koffi.node +0 -0
  31. package/build/2.3.10-beta.2/koffi_freebsd_x64/koffi.node +0 -0
  32. package/build/2.3.10-beta.2/koffi_linux_arm32hf/koffi.node +0 -0
  33. package/build/2.3.10-beta.2/koffi_linux_arm64/koffi.node +0 -0
  34. package/build/2.3.10-beta.2/koffi_linux_ia32/koffi.node +0 -0
  35. package/build/2.3.10-beta.2/koffi_linux_riscv64hf64/koffi.node +0 -0
  36. package/build/2.3.10-beta.2/koffi_linux_x64/koffi.node +0 -0
  37. package/build/2.3.10-beta.2/koffi_openbsd_ia32/koffi.node +0 -0
  38. package/build/2.3.10-beta.2/koffi_openbsd_x64/koffi.node +0 -0
  39. package/build/2.3.10-beta.2/koffi_win32_arm64/koffi.node +0 -0
  40. package/build/2.3.10-beta.2/koffi_win32_ia32/koffi.node +0 -0
  41. package/build/2.3.10-beta.2/koffi_win32_x64/koffi.node +0 -0
  42. /package/build/{2.3.10-beta.2 → 2.3.10}/koffi_win32_arm64/koffi.exp +0 -0
  43. /package/build/{2.3.10-beta.2 → 2.3.10}/koffi_win32_arm64/koffi.lib +0 -0
  44. /package/build/{2.3.10-beta.2 → 2.3.10}/koffi_win32_ia32/koffi.exp +0 -0
  45. /package/build/{2.3.10-beta.2 → 2.3.10}/koffi_win32_ia32/koffi.lib +0 -0
  46. /package/build/{2.3.10-beta.2 → 2.3.10}/koffi_win32_x64/koffi.exp +0 -0
  47. /package/build/{2.3.10-beta.2 → 2.3.10}/koffi_win32_x64/koffi.lib +0 -0
@@ -20,14 +20,7 @@
20
20
  // OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  #include "libcc.hh"
23
- #if !defined(LIBCC_NO_MINIZ) && __has_include("vendor/miniz/miniz.h")
24
- #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
25
- #include "vendor/miniz/miniz.h"
26
- #endif
27
- #if !defined(LIBCC_NO_BROTLI) && __has_include("vendor/brotli/c/include/brotli/decode.h")
28
- #include "vendor/brotli/c/include/brotli/decode.h"
29
- #include "vendor/brotli/c/include/brotli/encode.h"
30
- #endif
23
+
31
24
  #if __has_include("vendor/dragonbox/include/dragonbox/dragonbox.h") && __cplusplus >= 201703L
32
25
  #include "vendor/dragonbox/include/dragonbox/dragonbox.h"
33
26
  #endif
@@ -2142,6 +2135,8 @@ StatResult StatFile(const char *filename, unsigned int flags, FileInfo *out_info
2142
2135
  out_info->mtime = FileTimeToUnixTime(attr.ftLastWriteTime);
2143
2136
  out_info->btime = FileTimeToUnixTime(attr.ftCreationTime);
2144
2137
  out_info->mode = (out_info->type == FileType::Directory) ? 0755 : 0644;
2138
+ out_info->uid = 0;
2139
+ out_info->gid = 0;
2145
2140
 
2146
2141
  return StatResult::Success;
2147
2142
  }
@@ -2150,24 +2145,30 @@ bool RenameFile(const char *src_filename, const char *dest_filename, unsigned in
2150
2145
  {
2151
2146
  DWORD move_flags = (flags & (int)RenameFlag::Overwrite) ? MOVEFILE_REPLACE_EXISTING : 0;
2152
2147
 
2153
- if (win32_utf8) {
2154
- if (!MoveFileExA(src_filename, dest_filename, move_flags))
2155
- goto error;
2156
- } else {
2157
- wchar_t src_filename_w[4096];
2158
- wchar_t dest_filename_w[4096];
2159
- if (ConvertUtf8ToWin32Wide(src_filename, src_filename_w) < 0)
2160
- return false;
2161
- if (ConvertUtf8ToWin32Wide(dest_filename, dest_filename_w) < 0)
2162
- return false;
2148
+ for (int i = 0; i < 10; i++) {
2149
+ if (win32_utf8) {
2150
+ if (MoveFileExA(src_filename, dest_filename, move_flags))
2151
+ return true;
2152
+ } else {
2153
+ wchar_t src_filename_w[4096];
2154
+ wchar_t dest_filename_w[4096];
2155
+ if (ConvertUtf8ToWin32Wide(src_filename, src_filename_w) < 0)
2156
+ return false;
2157
+ if (ConvertUtf8ToWin32Wide(dest_filename, dest_filename_w) < 0)
2158
+ return false;
2163
2159
 
2164
- if (!MoveFileExW(src_filename_w, dest_filename_w, move_flags))
2165
- goto error;
2166
- }
2160
+ if (MoveFileExW(src_filename_w, dest_filename_w, move_flags))
2161
+ return true;
2162
+ }
2167
2163
 
2168
- return true;
2164
+ if (GetLastError() != ERROR_ACCESS_DENIED)
2165
+ break;
2166
+
2167
+ // If two threads are trying to rename to the same destination or the FS is
2168
+ // very busy, we get spurious ERROR_ACCESS_DENIED errors. Wait a bit and retry :)
2169
+ Sleep(1);
2170
+ }
2169
2171
 
2170
- error:
2171
2172
  LogError("Failed to rename file '%1' to '%2': %3", src_filename, dest_filename, GetWin32ErrorString());
2172
2173
  return false;
2173
2174
  }
@@ -2291,7 +2292,7 @@ static FileType FileModeToType(mode_t mode)
2291
2292
 
2292
2293
  StatResult StatFile(const char *filename, unsigned int flags, FileInfo *out_info)
2293
2294
  {
2294
- #ifdef __linux__
2295
+ #if defined(__linux__) && !defined(LIBCC_NO_STATX)
2295
2296
  int stat_flags = (flags & (int)StatFlag::FollowSymlink) ? 0 : AT_SYMLINK_NOFOLLOW;
2296
2297
  int stat_mask = STATX_TYPE | STATX_MODE | STATX_MTIME | STATX_BTIME | STATX_SIZE;
2297
2298
 
@@ -2326,6 +2327,8 @@ StatResult StatFile(const char *filename, unsigned int flags, FileInfo *out_info
2326
2327
  out_info->btime = out_info->mtime;
2327
2328
  }
2328
2329
  out_info->mode = (unsigned int)sxb.stx_mode & ~S_IFMT;
2330
+ out_info->uid = sxb.stx_uid;
2331
+ out_info->gid = sxb.stx_gid;
2329
2332
  #else
2330
2333
  int stat_flags = (flags & (int)StatFlag::FollowSymlink) ? 0 : AT_SYMLINK_NOFOLLOW;
2331
2334
 
@@ -2351,7 +2354,12 @@ StatResult StatFile(const char *filename, unsigned int flags, FileInfo *out_info
2351
2354
 
2352
2355
  out_info->type = FileModeToType(sb.st_mode);
2353
2356
  out_info->size = (int64_t)sb.st_size;
2354
- #if defined(__APPLE__)
2357
+ #if defined(__linux__)
2358
+ out_info->mtime = (int64_t)sb.st_mtim.tv_sec * 1000 +
2359
+ (int64_t)sb.st_mtim.tv_nsec / 1000000;
2360
+ out_info->btime = (int64_t)sb.st_ctim.tv_sec * 1000 +
2361
+ (int64_t)sb.st_ctim.tv_nsec / 1000000;
2362
+ #elif defined(__APPLE__)
2355
2363
  out_info->mtime = (int64_t)sb.st_mtimespec.tv_sec * 1000 +
2356
2364
  (int64_t)sb.st_mtimespec.tv_nsec / 1000000;
2357
2365
  out_info->btime = (int64_t)sb.st_birthtimespec.tv_sec * 1000 +
@@ -2368,6 +2376,8 @@ StatResult StatFile(const char *filename, unsigned int flags, FileInfo *out_info
2368
2376
  (int64_t)sb.st_birthtim.tv_nsec / 1000000;
2369
2377
  #endif
2370
2378
  out_info->mode = (unsigned int)sb.st_mode;
2379
+ out_info->uid = (uint32_t)sb.st_uid;
2380
+ out_info->gid = (uint32_t)sb.st_gid;
2371
2381
  #endif
2372
2382
 
2373
2383
  return StatResult::Success;
@@ -2997,9 +3007,13 @@ Span<const char> GetPathExtension(Span<const char> filename, CompressionType *ou
2997
3007
  };
2998
3008
 
2999
3009
  consume_next_extension();
3010
+
3000
3011
  if (out_compression_type) {
3001
- if (TestStr(extension, ".gz")) {
3002
- *out_compression_type = CompressionType::Gzip;
3012
+ const char *const *it = std::find_if(std::begin(CompressionTypeExtensions), std::end(CompressionTypeExtensions),
3013
+ [&](const char *it) { return it && TestStr(it, extension); });
3014
+
3015
+ if (it != std::end(CompressionTypeExtensions)) {
3016
+ *out_compression_type = (CompressionType)(it - CompressionTypeExtensions);
3003
3017
  consume_next_extension();
3004
3018
  } else {
3005
3019
  *out_compression_type = CompressionType::None;
@@ -5324,7 +5338,6 @@ class AsyncPool {
5324
5338
  HeapArray<bool> workers_state;
5325
5339
 
5326
5340
  HeapArray<TaskQueue> queues;
5327
- int next_queue_idx = 0;
5328
5341
  std::atomic_int pending_tasks { 0 };
5329
5342
 
5330
5343
  public:
@@ -5466,11 +5479,8 @@ void AsyncPool::AddTask(Async *async, const std::function<bool()> &func)
5466
5479
  {
5467
5480
  if (async_running_pool != async->pool) {
5468
5481
  for (;;) {
5469
- TaskQueue *queue = &queues[next_queue_idx];
5470
-
5471
- if (--next_queue_idx < 0) {
5472
- next_queue_idx = (int)workers_state.len - 1;
5473
- }
5482
+ int idx = GetRandomIntSafe(0, queues.len);
5483
+ TaskQueue *queue = &queues[idx];
5474
5484
 
5475
5485
  std::unique_lock<std::mutex> lock_queue(queue->queue_mutex, std::try_to_lock);
5476
5486
  if (lock_queue.owns_lock()) {
@@ -5870,39 +5880,8 @@ StreamReader stdin_st(stdin, "<stdin>");
5870
5880
  StreamWriter stdout_st(stdout, "<stdout>");
5871
5881
  StreamWriter stderr_st(stderr, "<stderr>");
5872
5882
 
5873
- #ifdef MZ_VERSION
5874
- struct MinizInflateContext {
5875
- tinfl_decompressor inflator;
5876
- bool done;
5877
-
5878
- uint8_t in[256 * 1024];
5879
- uint8_t *in_ptr;
5880
- Size in_len;
5881
-
5882
- uint8_t out[256 * 1024];
5883
- uint8_t *out_ptr;
5884
- Size out_len;
5885
-
5886
- // Gzip support
5887
- bool header_done;
5888
- uint32_t crc32;
5889
- Size uncompressed_size;
5890
- };
5891
- RG_STATIC_ASSERT(RG_SIZE(MinizInflateContext::out) >= TINFL_LZ_DICT_SIZE);
5892
- #endif
5893
-
5894
- #ifdef BROTLI_DEFAULT_MODE
5895
- struct BrotliDecompressContext {
5896
- BrotliDecoderState *state;
5897
- bool done;
5898
-
5899
- uint8_t in[256 * 1024];
5900
- Size in_len;
5901
-
5902
- uint8_t out[256 * 1024];
5903
- Size out_len;
5904
- };
5905
- #endif
5883
+ static CreateDecompressorFunc *DecompressorFunctions[RG_LEN(CompressionTypeNames)];
5884
+ static CreateCompressorFunc *CompressorFunctions[RG_LEN(CompressionTypeNames)];
5906
5885
 
5907
5886
  bool StreamReader::Open(Span<const uint8_t> buf, const char *filename,
5908
5887
  CompressionType compression_type)
@@ -6000,35 +5979,9 @@ bool StreamReader::Close(bool implicit)
6000
5979
  {
6001
5980
  RG_ASSERT(implicit || this != &stdin_st);
6002
5981
 
6003
- switch (compression.type) {
6004
- case CompressionType::None: {} break;
6005
-
6006
- case CompressionType::Gzip:
6007
- case CompressionType::Zlib: {
6008
- #ifdef MZ_VERSION
6009
- ReleaseOne(nullptr, compression.u.miniz);
6010
- compression.u.miniz = nullptr;
6011
- #else
6012
- RG_UNREACHABLE();
6013
- #endif
6014
- } break;
6015
-
6016
- case CompressionType::Brotli: {
6017
- #ifdef BROTLI_DEFAULT_MODE
6018
- BrotliDecompressContext *ctx = compression.u.brotli;
6019
-
6020
- if (ctx) {
6021
- if (ctx->state) {
6022
- BrotliDecoderDestroyInstance(ctx->state);
6023
- }
6024
-
6025
- ReleaseOne(nullptr, ctx);
6026
- compression.u.brotli = nullptr;
6027
- }
6028
- #else
6029
- RG_UNREACHABLE();
6030
- #endif
6031
- } break;
5982
+ if (decompressor) {
5983
+ RG_ASSERT(compression_type != CompressionType::None);
5984
+ delete decompressor;
6032
5985
  }
6033
5986
 
6034
5987
  switch (source.type) {
@@ -6048,7 +6001,7 @@ bool StreamReader::Close(bool implicit)
6048
6001
 
6049
6002
  filename = nullptr;
6050
6003
  error = true;
6051
- compression.type = CompressionType::None;
6004
+ compression_type = CompressionType::None;
6052
6005
  source.type = SourceType::Memory;
6053
6006
  source.eof = false;
6054
6007
  eof = false;
@@ -6079,31 +6032,12 @@ bool StreamReader::Rewind()
6079
6032
  } break;
6080
6033
  }
6081
6034
 
6082
- switch (compression.type) {
6083
- case CompressionType::None: {} break;
6084
-
6085
- case CompressionType::Gzip:
6086
- case CompressionType::Zlib: {
6087
- #ifdef MZ_VERSION
6088
- memset(compression.u.miniz, 0, sizeof(*compression.u.miniz));
6089
- tinfl_init(&compression.u.miniz->inflator);
6090
- compression.u.miniz->crc32 = MZ_CRC32_INIT;
6091
- #else
6092
- RG_UNREACHABLE();
6093
- #endif
6094
- } break;
6035
+ if (decompressor) {
6036
+ RG_ASSERT(compression_type != CompressionType::None);
6037
+ delete decompressor;
6095
6038
 
6096
- case CompressionType::Brotli: {
6097
- #ifdef BROTLI_DEFAULT_MODE
6098
- if (compression.u.brotli->state) {
6099
- BrotliDecoderDestroyInstance(compression.u.brotli->state);
6100
- compression.u.brotli->state = nullptr;
6101
- }
6102
- compression.u.brotli->state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
6103
- #else
6104
- RG_UNREACHABLE();
6105
- #endif
6106
- } break;
6039
+ if (!InitDecompressor(compression_type))
6040
+ return false;
6107
6041
  }
6108
6042
 
6109
6043
  source.eof = false;
@@ -6135,28 +6069,16 @@ Size StreamReader::Read(Span<uint8_t> out_buf)
6135
6069
  return -1;
6136
6070
 
6137
6071
  Size read_len = 0;
6138
- switch (compression.type) {
6139
- case CompressionType::None: {
6140
- read_len = ReadRaw(out_buf.len, out_buf.ptr);
6141
- eof = source.eof;
6142
- } break;
6072
+ if (decompressor) {
6073
+ RG_ASSERT(compression_type != CompressionType::None);
6143
6074
 
6144
- case CompressionType::Gzip:
6145
- case CompressionType::Zlib: {
6146
- #ifdef MZ_VERSION
6147
- read_len = ReadInflate(out_buf.len, out_buf.ptr);
6148
- #else
6149
- RG_UNREACHABLE();
6150
- #endif
6151
- } break;
6075
+ read_len = decompressor->Read(out_buf.len, out_buf.ptr);
6076
+ error |= (read_len < 0);
6077
+ } else {
6078
+ RG_ASSERT(compression_type == CompressionType::None);
6152
6079
 
6153
- case CompressionType::Brotli: {
6154
- #ifdef BROTLI_DEFAULT_MODE
6155
- read_len = ReadBrotli(out_buf.len, out_buf.ptr);
6156
- #else
6157
- RG_UNREACHABLE();
6158
- #endif
6159
- } break;
6080
+ read_len = ReadRaw(out_buf.len, out_buf.ptr);
6081
+ eof = source.eof;
6160
6082
  }
6161
6083
 
6162
6084
  return read_len;
@@ -6185,7 +6107,7 @@ Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
6185
6107
  // For some files (such as in /proc), the file size is reported as 0 even though there
6186
6108
  // is content inside, because these files are generated on demand. So we need to take
6187
6109
  // the slow path for apparently empty files.
6188
- if (compression.type == CompressionType::None && ComputeRawLen() > 0) {
6110
+ if (compression_type == CompressionType::None && ComputeRawLen() > 0) {
6189
6111
  if (raw_len > max_len) {
6190
6112
  LogError("File '%1' is too large (limit = %2)", filename, FmtDiskSize(max_len));
6191
6113
  return -1;
@@ -6265,253 +6187,30 @@ int64_t StreamReader::ComputeRawLen()
6265
6187
 
6266
6188
  bool StreamReader::InitDecompressor(CompressionType type)
6267
6189
  {
6268
- switch (type) {
6269
- case CompressionType::None: {} break;
6270
-
6271
- case CompressionType::Gzip:
6272
- case CompressionType::Zlib: {
6273
- #ifdef MZ_VERSION
6274
- compression.u.miniz = AllocateOne<MinizInflateContext>(nullptr, (int)AllocFlag::Zero);
6275
- tinfl_init(&compression.u.miniz->inflator);
6276
- compression.u.miniz->crc32 = MZ_CRC32_INIT;
6277
- #else
6278
- LogError("Deflate decompression not available for '%1'", filename);
6279
- error = true;
6280
- return false;
6281
- #endif
6282
- } break;
6190
+ if (type != CompressionType::None) {
6191
+ CreateDecompressorFunc *func = DecompressorFunctions[(int)type];
6283
6192
 
6284
- case CompressionType::Brotli: {
6285
- #ifdef BROTLI_DEFAULT_MODE
6286
- compression.u.brotli = AllocateOne<BrotliDecompressContext>(nullptr, (int)AllocFlag::Zero);
6287
- compression.u.brotli->state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
6288
- #else
6289
- LogError("Brotli decompression not available for '%1'", filename);
6193
+ if (!func) {
6194
+ LogError("%1 decompression is not available for '%2'", CompressionTypeNames[(int)type], filename);
6290
6195
  error = true;
6291
6196
  return false;
6292
- #endif
6293
- } break;
6294
- }
6295
- compression.type = type;
6296
-
6297
- return true;
6298
- }
6299
-
6300
- #ifdef MZ_VERSION
6301
- Size StreamReader::ReadInflate(Size max_len, void *out_buf)
6302
- {
6303
- MinizInflateContext *ctx = compression.u.miniz;
6304
-
6305
- // Gzip header is not directly supported by miniz. Currently this
6306
- // will fail if the header is longer than 4096 bytes, which is
6307
- // probably quite rare.
6308
- if (compression.type == CompressionType::Gzip && !ctx->header_done) {
6309
- uint8_t header[4096];
6310
- Size header_len;
6311
-
6312
- header_len = ReadRaw(RG_SIZE(header), header);
6313
- if (header_len < 0) {
6314
- return -1;
6315
- } else if (header_len < 10 || header[0] != 0x1F || header[1] != 0x8B) {
6316
- LogError("File '%1' does not look like a Gzip stream", filename);
6317
- error = true;
6318
- return -1;
6319
- }
6320
-
6321
- Size header_offset = 10;
6322
- if (header[3] & 0x4) { // FEXTRA
6323
- if (header_len - header_offset < 2)
6324
- goto truncated_error;
6325
- uint16_t extra_len = (uint16_t)((header[11] << 8) | header[10]);
6326
- if (extra_len > header_len - header_offset)
6327
- goto truncated_error;
6328
- header_offset += extra_len;
6329
- }
6330
- if (header[3] & 0x8) { // FNAME
6331
- uint8_t *end_ptr = (uint8_t *)memchr(header + header_offset, '\0',
6332
- (size_t)(header_len - header_offset));
6333
- if (!end_ptr)
6334
- goto truncated_error;
6335
- header_offset = end_ptr - header + 1;
6336
- }
6337
- if (header[3] & 0x10) { // FCOMMENT
6338
- uint8_t *end_ptr = (uint8_t *)memchr(header + header_offset, '\0',
6339
- (size_t)(header_len - header_offset));
6340
- if (!end_ptr)
6341
- goto truncated_error;
6342
- header_offset = end_ptr - header + 1;
6343
- }
6344
- if (header[3] & 0x2) { // FHCRC
6345
- if (header_len - header_offset < 2)
6346
- goto truncated_error;
6347
- uint16_t crc16 = (uint16_t)(header[1] << 8 | header[0]);
6348
- if ((mz_crc32(MZ_CRC32_INIT, header, (size_t)header_offset) & 0xFFFF) == crc16) {
6349
- LogError("Failed header CRC16 check in '%s'", filename);
6350
- error = true;
6351
- return -1;
6352
- }
6353
- header_offset += 2;
6354
- }
6355
-
6356
- // Put back remaining data in the buffer
6357
- memcpy_safe(ctx->in, header + header_offset, (size_t)(header_len - header_offset));
6358
- ctx->in_ptr = ctx->in;
6359
- ctx->in_len = header_len - header_offset;
6360
-
6361
- ctx->header_done = true;
6362
- }
6363
-
6364
- // Inflate (with miniz)
6365
- {
6366
- Size read_len = 0;
6367
- for (;;) {
6368
- if (max_len < ctx->out_len) {
6369
- memcpy_safe(out_buf, ctx->out_ptr, (size_t)max_len);
6370
- read_len += max_len;
6371
- ctx->out_ptr += max_len;
6372
- ctx->out_len -= max_len;
6373
-
6374
- return read_len;
6375
- } else {
6376
- memcpy_safe(out_buf, ctx->out_ptr, (size_t)ctx->out_len);
6377
- read_len += ctx->out_len;
6378
- out_buf = (uint8_t *)out_buf + ctx->out_len;
6379
- max_len -= ctx->out_len;
6380
- ctx->out_ptr = ctx->out;
6381
- ctx->out_len = 0;
6382
-
6383
- if (ctx->done) {
6384
- eof = true;
6385
- return read_len;
6386
- }
6387
- }
6388
-
6389
- while (ctx->out_len < RG_SIZE(ctx->out)) {
6390
- if (!ctx->in_len) {
6391
- ctx->in_ptr = ctx->in;
6392
- ctx->in_len = ReadRaw(RG_SIZE(ctx->in), ctx->in);
6393
- if (ctx->in_len < 0)
6394
- return read_len ? read_len : ctx->in_len;
6395
- }
6396
-
6397
- size_t in_arg = (size_t)ctx->in_len;
6398
- size_t out_arg = (size_t)(RG_SIZE(ctx->out) - ctx->out_len);
6399
- uint32_t flags = (uint32_t)
6400
- ((compression.type == CompressionType::Zlib ? TINFL_FLAG_PARSE_ZLIB_HEADER : 0) |
6401
- (source.eof ? 0 : TINFL_FLAG_HAS_MORE_INPUT));
6402
-
6403
- tinfl_status status = tinfl_decompress(&ctx->inflator, ctx->in_ptr, &in_arg,
6404
- ctx->out, ctx->out + ctx->out_len,
6405
- &out_arg, flags);
6406
-
6407
- if (compression.type == CompressionType::Gzip) {
6408
- ctx->crc32 = (uint32_t)mz_crc32(ctx->crc32, ctx->out + ctx->out_len, out_arg);
6409
- ctx->uncompressed_size += (Size)out_arg;
6410
- }
6411
-
6412
- ctx->in_ptr += (Size)in_arg;
6413
- ctx->in_len -= (Size)in_arg;
6414
- ctx->out_len += (Size)out_arg;
6415
-
6416
- if (status == TINFL_STATUS_DONE) {
6417
- // Gzip footer (CRC and size check)
6418
- if (compression.type == CompressionType::Gzip) {
6419
- uint32_t footer[2];
6420
- RG_STATIC_ASSERT(RG_SIZE(footer) == 8);
6421
-
6422
- if (ctx->in_len < RG_SIZE(footer)) {
6423
- memcpy_safe(footer, ctx->in_ptr, (size_t)ctx->in_len);
6424
-
6425
- Size missing_len = RG_SIZE(footer) - ctx->in_len;
6426
- if (ReadRaw(missing_len, footer + ctx->in_len) < missing_len) {
6427
- if (error) {
6428
- return -1;
6429
- } else {
6430
- goto truncated_error;
6431
- }
6432
- }
6433
- } else {
6434
- memcpy_safe(footer, ctx->in_ptr, RG_SIZE(footer));
6435
- }
6436
- footer[0] = LittleEndian(footer[0]);
6437
- footer[1] = LittleEndian(footer[1]);
6438
-
6439
- if (ctx->crc32 != footer[0] ||
6440
- (uint32_t)ctx->uncompressed_size != footer[1]) {
6441
- LogError("Failed CRC32 or size check in GZip stream '%1'", filename);
6442
- error = true;
6443
- return -1;
6444
- }
6445
- }
6446
-
6447
- ctx->done = true;
6448
- break;
6449
- } else if (status < TINFL_STATUS_DONE) {
6450
- LogError("Failed to decompress '%1' (Deflate)", filename);
6451
- error = true;
6452
- return -1;
6453
- }
6454
- }
6455
6197
  }
6456
- }
6457
6198
 
6458
- truncated_error:
6459
- LogError("Truncated Gzip header in '%1'", filename);
6460
- error = true;
6461
- return -1;
6462
- }
6463
- #endif
6199
+ decompressor = func(this);
6464
6200
 
6465
- #ifdef BROTLI_DEFAULT_MODE
6466
- Size StreamReader::ReadBrotli(Size max_len, void *out_buf)
6467
- {
6468
- BrotliDecompressContext *ctx = compression.u.brotli;
6469
-
6470
- for (;;) {
6471
- if (ctx->out_len || ctx->done) {
6472
- Size copy_len = std::min(max_len, ctx->out_len);
6473
-
6474
- ctx->out_len -= copy_len;
6475
- memcpy(out_buf, ctx->out, copy_len);
6476
- memmove(ctx->out, ctx->out + copy_len, ctx->out_len);
6477
-
6478
- eof = !ctx->out_len && ctx->done;
6479
- return copy_len;
6480
- }
6481
-
6482
- if (ctx->in_len < RG_SIZE(ctx->in)) {
6483
- Size raw_len = ReadRaw(RG_SIZE(ctx->in) - ctx->in_len, ctx->in + ctx->in_len);
6484
- if (raw_len < 0)
6485
- return -1;
6486
- ctx->in_len += raw_len;
6487
- }
6488
-
6489
- const uint8_t *next_in = ctx->in;
6490
- uint8_t *next_out = ctx->out + ctx->out_len;
6491
- size_t avail_in = (size_t)ctx->in_len;
6492
- size_t avail_out = (size_t)(RG_SIZE(ctx->out) - ctx->out_len);
6493
-
6494
- BrotliDecoderResult ret = BrotliDecoderDecompressStream(ctx->state, &avail_in, &next_in,
6495
- &avail_out, &next_out, nullptr);
6496
-
6497
- if (ret == BROTLI_DECODER_RESULT_SUCCESS) {
6498
- ctx->done = true;
6499
- } else if (ret == BROTLI_DECODER_RESULT_ERROR) {
6500
- LogError("Malformed Brotli stream in '%1'", filename);
6201
+ if (!decompressor) {
6501
6202
  error = true;
6502
- return -1;
6503
- } else if (ret == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
6504
- LogError("Truncated Brotli stream in '%1'", filename);
6203
+ return false;
6204
+ }
6205
+ if (!decompressor->Init(type)) {
6505
6206
  error = true;
6506
- return -1;
6207
+ return false;
6507
6208
  }
6508
-
6509
- ctx->out_len = next_out - ctx->out - ctx->out_len;
6510
6209
  }
6511
6210
 
6512
- RG_UNREACHABLE();
6211
+ compression_type = type;
6212
+ return true;
6513
6213
  }
6514
- #endif
6515
6214
 
6516
6215
  Size StreamReader::ReadRaw(Size max_len, void *out_buf)
6517
6216
  {
@@ -6559,6 +6258,11 @@ restart:
6559
6258
  return read_len;
6560
6259
  }
6561
6260
 
6261
+ StreamDecompressorHelper::StreamDecompressorHelper(CompressionType compression_type, CreateDecompressorFunc *func)
6262
+ {
6263
+ DecompressorFunctions[(int)compression_type] = func;
6264
+ }
6265
+
6562
6266
  // XXX: Maximum line length
6563
6267
  bool LineReader::Next(Span<char> *out_line)
6564
6268
  {
@@ -6612,16 +6316,12 @@ void LineReader::PushLogFilter()
6612
6316
  });
6613
6317
  }
6614
6318
 
6615
- #ifdef MZ_VERSION
6616
- struct MinizDeflateContext {
6617
- tdefl_compressor deflator;
6618
-
6619
- // Gzip support
6620
- uint32_t crc32;
6621
- Size uncompressed_size;
6319
+ #ifdef LZ4_VERSION_MAJOR
6320
+ struct LZ4CompressContext {
6321
+ LZ4F_cctx *encoder;
6322
+ LZ4F_preferences_t prefs = {};
6622
6323
 
6623
- // Used to buffer small writes
6624
- LocalArray<uint8_t, 1024> buf;
6324
+ HeapArray<uint8_t> buf;
6625
6325
  };
6626
6326
  #endif
6627
6327
 
@@ -6788,51 +6488,14 @@ bool StreamWriter::Write(Span<const uint8_t> buf)
6788
6488
  if (RG_UNLIKELY(error))
6789
6489
  return false;
6790
6490
 
6791
- switch (compression.type) {
6792
- case CompressionType::None: {
6793
- return WriteRaw(buf);
6794
- } break;
6795
-
6796
- case CompressionType::Gzip:
6797
- case CompressionType::Zlib: {
6798
- #ifdef MZ_VERSION
6799
- MinizDeflateContext *ctx = compression.u.miniz;
6800
-
6801
- if (ctx->buf.len) {
6802
- Size copy_len = std::min(buf.len, ctx->buf.Available());
6803
-
6804
- memcpy_safe(ctx->buf.end(), buf.ptr, copy_len);
6805
- ctx->buf.len += copy_len;
6806
- buf.ptr += copy_len;
6807
- buf.len -= copy_len;
6808
- }
6809
-
6810
- if (buf.len) {
6811
- if (ctx->buf.len && !WriteDeflate(ctx->buf))
6812
- return false;
6813
- ctx->buf.Clear();
6814
-
6815
- if (buf.len >= RG_SIZE(ctx->buf.data) / 2) {
6816
- if (!WriteDeflate(buf))
6817
- return false;
6818
- } else {
6819
- memcpy_safe(ctx->buf.data, buf.ptr, buf.len);
6820
- ctx->buf.len = buf.len;
6821
- }
6822
- }
6823
-
6824
- return true;
6825
- #endif
6826
- } break;
6491
+ if (compressor) {
6492
+ RG_ASSERT(compression_type != CompressionType::None);
6827
6493
 
6828
- case CompressionType::Brotli: {
6829
- #ifdef BROTLI_DEFAULT_MODE
6830
- return WriteBrotli(buf);
6831
- #endif
6832
- } break;
6494
+ error |= !compressor->Write(buf);
6495
+ return !error;
6496
+ } else {
6497
+ return WriteRaw(buf);
6833
6498
  }
6834
-
6835
- RG_UNREACHABLE();
6836
6499
  }
6837
6500
 
6838
6501
  bool StreamWriter::Close(bool implicit)
@@ -6840,82 +6503,11 @@ bool StreamWriter::Close(bool implicit)
6840
6503
  RG_ASSERT(implicit || this != &stdout_st);
6841
6504
  RG_ASSERT(implicit || this != &stderr_st);
6842
6505
 
6843
- switch (compression.type) {
6844
- case CompressionType::None: {} break;
6845
-
6846
- case CompressionType::Gzip:
6847
- case CompressionType::Zlib: {
6848
- #ifdef MZ_VERSION
6849
- MinizDeflateContext *ctx = compression.u.miniz;
6850
-
6851
- RG_DEFER {
6852
- ReleaseOne(nullptr, ctx);
6853
- compression.u.miniz = nullptr;
6854
- };
6855
-
6856
- if (IsValid() && ctx) {
6857
- if (ctx->buf.len && !WriteDeflate(ctx->buf)) {
6858
- error = true;
6859
- break;
6860
- }
6861
-
6862
- uint8_t dummy; // Avoid UB in miniz
6863
- tdefl_status status = tdefl_compress_buffer(&ctx->deflator, &dummy, 0, TDEFL_FINISH);
6864
- if (status != TDEFL_STATUS_DONE) {
6865
- if (status != TDEFL_STATUS_PUT_BUF_FAILED) {
6866
- LogError("Failed to end Deflate stream for '%1", filename);
6867
- }
6868
-
6869
- error = true;
6870
- break;
6871
- }
6872
-
6873
- if (compression.type == CompressionType::Gzip) {
6874
- uint32_t gzip_footer[] = {
6875
- LittleEndian(ctx->crc32),
6876
- LittleEndian((uint32_t)ctx->uncompressed_size)
6877
- };
6506
+ if (compressor && !error) {
6507
+ RG_ASSERT(compression_type != CompressionType::None);
6508
+ error |= !compressor->Finalize();
6878
6509
 
6879
- if (!WriteRaw(MakeSpan((uint8_t *)gzip_footer, RG_SIZE(gzip_footer)))) {
6880
- error = true;
6881
- break;
6882
- }
6883
- }
6884
- }
6885
- #endif
6886
- } break;
6887
-
6888
- case CompressionType::Brotli: {
6889
- #ifdef BROTLI_DEFAULT_MODE
6890
- BrotliEncoderState *state = compression.u.brotli;
6891
- uint8_t output_buf[2048];
6892
-
6893
- if (state) {
6894
- RG_DEFER {
6895
- BrotliEncoderDestroyInstance(state);
6896
- compression.u.brotli = nullptr;
6897
- };
6898
-
6899
- do {
6900
- const uint8_t *next_in = nullptr;
6901
- uint8_t *next_out = output_buf;
6902
- size_t avail_in = 0;
6903
- size_t avail_out = RG_SIZE(output_buf);
6904
-
6905
- if (!BrotliEncoderCompressStream(state, BROTLI_OPERATION_FINISH,
6906
- &avail_in, &next_in, &avail_out, &next_out, nullptr)) {
6907
- LogError("Failed to compress '%1' with Brotli", filename);
6908
- error = true;
6909
- break;
6910
- }
6911
- if (!WriteRaw(MakeSpan(output_buf, next_out - output_buf))) {
6912
- error = true;
6913
- break;
6914
- }
6915
- } while (BrotliEncoderHasMoreOutput(state));
6916
- }
6917
- #endif
6918
- } break;
6510
+ delete compressor;
6919
6511
  }
6920
6512
 
6921
6513
  switch (dest.type) {
@@ -6974,7 +6566,7 @@ bool StreamWriter::Close(bool implicit)
6974
6566
 
6975
6567
  filename = nullptr;
6976
6568
  error = true;
6977
- compression.type = CompressionType::None;
6569
+ compression_type = CompressionType::None;
6978
6570
  dest.type = DestinationType::Memory;
6979
6571
  str_alloc.ReleaseAll();
6980
6572
 
@@ -6983,133 +6575,32 @@ bool StreamWriter::Close(bool implicit)
6983
6575
 
6984
6576
  bool StreamWriter::InitCompressor(CompressionType type, CompressionSpeed speed)
6985
6577
  {
6986
- switch (type) {
6987
- case CompressionType::None: {} break;
6578
+ if (type != CompressionType::None) {
6579
+ CreateCompressorFunc *func = CompressorFunctions[(int)type];
6988
6580
 
6989
- case CompressionType::Gzip:
6990
- case CompressionType::Zlib: {
6991
- #ifdef MZ_VERSION
6992
- compression.u.miniz = AllocateOne<MinizDeflateContext>(nullptr, (int)AllocFlag::Zero);
6993
- compression.u.miniz->crc32 = MZ_CRC32_INIT;
6994
-
6995
- int flags = 0;
6996
- switch (speed) {
6997
- case CompressionSpeed::Default: { flags = 32 | TDEFL_GREEDY_PARSING_FLAG; } break;
6998
- case CompressionSpeed::Slow: { flags = 512; } break;
6999
- case CompressionSpeed::Fast: { flags = 1 | TDEFL_GREEDY_PARSING_FLAG; } break;
7000
- }
7001
- flags |= (type == CompressionType::Zlib ? TDEFL_WRITE_ZLIB_HEADER : 0);
7002
-
7003
- tdefl_status status = tdefl_init(&compression.u.miniz->deflator,
7004
- [](const void *buf, int len, void *udata) {
7005
- StreamWriter *st = (StreamWriter *)udata;
7006
- return (int)st->WriteRaw(MakeSpan((uint8_t *)buf, len));
7007
- }, this, flags);
7008
- if (status != TDEFL_STATUS_OKAY) {
7009
- LogError("Failed to initialize Deflate compression for '%1'", filename);
7010
- error = true;
7011
- return false;
7012
- }
7013
-
7014
- if (type == CompressionType::Gzip) {
7015
- static uint8_t gzip_header[] = {
7016
- 0x1F, 0x8B, // Fixed bytes
7017
- 8, // Deflate
7018
- 0, // FLG
7019
- 0, 0, 0, 0, // MTIME
7020
- 0, // XFL
7021
- 0 // OS
7022
- };
7023
-
7024
- if (!WriteRaw(gzip_header))
7025
- return false;
7026
- }
7027
- #else
7028
- LogError("Deflate compression not available for '%1'", filename);
6581
+ if (!func) {
6582
+ LogError("%1 compression is not available for '%2'", CompressionTypeNames[(int)type], filename);
7029
6583
  error = true;
7030
6584
  return false;
7031
- #endif
7032
- } break;
7033
-
7034
- case CompressionType::Brotli: {
7035
- #ifdef BROTLI_DEFAULT_MODE
7036
- BrotliEncoderState *state = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
7037
- compression.u.brotli = state;
7038
-
7039
- RG_STATIC_ASSERT(BROTLI_MIN_QUALITY == 0 && BROTLI_MAX_QUALITY == 11);
7040
-
7041
- switch (speed) {
7042
- case CompressionSpeed::Default: { BrotliEncoderSetParameter(state, BROTLI_PARAM_QUALITY, 6); } break;
7043
- case CompressionSpeed::Slow: { BrotliEncoderSetParameter(state, BROTLI_PARAM_QUALITY, 11); } break;
7044
- case CompressionSpeed::Fast: { BrotliEncoderSetParameter(state, BROTLI_PARAM_QUALITY, 0); } break;
7045
- }
7046
- #else
7047
- LogError("Brotli compression not available for '%1'", filename);
7048
- error = true;
7049
- return false;
7050
- #endif
7051
- } break;
7052
- }
7053
-
7054
- compression.type = type;
7055
- compression.speed = speed;
7056
-
7057
- return true;
7058
- }
7059
-
7060
- #ifdef MZ_VERSION
7061
- bool StreamWriter::WriteDeflate(Span<const uint8_t> buf)
7062
- {
7063
- MinizDeflateContext *ctx = compression.u.miniz;
7064
-
7065
- if (compression.type == CompressionType::Gzip) {
7066
- ctx->crc32 = (uint32_t)mz_crc32(ctx->crc32, buf.ptr, (size_t)buf.len);
7067
- ctx->uncompressed_size += buf.len;
7068
- }
7069
-
7070
- tdefl_status status = tdefl_compress_buffer(&ctx->deflator, buf.ptr, (size_t)buf.len, TDEFL_NO_FLUSH);
7071
- if (status < TDEFL_STATUS_OKAY) {
7072
- if (status != TDEFL_STATUS_PUT_BUF_FAILED) {
7073
- LogError("Failed to deflate stream to '%1'", filename);
7074
6585
  }
7075
6586
 
7076
- error = true;
7077
- return false;
7078
- }
7079
-
7080
- return true;
7081
- }
7082
- #endif
7083
-
7084
- #ifdef BROTLI_DEFAULT_MODE
7085
- bool StreamWriter::WriteBrotli(Span<const uint8_t> buf)
7086
- {
7087
- BrotliEncoderState *state = compression.u.brotli;
7088
- uint8_t output_buf[2048];
6587
+ compressor = func(this);
7089
6588
 
7090
- while (buf.len || BrotliEncoderHasMoreOutput(state)) {
7091
- const uint8_t *next_in = buf.ptr;
7092
- uint8_t *next_out = output_buf;
7093
- size_t avail_in = (size_t)buf.len;
7094
- size_t avail_out = RG_SIZE(output_buf);
7095
-
7096
- if (!BrotliEncoderCompressStream(state, BROTLI_OPERATION_PROCESS,
7097
- &avail_in, &next_in, &avail_out, &next_out, nullptr)) {
6589
+ if (!compressor) {
7098
6590
  error = true;
7099
6591
  return false;
7100
6592
  }
7101
- if (!WriteRaw(MakeSpan(output_buf, next_out - output_buf))) {
6593
+ if (!compressor->Init(type, speed)) {
7102
6594
  error = true;
7103
6595
  return false;
7104
6596
  }
7105
-
7106
- buf.len -= next_in - buf.ptr;
7107
- buf.ptr = next_in;
7108
6597
  }
7109
6598
 
6599
+ compression_type = type;
6600
+ compression_speed = speed;
6601
+
7110
6602
  return true;
7111
6603
  }
7112
- #endif
7113
6604
 
7114
6605
  bool StreamWriter::WriteRaw(Span<const uint8_t> buf)
7115
6606
  {
@@ -7161,6 +6652,11 @@ bool StreamWriter::WriteRaw(Span<const uint8_t> buf)
7161
6652
  return true;
7162
6653
  }
7163
6654
 
6655
+ StreamCompressorHelper::StreamCompressorHelper(CompressionType compression_type, CreateCompressorFunc *func)
6656
+ {
6657
+ CompressorFunctions[(int)compression_type] = func;
6658
+ }
6659
+
7164
6660
  bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer)
7165
6661
  {
7166
6662
  if (!reader->IsValid())