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