From beb8b405db72e1893d71cbbd74d1631a466d5f74 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 23 Aug 2025 22:54:33 +0100 Subject: [PATCH] Asked Copilot to comment the code. --- zoo/lzd.c | 59 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/zoo/lzd.c b/zoo/lzd.c index c717c41..0127346 100644 --- a/zoo/lzd.c +++ b/zoo/lzd.c @@ -1,5 +1,5 @@ /* -* This file is part of the Aaru Data Preservation Suite. + * This file is part of the Aaru Data Preservation Suite. * Copyright (c) 2019-2025 Natalia Portillo. * * This library is free software; you can redistribute it and/or modify @@ -19,73 +19,83 @@ // Lempel-Ziv-Davis compression implementation based on the public domain code from // Rahul Dhesi from zoo +#include "lzd.h" +#include #include #include -#include -#include "lzd.h" #include "../library.h" +// Reset the dictionary to its initial state static void init_dict(LZDContext *ctx) { - ctx->nbits = 9; - ctx->max_code = 1u << 9; - ctx->free_code = FIRST_FREE; - ctx->have_old = 0; + ctx->nbits = 9; // start with 9‑bit codes + ctx->max_code = 1u << 9; // maximum code value for current nbits + ctx->free_code = FIRST_FREE; // next free dictionary slot + ctx->have_old = 0; // no "previous code" yet } +// Follow the head[] chain until you get the first literal byte of a code static int firstch(LZDContext *ctx, int code) { int steps = 0; while(code > 255) - { - if((unsigned)code > MAXMAX) return -1; - if(++steps > (int)MAXMAX) return -1; + { // follow links until you hit a literal (0‑255) + if((unsigned)code > MAXMAX) return -1; // invalid code range + if(++steps > (int)MAXMAX) return -1; // prevent infinite loop code = ctx->head[code]; } return code; } +// Ensure there are at least nbits available in the bit buffer static int fill_bits(LZDContext *ctx) { while(ctx->bitcount < (int)ctx->nbits) { - if(ctx->in_pos >= ctx->in_len) return -1; + if(ctx->in_pos >= ctx->in_len) return -1; // no more input available + // pull a byte from the input stream into bitbuf at current position ctx->bitbuf |= (uint64_t)ctx->in_ptr[ctx->in_pos++] << ctx->bitcount; ctx->bitcount += 8; } return 0; } +// Read the next code of nbits from the bit buffer static int read_code(LZDContext *ctx) { - if(fill_bits(ctx) < 0) return -1; - int code = (int)(ctx->bitbuf & masks[ctx->nbits]); - ctx->bitbuf >>= ctx->nbits; + if(fill_bits(ctx) < 0) return -1; // top up bits if needed + int code = (int)(ctx->bitbuf & masks[ctx->nbits]); // mask off the low nbits + ctx->bitbuf >>= ctx->nbits; // consume bits ctx->bitcount -= ctx->nbits; return code; } +// Initialise a decompression context: allocate tables, set up initial dictionary LZDStatus LZD_Init(LZDContext *ctx) { memset(ctx, 0, sizeof *ctx); + // allocate head, tail and stack arrays to hold dictionary links and output stack ctx->head = malloc((MAXMAX + 1) * sizeof *ctx->head); ctx->tail = malloc((MAXMAX + 1) * sizeof *ctx->tail); ctx->stack = malloc((MAXMAX + 1) * sizeof *ctx->stack); if(!ctx->head || !ctx->tail || !ctx->stack) return LZD_NEED_INPUT; + // initialise first 256 dictionary entries to literal bytes for(int i = 0; i < 256; i++) { ctx->head[i] = -1; ctx->tail[i] = (uint8_t)i; } + // set stack pointers to empty ctx->stack_lim = ctx->stack + (MAXMAX + 1); ctx->stack_ptr = ctx->stack_lim; - init_dict(ctx); + init_dict(ctx); // reset code size/free_code ctx->bitbuf = 0; ctx->bitcount = 0; return LZD_OK; } +// Point the context at a new input buffer LZDStatus LZD_Feed(LZDContext *ctx, const unsigned char *in, size_t in_len) { ctx->in_ptr = in; @@ -94,26 +104,31 @@ LZDStatus LZD_Feed(LZDContext *ctx, const unsigned char *in, size_t in_len) return LZD_OK; } +// Pull decompressed bytes into `out` up to out_len or until input is exhausted LZDStatus LZD_Drain(LZDContext *ctx, unsigned char *out, size_t out_len, size_t *out_produced) { size_t outpos = 0; while(outpos < out_len) { + // If there are bytes on the stack (from expanding a code), emit them first if(ctx->stack_ptr < ctx->stack_lim) { out[outpos++] = (uint8_t)*ctx->stack_ptr++; continue; } + // Otherwise, read the next code from the bitstream int raw = read_code(ctx); if(raw < 0) { *out_produced = outpos; + // If we emitted something, signal OK; otherwise tell caller we need more input return outpos > 0 ? LZD_OK : LZD_NEED_INPUT; } unsigned code = (unsigned)raw; + // Special code: CLEAR – reset the dictionary and read a fresh literal if(code == CLEAR) { init_dict(ctx); @@ -128,6 +143,7 @@ LZDStatus LZD_Drain(LZDContext *ctx, unsigned char *out, size_t out_len, size_t out[outpos++] = (uint8_t)lit; continue; } + // Special code: Z_EOF – end of compressed stream if(code == Z_EOF) { *out_produced = outpos; @@ -135,15 +151,17 @@ LZDStatus LZD_Drain(LZDContext *ctx, unsigned char *out, size_t out_len, size_t } unsigned in_code = code; + // Handle KwKwK case: code not yet in the dictionary if(code >= ctx->free_code) { if(!ctx->have_old) return LZD_DONE; - int fc = firstch(ctx, ctx->old_code); + int fc = firstch(ctx, ctx->old_code); // get first character of previous code if(fc < 0) return LZD_DONE; *--ctx->stack_ptr = (char)fc; code = ctx->old_code; } + // Walk backwards through dictionary, pushing bytes onto the stack while(code > 255) { *--ctx->stack_ptr = (char)ctx->tail[code]; @@ -152,11 +170,13 @@ LZDStatus LZD_Drain(LZDContext *ctx, unsigned char *out, size_t out_len, size_t uint8_t first_byte = (uint8_t)code; *--ctx->stack_ptr = (char)first_byte; + // Add new sequence to dictionary if we have a valid previous code if(ctx->have_old && ctx->free_code <= MAXMAX) { ctx->tail[ctx->free_code] = first_byte; ctx->head[ctx->free_code] = (int)ctx->old_code; ctx->free_code++; + // Increase code width when table fills up to current max_code if(ctx->free_code >= ctx->max_code && ctx->nbits < MAXBITS) { ctx->nbits++; @@ -171,6 +191,7 @@ LZDStatus LZD_Drain(LZDContext *ctx, unsigned char *out, size_t out_len, size_t return LZD_OK; } +// Free dynamic allocations inside an LZDContext void LZD_Destroy(LZDContext *ctx) { if(!ctx) return; @@ -179,12 +200,14 @@ void LZD_Destroy(LZDContext *ctx) free(ctx->stack); } +// Public API: allocate+initialise a new context AARU_EXPORT void AARU_CALL *CreateLZDContext(void) { LZDContext *c = malloc(sizeof *c); return c && LZD_Init(c) == LZD_OK ? c : (free(c), NULL); } +// Public API: destroy and free a context AARU_EXPORT void AARU_CALL DestroyLZDContext(void *ctx) { if(ctx) @@ -194,12 +217,14 @@ AARU_EXPORT void AARU_CALL DestroyLZDContext(void *ctx) } } +// Public API wrapper to feed new compressed data AARU_EXPORT int AARU_CALL LZD_FeedNative(void *ctx, const unsigned char *data, size_t length) { return (int)LZD_Feed(ctx, data, length); } +// Public API wrapper to drain decompressed data AARU_EXPORT int AARU_CALL LZD_DrainNative(void *ctx, unsigned char *outBuf, size_t outBufLen, size_t *produced) { return (int)LZD_Drain(ctx, outBuf, outBufLen, produced); -} +} \ No newline at end of file