diff options
Diffstat (limited to 'deduper/libpuzzle/src/compress.c')
-rw-r--r-- | deduper/libpuzzle/src/compress.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/deduper/libpuzzle/src/compress.c b/deduper/libpuzzle/src/compress.c new file mode 100644 index 0000000..e71da95 --- /dev/null +++ b/deduper/libpuzzle/src/compress.c @@ -0,0 +1,125 @@ +#include "puzzle_common.h" +#include "puzzle_p.h" +#include "puzzle.h" +#include "globals.h" + +void puzzle_init_compressed_cvec(PuzzleContext * const context, + PuzzleCompressedCvec * const compressed_cvec) +{ + (void) context; + compressed_cvec->sizeof_compressed_vec = (size_t) 0U; + compressed_cvec->vec = NULL; +} + +void puzzle_free_compressed_cvec(PuzzleContext * const context, + PuzzleCompressedCvec * const compressed_cvec) +{ + (void) context; + free(compressed_cvec->vec); + compressed_cvec->vec = NULL; +} + +int puzzle_compress_cvec(PuzzleContext * const context, + PuzzleCompressedCvec * const compressed_cvec, + const PuzzleCvec * const cvec) +{ +#define PC_NM(X) ((unsigned char) ((X) + 2)) + size_t remaining = cvec->sizeof_vec; + const signed char *ptr; + unsigned char *cptr; + + (void) context; + compressed_cvec->sizeof_compressed_vec = + (cvec->sizeof_vec + (size_t) 2U) / (size_t) 3U; + if ((compressed_cvec->vec = + calloc(compressed_cvec->sizeof_compressed_vec, + sizeof *compressed_cvec->vec)) == NULL) { + return -1; + } + ptr = cvec->vec; + cptr = compressed_cvec->vec; + while (remaining >= (size_t) 3U) { + *cptr++ = PC_NM(ptr[0]) + PC_NM(ptr[1]) * 5U + + PC_NM(ptr[2]) * (5U * 5U); + ptr += 3U; + remaining -= 3U; + } + if (remaining == (size_t) 1U) { + *cptr++ = PC_NM(ptr[0]); + compressed_cvec->vec[0] |= 128U; + } else if (remaining == (size_t) 2U) { + *cptr++ = PC_NM(ptr[0]) + PC_NM(ptr[1]) * 5U; + if (compressed_cvec->sizeof_compressed_vec < (size_t) 2U) { + puzzle_err_bug(__FILE__, __LINE__); + } + compressed_cvec->vec[1] |= 128U; + } + if ((size_t) (cptr - compressed_cvec->vec) != + compressed_cvec->sizeof_compressed_vec) { + puzzle_err_bug(__FILE__, __LINE__); + } + return 0; +} + +int puzzle_uncompress_cvec(PuzzleContext * const context, + const PuzzleCompressedCvec * const compressed_cvec, + PuzzleCvec * const cvec) +{ +#define PC_FL(X) ((X) & 127U) +#define PC_NP(X) ((signed char) (X) - 2) + + size_t remaining; + unsigned char trailing_bits; + const unsigned char *cptr = compressed_cvec->vec; + signed char *ptr; + unsigned char c; + + (void) context; + if (cvec->vec != NULL) { + puzzle_err_bug(__FILE__, __LINE__); + } + if ((remaining = compressed_cvec->sizeof_compressed_vec) < (size_t) 2U) { + puzzle_err_bug(__FILE__, __LINE__); + } + trailing_bits = ((cptr[0] & 128U) >> 7) | ((cptr[1] & 128U) >> 6); + if (trailing_bits > 2U) { + puzzle_err_bug(__FILE__, __LINE__); + } + cvec->sizeof_vec = (size_t) 3U * + (compressed_cvec->sizeof_compressed_vec - trailing_bits) + + trailing_bits; + if (compressed_cvec->sizeof_compressed_vec > + SIZE_MAX / (size_t) 3U - (size_t) 2U) { + puzzle_err_bug(__FILE__, __LINE__); + } + if ((cvec->vec = calloc(cvec->sizeof_vec, sizeof *cvec->vec)) == NULL) { + return -1; + } + if (trailing_bits != 0U) { + if (remaining <= (size_t) 0U) { + puzzle_err_bug(__FILE__, __LINE__); + } + remaining--; + } + ptr = cvec->vec; + while (remaining > (size_t) 0U) { + c = PC_FL(*cptr++); + *ptr++ = PC_NP(c % 5U); + c /= 5U; + *ptr++ = PC_NP(c % 5U); + c /= 5U; + *ptr++ = PC_NP(c % 5U); + remaining--; + } + if (trailing_bits == 1U) { + *ptr++ = PC_NP(PC_FL(*cptr) % 5U); + } else if (trailing_bits == 2U) { + c = PC_FL(*cptr); + *ptr++ = PC_NP(c % 5U); + *ptr++ = PC_NP(c / 5U % 5U); + } + if ((size_t) (ptr - cvec->vec) != cvec->sizeof_vec) { + puzzle_err_bug(__FILE__, __LINE__); + } + return 0; +} |