kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }