1 /*
2  * Copyright 2018 Jonathan Dieter <jdieter@gmail.com>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  1. Redistributions of source code must retain the above copyright notice,
8  *     this list of conditions and the following disclaimer.
9  *
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <stdbool.h>
30 #include <zck.h>
31 #include "zck_private.h"
32 
compint_from_size(char * compint,size_t val,size_t * length)33 void compint_from_size(char *compint, size_t val, size_t *length) {
34     for(unsigned char *i = (unsigned char *)compint; ; i++) {
35         i[0] = val % 128;
36         val = (val - i[0]) / 128;
37         (*length)++;
38         if(val == 0) {
39             i[0] += 128;
40             break;
41         }
42     }
43     return;
44 }
45 
compint_to_size(zckCtx * zck,size_t * val,const char * compint,size_t * length,size_t max_length)46 int compint_to_size(zckCtx *zck, size_t *val, const char *compint,
47                     size_t *length, size_t max_length) {
48     VALIDATE_BOOL(zck);
49 
50     *val = 0;
51     size_t old_val = 0;
52     const unsigned char *i = (unsigned char *)compint;
53     int count = 0;
54     bool done = false;
55     while(true) {
56         size_t c = i[0];
57         if(c >= 128) {
58             c -= 128;
59             done = true;
60         }
61         /* There *must* be a more elegant way of doing c * 128**count */
62         for(int f=0; f<count; f++)
63             c *= 128;
64         *val += c;
65         (*length) = (*length) + 1;
66         count++;
67         if(done)
68             break;
69         i++;
70         /* Make sure we're not overflowing and fail if we do */
71         if(count > MAX_COMP_SIZE || count > max_length || *val < old_val) {
72             if(count > max_length)
73                 set_fatal_error(zck, "Read past end of header");
74             else
75                 set_fatal_error(zck, "Number too large");
76             *length -= count;
77             *val = 0;
78             return false;
79         }
80         old_val = *val;
81     }
82     return true;
83 }
84 
compint_from_int(zckCtx * zck,char * compint,int val,size_t * length)85 int compint_from_int(zckCtx *zck, char *compint, int val, size_t *length) {
86     VALIDATE_BOOL(zck);
87 
88     if(val < 0) {
89         set_error(zck, "Unable to compress negative integers");
90         return false;
91     }
92 
93     compint_from_size(compint, (size_t)val, length);
94     return true;
95 }
96 
compint_to_int(zckCtx * zck,int * val,const char * compint,size_t * length,size_t max_length)97 int compint_to_int(zckCtx *zck, int *val, const char *compint, size_t *length,
98                    size_t max_length) {
99     VALIDATE_BOOL(zck);
100 
101     size_t new = (size_t)*val;
102     if(!compint_to_size(zck, &new, compint, length, max_length))
103         return false;
104     *val = (int)new;
105     if(*val < 0) {
106         set_fatal_error(zck, "Overflow error: compressed int is negative");
107         return false;
108     }
109     return true;
110 }
111