aboutsummaryrefslogtreecommitdiff
path: root/deduper/libpuzzle/src/compress.c
blob: e71da95ff5a47ce589b6d16dae9a64286dbe7519 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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;
}