compress.c (3165B)
1 /* Public standalone compression API: a thin composition over the internal codec 2 * shims (src/dist/{deflate,lz4frame}.c) that also back <kit/package.h>. See 3 * <kit/compress.h>. */ 4 5 #include <kit/compress.h> 6 #include <stdarg.h> 7 8 #include "dist/deflate.h" 9 #include "dist/dist.h" 10 #include "dist/lz4frame.h" 11 12 /* Container magic: gzip (RFC 1952) and the LZ4 frame magic, little-endian 13 * 0x184D2204. Used only to auto-detect the format on decompress. */ 14 static const uint8_t COMPRESS_GZIP_MAGIC[2] = {0x1f, 0x8b}; 15 static const uint8_t COMPRESS_LZ4F_MAGIC[4] = {0x04, 0x22, 0x4d, 0x18}; 16 17 /* Emit an operational error through the context diag sink (no source location), 18 * mirroring src/api/cas.c. No-op when the caller supplied no sink. */ 19 static void compress_diagf(const KitContext* ctx, const char* fmt, ...) { 20 va_list ap; 21 KitSrcLoc loc; 22 if (!ctx || !ctx->diag || !ctx->diag->emit) return; 23 loc.file_id = 0; 24 loc.line = 0; 25 loc.col = 0; 26 va_start(ap, fmt); 27 ctx->diag->emit(ctx->diag, KIT_DIAG_ERROR, loc, fmt, ap); 28 va_end(ap); 29 } 30 31 static const char* compress_fmt_name(KitCompressFormat fmt) { 32 return fmt == KIT_COMPRESS_GZIP ? "gzip" : "lz4"; 33 } 34 35 KitStatus kit_compress(const KitContext* ctx, KitCompressFormat fmt, 36 const uint8_t* data, size_t len, KitWriter* out) { 37 int r; 38 if (!ctx || !ctx->heap || !out || (!data && len != 0)) return KIT_ERR; 39 switch (fmt) { 40 case KIT_COMPRESS_GZIP: 41 r = dist_gz_compress(out, data, len); 42 break; 43 case KIT_COMPRESS_LZ4_FRAME: 44 r = dist_lz4f_compress(ctx->heap, out, data, len); 45 break; 46 default: 47 compress_diagf(ctx, "compress: unknown format %d", (int)fmt); 48 return KIT_ERR; 49 } 50 if (r != DIST_OK) { 51 compress_diagf(ctx, "compress: %s encode failed", compress_fmt_name(fmt)); 52 return KIT_ERR; 53 } 54 return KIT_OK; 55 } 56 57 KitStatus kit_decompress(const KitContext* ctx, KitCompressFormat fmt, 58 const uint8_t* data, size_t len, KitWriter* out) { 59 int r; 60 if (!ctx || !ctx->heap || !out || (!data && len != 0)) return KIT_ERR; 61 switch (fmt) { 62 case KIT_COMPRESS_GZIP: 63 r = dist_gz_decompress(out, data, len); 64 break; 65 case KIT_COMPRESS_LZ4_FRAME: 66 r = dist_lz4f_decompress(ctx->heap, out, data, len); 67 break; 68 default: 69 compress_diagf(ctx, "decompress: unknown format %d", (int)fmt); 70 return KIT_ERR; 71 } 72 if (r != DIST_OK) { 73 compress_diagf(ctx, "decompress: %s decode failed", compress_fmt_name(fmt)); 74 return KIT_ERR; 75 } 76 return KIT_OK; 77 } 78 79 KitStatus kit_compress_detect(const uint8_t* data, size_t len, 80 KitCompressFormat* out_fmt) { 81 if (!data || !out_fmt) return KIT_ERR; 82 if (len >= sizeof COMPRESS_GZIP_MAGIC && data[0] == COMPRESS_GZIP_MAGIC[0] && 83 data[1] == COMPRESS_GZIP_MAGIC[1]) { 84 *out_fmt = KIT_COMPRESS_GZIP; 85 return KIT_OK; 86 } 87 if (len >= sizeof COMPRESS_LZ4F_MAGIC && data[0] == COMPRESS_LZ4F_MAGIC[0] && 88 data[1] == COMPRESS_LZ4F_MAGIC[1] && data[2] == COMPRESS_LZ4F_MAGIC[2] && 89 data[3] == COMPRESS_LZ4F_MAGIC[3]) { 90 *out_fmt = KIT_COMPRESS_LZ4_FRAME; 91 return KIT_OK; 92 } 93 return KIT_ERR; 94 }