commit | author | age
|
dba66b
|
1 |
#include<stdio.h> |
SP |
2 |
#include<stdlib.h> |
|
3 |
#include<general.h> |
|
4 |
#include<string.h> |
|
5 |
#include<zlib.h> |
|
6 |
#include<inttypes.h> |
|
7 |
#include<b64zlib_compression.h> |
|
8 |
|
|
9 |
|
|
10 |
/* zlib compression base64 encoded */ |
|
11 |
/* compressed must not be pre-malloced */ |
|
12 |
/* taken from https://gist.github.com/arq5x/5315739 */ |
|
13 |
/* This function is not to be used in compressing paraview data. See below. */ |
|
14 |
ts_uint ts_compress_data(char *data, ts_uint data_len, char **compressed){ |
|
15 |
z_stream defstream; |
|
16 |
defstream.zalloc = Z_NULL; |
|
17 |
defstream.zfree = Z_NULL; |
|
18 |
defstream.opaque = Z_NULL; |
|
19 |
defstream.avail_in = data_len+1; |
|
20 |
defstream.next_in = (unsigned char *)data; |
|
21 |
char *compr=(char *)malloc(data_len*sizeof(char)); |
|
22 |
defstream.avail_out = data_len+1; |
|
23 |
defstream.next_out = (unsigned char *)compr; |
|
24 |
deflateInit(&defstream, 6); |
|
25 |
// deflateInit(&defstream, Z_BEST_COMPRESSION); |
|
26 |
deflate(&defstream, Z_FINISH); |
|
27 |
deflateEnd(&defstream); |
|
28 |
*compressed=compr; |
|
29 |
return defstream.total_out; |
|
30 |
} |
|
31 |
|
2669d7
|
32 |
/* This function may be used to compress lange strings, however it is not compatible with paraview */ |
dba66b
|
33 |
ts_uint ts_compress_string64(char *data, ts_uint data_len, char **encoded_compressed){ |
SP |
34 |
size_t nbase; |
|
35 |
char *compr; |
|
36 |
size_t number_of_compressed_bytes=ts_compress_data(data, data_len, &compr); |
|
37 |
*encoded_compressed=base64_encode((unsigned char *)compr,number_of_compressed_bytes,&nbase); |
|
38 |
free(compr); |
|
39 |
return nbase; |
|
40 |
} |
|
41 |
|
2669d7
|
42 |
|
SP |
43 |
/** @brief Compresses and base64 encodes a specific section in VTK file. Function corresponds to rules prescribed by VTK standards. |
|
44 |
* |
|
45 |
* The list of Int8, Int64 and Double precision values (or vectors) are compressed and base64 encoded according to the follow sheme: |
|
46 |
* |
|
47 |
* Binary data in the file are compressed when the VTKFile element is of the form |
|
48 |
* |
|
49 |
* <VTKFile ... compressor="vtkZLibDataCompressor"> |
|
50 |
* |
|
51 |
* The data corresponding to a data array are stored in a set of blocks which are each compressed using the zlib library. The block structure allows semi-random access without decompressing all data. In uncompressed form all the blocks have the same size except possibly the last block which might be smaller. The data for one array begin with a header of the form |
|
52 |
* |
|
53 |
* [#blocks][#u-size][#p-size][#c-size-1][#c-size-2]...[#c-size-#blocks][DATA] |
|
54 |
* |
|
55 |
* Each token is an integer value whose type is specified by "header_type" at the top of the file (UInt32 if no type specified). The token meanings are: |
|
56 |
* |
|
57 |
* [#blocks] = Number of blocks |
|
58 |
* [#u-size] = Block size before compression |
|
59 |
* [#p-size] = Size of last partial block (zero if it not needed) |
|
60 |
* [#c-size-i] = Size in bytes of block i after compression |
|
61 |
* |
|
62 |
* The [DATA] portion stores contiguously every block appended together. The offset from the beginning of the data section to the beginning of a block is computed by summing the compressed block sizes from preceding blocks according to the header. |
|
63 |
* |
|
64 |
* |
|
65 |
* @param *data is a pointer of bytes to original vector containting double, long or char values. |
|
66 |
* @param *data_len is a number of bytes in *data pointer, NOT the number of containing values! |
|
67 |
* @returns a pointer to string containing base64 encoded compressed string. Should be freed somewhere afterwards. |
|
68 |
*/ |
dba66b
|
69 |
char *ts_compress(char *data, ts_uint data_len){ |
SP |
70 |
size_t nbase1, nbase2; |
|
71 |
unsigned char *compr=(unsigned char *)malloc(data_len); |
|
72 |
size_t number_of_compressed_bytes=data_len; |
|
73 |
|
|
74 |
compress(compr,&number_of_compressed_bytes, (unsigned char *)data, data_len); |
|
75 |
|
|
76 |
char *encoded_compressed=base64_encode((unsigned char *)compr,number_of_compressed_bytes,&nbase1); |
|
77 |
|
|
78 |
free(compr); |
|
79 |
|
|
80 |
ts_uint header[4]={1, data_len, data_len, number_of_compressed_bytes}; |
2669d7
|
81 |
fprintf(stderr,"Header before encoding: %d, %d, %d, %d\n", header[0],header[1],header[2], header[3]); |
dba66b
|
82 |
char *encoded_header=(char *)base64_encode((unsigned char *)header, 4*sizeof(ts_uint), &nbase2); |
SP |
83 |
char *return_value=malloc((nbase1+nbase2+1)*sizeof(char)); |
|
84 |
strncpy(return_value,encoded_header,nbase2); |
|
85 |
strncpy(return_value+nbase2,encoded_compressed,nbase1); |
|
86 |
*(return_value+nbase1+nbase2)=0; |
|
87 |
|
|
88 |
free(encoded_compressed); |
|
89 |
free(encoded_header); |
2669d7
|
90 |
|
SP |
91 |
//test decoding and decompression |
|
92 |
char *test_data = ts_decompress((unsigned char *)return_value, nbase1+nbase2, data_len); |
|
93 |
free(test_data); |
dba66b
|
94 |
return return_value; |
2669d7
|
95 |
} |
SP |
96 |
|
|
97 |
char *ts_decompress(unsigned char *compressed_data, unsigned int data_len, unsigned int result_len){ |
|
98 |
const size_t encoded_header_len=24; |
|
99 |
ts_uint *header; |
|
100 |
size_t nbase1=0,nbase2=0; |
|
101 |
header=(ts_uint *)base64_decode((const char *)compressed_data, encoded_header_len, &nbase2); |
|
102 |
if(header==NULL) fprintf(stderr, "Error decoding header\n"); |
|
103 |
fprintf(stderr,"Header=%d, %d, %d, %d\n", header[0],header[1], header[2], header[3]); |
|
104 |
unsigned char *decoded_data=base64_decode((const char *)&compressed_data[encoded_header_len], data_len-encoded_header_len, &nbase1); |
c59e0b
|
105 |
if(decoded_data==NULL) fprintf(stderr, "Error decoding compressed data\n"); |
2669d7
|
106 |
unsigned char *return_value=(unsigned char *)malloc(result_len*sizeof(char)); |
SP |
107 |
uncompress(return_value, (unsigned long *)&result_len, decoded_data, header[3]); |
c59e0b
|
108 |
// fprintf(stderr,"RESULT_LEN=%d\n",result_len); |
2669d7
|
109 |
free(decoded_data); |
SP |
110 |
free(header); |
|
111 |
return (char *)return_value; |
dba66b
|
112 |
} |
SP |
113 |
|
|
114 |
ts_uint ts_decompress_string64(char *b64, ts_uint data_len, char **decompressed){ |
|
115 |
return TS_SUCCESS; |
|
116 |
} |
|
117 |
|
|
118 |
/* base64 encoding, taken from http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c */ |
|
119 |
static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', |
|
120 |
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', |
|
121 |
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', |
|
122 |
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', |
|
123 |
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', |
|
124 |
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', |
|
125 |
'w', 'x', 'y', 'z', '0', '1', '2', '3', |
|
126 |
'4', '5', '6', '7', '8', '9', '+', '/'}; |
|
127 |
static int mod_table[] = {0, 2, 1}; |
|
128 |
|
|
129 |
|
|
130 |
char *base64_encode(const unsigned char *data, size_t input_length, size_t *output_length) { |
|
131 |
*output_length = 4 * ((input_length + 2) / 3); |
|
132 |
int i,j; |
|
133 |
char *encoded_data = malloc(*output_length); |
|
134 |
if (encoded_data == NULL) return NULL; |
|
135 |
|
|
136 |
for (i = 0, j = 0; i < input_length;) { |
|
137 |
|
|
138 |
uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0; |
|
139 |
uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0; |
|
140 |
uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0; |
|
141 |
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; |
|
142 |
|
|
143 |
encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; |
|
144 |
encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; |
|
145 |
encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; |
|
146 |
encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; |
|
147 |
} |
|
148 |
|
|
149 |
for (i = 0; i < mod_table[input_length % 3]; i++) |
|
150 |
encoded_data[*output_length - 1 - i] = '='; |
|
151 |
|
|
152 |
return encoded_data; |
|
153 |
} |
|
154 |
|
|
155 |
|
|
156 |
unsigned char *base64_decode(const char *data, size_t input_length, size_t *output_length) { |
|
157 |
int i,j; |
c59e0b
|
158 |
char *decoding_table = build_decoding_table(); |
dba66b
|
159 |
|
SP |
160 |
if (input_length % 4 != 0) return NULL; |
|
161 |
|
|
162 |
*output_length = input_length / 4 * 3; |
|
163 |
if (data[input_length - 1] == '=') (*output_length)--; |
|
164 |
if (data[input_length - 2] == '=') (*output_length)--; |
|
165 |
|
|
166 |
unsigned char *decoded_data = malloc(*output_length); |
|
167 |
if (decoded_data == NULL) return NULL; |
|
168 |
|
|
169 |
for (i = 0, j = 0; i < input_length;) { |
|
170 |
uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]]; |
|
171 |
uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]]; |
|
172 |
uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]]; |
|
173 |
uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]]; |
|
174 |
|
|
175 |
uint32_t triple = (sextet_a << 3 * 6) |
|
176 |
+ (sextet_b << 2 * 6) |
|
177 |
+ (sextet_c << 1 * 6) |
|
178 |
+ (sextet_d << 0 * 6); |
|
179 |
|
|
180 |
if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF; |
|
181 |
if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; |
|
182 |
if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; |
|
183 |
} |
c59e0b
|
184 |
free(decoding_table); |
dba66b
|
185 |
return decoded_data; |
SP |
186 |
} |
|
187 |
|
|
188 |
|
c59e0b
|
189 |
char *build_decoding_table() { |
SP |
190 |
char *decoding_table = malloc(256); |
dba66b
|
191 |
int i; |
SP |
192 |
for (i = 0; i < 64; i++) |
|
193 |
decoding_table[(unsigned char) encoding_table[i]] = i; |
c59e0b
|
194 |
return decoding_table; |
dba66b
|
195 |
} |
SP |
196 |
|
|
197 |
|
|
198 |
|
|
199 |
|
|
200 |
|