00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "roslz4/lz4s.h"
00036
00037 #include "xxhash.h"
00038
00039 #include <stdint.h>
00040 #include <string.h>
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043
00044 #if 0
00045 #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
00046 #else
00047 #define DEBUG(...)
00048 #endif
00049
00050
00051 const uint32_t kMagicNumber = 0x184D2204;
00052 const uint32_t kEndOfStream = 0x00000000;
00053
00054
00055 const uint8_t k1Bits = 0x01;
00056 const uint8_t k2Bits = 0x03;
00057 const uint8_t k3Bits = 0x07;
00058 const uint8_t k4Bits = 0x0F;
00059 const uint8_t k8Bits = 0xFF;
00060
00061 uint32_t readUInt32(unsigned char *buffer) {
00062 return ((buffer[0] << 0) | (buffer[1] << 8) |
00063 (buffer[2] << 16) | (buffer[3] << 24));
00064 }
00065
00066 void writeUInt32(unsigned char *buffer, uint32_t val) {
00067 buffer[0] = val & 0xFF;
00068 buffer[1] = (val >> 8) & 0xFF;
00069 buffer[2] = (val >> 16) & 0xFF;
00070 buffer[3] = (val >> 24) & 0xFF;
00071 }
00072
00073 int min(int a, int b) {
00074 return a < b ? a : b;
00075 }
00076
00077
00078
00079 typedef struct {
00080 int block_independence_flag;
00081 int block_checksum_flag;
00082 int stream_checksum_flag;
00083
00084 char *buffer;
00085 int buffer_size;
00086 int buffer_offset;
00087
00088 int finished;
00089
00090 void* xxh32_state;
00091
00092
00093 int wrote_header;
00094
00095
00096 char header[10];
00097 uint32_t block_size;
00098 int block_size_read;
00099 int block_uncompressed;
00100 uint32_t stream_checksum;
00101 int stream_checksum_read;
00102 } stream_state;
00103
00104 void advanceInput(roslz4_stream *str, int nbytes) {
00105 str->input_next += nbytes;
00106 str->input_left -= nbytes;
00107 str->total_in += nbytes;
00108 }
00109
00110 void advanceOutput(roslz4_stream *str, int nbytes) {
00111 str->output_next += nbytes;
00112 str->output_left -= nbytes;
00113 str->total_out += nbytes;
00114 }
00115
00116 void fillUInt32(roslz4_stream *str, uint32_t *dest_val, int *offset) {
00117 char *dest = (char*) dest_val;
00118 int to_copy = min(4 - *offset, str->input_left);
00119 memcpy(dest + *offset, str->input_next, to_copy);
00120 advanceInput(str, to_copy);
00121 *offset += to_copy;
00122 }
00123
00124 int writeHeader(roslz4_stream *str) {
00125 if (str->output_left < 7) {
00126 return ROSLZ4_OUTPUT_SMALL;
00127 }
00128
00129 stream_state *state = str->state;
00130 writeUInt32((unsigned char*) str->output_next, kMagicNumber);
00131 int version = 1;
00132 char *out = str->output_next;
00133 *(out+4) = ((unsigned)version & k2Bits) << 6;
00134 *(out+4) |= ((unsigned)state->block_independence_flag & k1Bits) << 5;
00135 *(out+4) |= ((unsigned)state->block_checksum_flag & k1Bits) << 4;
00136 *(out+4) |= ((unsigned)state->stream_checksum_flag & k1Bits) << 2;
00137 *(out+5) = ((unsigned)str->block_size_id & k3Bits) << 4;
00138
00139
00140 unsigned char checksum = (XXH32(str->output_next + 4, 2, 0) >> 8) & k8Bits;
00141 *(str->output_next+6) = checksum;
00142
00143 advanceOutput(str, 7);
00144 DEBUG("writeHeader() Put 7 bytes in output\n");
00145
00146 return ROSLZ4_OK;
00147 }
00148
00149 int writeEOS(roslz4_stream *str) {
00150 if (str->output_left < 8) {
00151 return ROSLZ4_OUTPUT_SMALL;
00152 }
00153
00154 stream_state *state = str->state;
00155 state->finished = 1;
00156 writeUInt32((unsigned char*) str->output_next, kEndOfStream);
00157 advanceOutput(str, 4);
00158
00159 uint32_t stream_checksum = XXH32_digest(state->xxh32_state);
00160 writeUInt32((unsigned char*) str->output_next, stream_checksum);
00161 advanceOutput(str, 4);
00162 state->xxh32_state = NULL;
00163
00164 DEBUG("writeEOS() Wrote 8 bytes to output %i\n", str->output_left);
00165 return ROSLZ4_STREAM_END;
00166 }
00167
00168
00169
00170 int bufferToOutput(roslz4_stream *str) {
00171 stream_state *state = str->state;
00172 uint32_t uncomp_size = state->buffer_offset;
00173 if (state->buffer_offset == 0) {
00174 return 0;
00175 } else if (str->output_left - 4 < uncomp_size) {
00176 DEBUG("bufferToOutput() Not enough space left in output\n");
00177 return ROSLZ4_OUTPUT_SMALL;
00178 }
00179
00180 DEBUG("bufferToOutput() Flushing %i bytes, %i left in output\n",
00181 state->buffer_offset, str->output_left);
00182
00183
00184 uint32_t comp_size = LZ4_compress_limitedOutput(state->buffer,
00185 str->output_next + 4,
00186 (int) state->buffer_offset,
00187 (int) uncomp_size - 1);
00188 uint32_t wrote;
00189 if (comp_size > 0) {
00190 DEBUG("bufferToOutput() Compressed to %i bytes\n", comp_size);
00191
00192 wrote = 4 + comp_size;
00193 writeUInt32((unsigned char*)str->output_next, comp_size);
00194 } else {
00195
00196 DEBUG("bufferToOutput() Can't compress, copying input\n");
00197 memcpy(str->output_next + 4, state->buffer, uncomp_size);
00198
00199
00200 wrote = 4 + uncomp_size;
00201 writeUInt32((unsigned char*) str->output_next, uncomp_size | 0x80000000);
00202 }
00203
00204 advanceOutput(str, wrote);
00205 state->buffer_offset -= uncomp_size;
00206
00207 DEBUG("bufferToOutput() Ate %i from buffer, wrote %i to output (%i)\n",
00208 uncomp_size, wrote, str->output_left);
00209 return wrote;
00210 }
00211
00212
00213
00214 int inputToBuffer(roslz4_stream *str) {
00215 stream_state *state = str->state;
00216 if (str->input_left == 0 ||
00217 state->buffer_size == state->buffer_offset) {
00218 return 0;
00219 }
00220 int buffer_left = state->buffer_size - state->buffer_offset;
00221 int to_copy = min(str->input_left, buffer_left);
00222
00223 int ret = XXH32_update(state->xxh32_state, str->input_next, to_copy);
00224 if (ret == XXH_ERROR) { return ROSLZ4_ERROR; }
00225
00226 memcpy(state->buffer + state->buffer_offset, str->input_next, to_copy);
00227 advanceInput(str, to_copy);
00228 state->buffer_offset += to_copy;
00229
00230 DEBUG("inputToBuffer() Wrote % 5i bytes to buffer (size=% 5i)\n",
00231 to_copy, state->buffer_offset);
00232 return to_copy;
00233 }
00234
00235 int streamStateAlloc(roslz4_stream *str) {
00236 stream_state *state = (stream_state*) malloc(sizeof(stream_state));
00237 if (state == NULL) {
00238 return ROSLZ4_MEMORY_ERROR;
00239 }
00240 str->state = state;
00241
00242 str->block_size_id = -1;
00243 state->block_independence_flag = 1;
00244 state->block_checksum_flag = 0;
00245 state->stream_checksum_flag = 1;
00246
00247 state->finished = 0;
00248
00249 state->xxh32_state = XXH32_init(0);
00250 state->stream_checksum = 0;
00251 state->stream_checksum_read = 0;
00252
00253 state->wrote_header = 0;
00254
00255 state->buffer_offset = 0;
00256 state->buffer_size = 0;
00257 state->buffer = NULL;
00258
00259 state->block_size = 0;
00260 state->block_size_read = 0;
00261 state->block_uncompressed = 0;
00262
00263 str->total_in = 0;
00264 str->total_out = 0;
00265
00266 return ROSLZ4_OK;
00267 }
00268
00269 int streamResizeBuffer(roslz4_stream *str, int block_size_id) {
00270 stream_state *state = str->state;
00271 if (!(4 <= block_size_id && block_size_id <= 7)) {
00272 return ROSLZ4_PARAM_ERROR;
00273 }
00274
00275 str->block_size_id = block_size_id;
00276 state->buffer_offset = 0;
00277 state->buffer_size = roslz4_blockSizeFromIndex(str->block_size_id);
00278 state->buffer = (char*) malloc(sizeof(char) * state->buffer_size);
00279 if (state->buffer == NULL) {
00280 return ROSLZ4_MEMORY_ERROR;
00281 }
00282 return ROSLZ4_OK;
00283 }
00284
00285 void streamStateFree(roslz4_stream *str) {
00286 stream_state *state = str->state;
00287 if (state != NULL) {
00288 if (state->buffer != NULL) {
00289 free(state->buffer);
00290 }
00291 if (state->xxh32_state != NULL) {
00292 XXH32_digest(state->xxh32_state);
00293 }
00294 free(state);
00295 str->state = NULL;
00296 }
00297 }
00298
00299 int roslz4_blockSizeFromIndex(int block_id) {
00300 return (1 << (8 + (2 * block_id)));
00301 }
00302
00303 int roslz4_compressStart(roslz4_stream *str, int block_size_id) {
00304 int ret = streamStateAlloc(str);
00305 if (ret < 0) { return ret; }
00306 return streamResizeBuffer(str, block_size_id);
00307 }
00308
00309 int roslz4_compress(roslz4_stream *str, int action) {
00310 int ret;
00311 stream_state *state = str->state;
00312 if (action != ROSLZ4_RUN && action != ROSLZ4_FINISH) {
00313 return ROSLZ4_PARAM_ERROR;
00314 } else if (state->finished) {
00315 return ROSLZ4_ERROR;
00316 }
00317
00318 if (!state->wrote_header) {
00319 ret = writeHeader(str);
00320 if (ret < 0) { return ret; }
00321 state->wrote_header = 1;
00322 }
00323
00324
00325 int read = 0, wrote = 0;
00326 do {
00327 read = inputToBuffer(str);
00328 if (read < 0) { return read; }
00329
00330 wrote = 0;
00331 if (action == ROSLZ4_FINISH || state->buffer_offset == state->buffer_size) {
00332 wrote = bufferToOutput(str);
00333 if (wrote < 0) { return wrote; }
00334 }
00335 } while (read > 0 || wrote > 0);
00336
00337
00338 if (action == ROSLZ4_FINISH) {
00339 return writeEOS(str);
00340 } else {
00341 return ROSLZ4_OK;
00342 }
00343 }
00344
00345 void roslz4_compressEnd(roslz4_stream *str) {
00346 streamStateFree(str);
00347 }
00348
00349
00350
00351 int roslz4_decompressStart(roslz4_stream *str) {
00352 return streamStateAlloc(str);
00353
00354 }
00355
00356
00357
00358 int processHeader(roslz4_stream *str) {
00359 stream_state *state = str->state;
00360 if (str->total_in >= 7) {
00361 return 1;
00362 }
00363
00364 int to_copy = min(7 - str->total_in, str->input_left);
00365 memcpy(state->header + str->total_in, str->input_next, to_copy);
00366 advanceInput(str, to_copy);
00367 if (str->total_in < 7) {
00368 return 0;
00369 }
00370
00371
00372 unsigned char *header = (unsigned char*) state->header;
00373 uint32_t magic_number = readUInt32(header);
00374 if (magic_number != kMagicNumber) {
00375 return ROSLZ4_DATA_ERROR;
00376 }
00377
00378 int version = (header[4] >> 6) & k2Bits;
00379 int block_independence_flag = (header[4] >> 5) & k1Bits;
00380 int block_checksum_flag = (header[4] >> 4) & k1Bits;
00381 int stream_size_flag = (header[4] >> 3) & k1Bits;
00382 int stream_checksum_flag = (header[4] >> 2) & k1Bits;
00383 int reserved1 = (header[4] >> 1) & k1Bits;
00384 int preset_dictionary_flag = (header[4] >> 0) & k1Bits;
00385
00386 int reserved2 = (header[5] >> 7) & k1Bits;
00387 int block_max_id = (header[5] >> 4) & k3Bits;
00388 int reserved3 = (header[5] >> 0) & k4Bits;
00389
00390
00391 if (version != 1) {
00392 return ROSLZ4_DATA_ERROR;
00393 }
00394 if (reserved1 != 0 || reserved2 != 0 || reserved3 != 0) {
00395 return ROSLZ4_DATA_ERROR;
00396 }
00397 if (!(4 <= block_max_id && block_max_id <= 7)) {
00398 return ROSLZ4_DATA_ERROR;
00399 }
00400
00401
00402 if (stream_size_flag != 0) {
00403 return ROSLZ4_DATA_ERROR;
00404 }
00405 if (preset_dictionary_flag != 0) {
00406 return ROSLZ4_DATA_ERROR;
00407 }
00408 if (block_independence_flag != 1) {
00409 return ROSLZ4_DATA_ERROR;
00410 }
00411 if (block_checksum_flag != 0) {
00412 return ROSLZ4_DATA_ERROR;
00413 }
00414 if (stream_checksum_flag != 1) {
00415 return ROSLZ4_DATA_ERROR;
00416 }
00417
00418 int header_checksum = (XXH32(header + 4, 2, 0) >> 8) & k8Bits;
00419 int stored_header_checksum = (header[6] >> 0) & k8Bits;
00420 if (header_checksum != stored_header_checksum) {
00421 return ROSLZ4_DATA_ERROR;
00422 }
00423
00424 int ret = streamResizeBuffer(str, block_max_id);
00425 if (ret == ROSLZ4_OK) {
00426 return 1;
00427 } else {
00428 return ret;
00429 }
00430 }
00431
00432
00433 int readBlockSize(roslz4_stream *str) {
00434 stream_state *state = str->state;
00435 if (state->block_size_read < 4) {
00436 fillUInt32(str, &state->block_size, &state->block_size_read);
00437 if (state->block_size_read == 4) {
00438 state->block_size = readUInt32((unsigned char*)&state->block_size);
00439 state->block_uncompressed = ((unsigned)state->block_size >> 31) & k1Bits;
00440 state->block_size &= 0x7FFFFFFF;
00441 DEBUG("readBlockSize() Block size = %i uncompressed = %i\n",
00442 state->block_size, state->block_uncompressed);
00443 return 1;
00444 } else {
00445 return 0;
00446 }
00447 }
00448 return 1;
00449 }
00450
00451
00452
00453 int readBlock(roslz4_stream *str) {
00454 stream_state *state = str->state;
00455 if (state->block_size_read != 4 || state->block_size == kEndOfStream) {
00456 return ROSLZ4_ERROR;
00457 }
00458
00459 int block_left = state->block_size - state->buffer_offset;
00460 int to_copy = min(str->input_left, block_left);
00461 memcpy(state->buffer + state->buffer_offset, str->input_next, to_copy);
00462 advanceInput(str, to_copy);
00463 state->buffer_offset += to_copy;
00464 DEBUG("readBlock() Read %i bytes from input (block = %i/%i)\n",
00465 to_copy, state->buffer_offset, state->block_size);
00466 return state->buffer_offset == state->block_size;
00467 }
00468
00469 int decompressBlock(roslz4_stream *str) {
00470 stream_state *state = str->state;
00471 if (state->block_size_read != 4 || state->block_size != state->buffer_offset) {
00472
00473 return ROSLZ4_ERROR;
00474 }
00475
00476 if (state->block_uncompressed) {
00477 if (str->output_left >= state->block_size) {
00478 memcpy(str->output_next, state->buffer, state->block_size);
00479 int ret = XXH32_update(state->xxh32_state, str->output_next,
00480 state->block_size);
00481 if (ret == XXH_ERROR) { return ROSLZ4_ERROR; }
00482 advanceOutput(str, state->block_size);
00483 state->block_size_read = 0;
00484 state->buffer_offset = 0;
00485 return ROSLZ4_OK;
00486 } else {
00487 return ROSLZ4_OUTPUT_SMALL;
00488 }
00489 } else {
00490 int decomp_size;
00491 decomp_size = LZ4_decompress_safe(state->buffer, str->output_next,
00492 state->block_size, str->output_left);
00493 if (decomp_size < 0) {
00494 if (str->output_left >= state->buffer_size) {
00495 return ROSLZ4_DATA_ERROR;
00496 } else {
00497
00498 return ROSLZ4_OUTPUT_SMALL;
00499 }
00500 } else {
00501 int ret = XXH32_update(state->xxh32_state, str->output_next, decomp_size);
00502 if (ret == XXH_ERROR) { return ROSLZ4_ERROR; }
00503 advanceOutput(str, decomp_size);
00504 state->block_size_read = 0;
00505 state->buffer_offset = 0;
00506 return ROSLZ4_OK;
00507 }
00508 }
00509 }
00510
00511 int readChecksum(roslz4_stream *str) {
00512 stream_state *state = str->state;
00513 fillUInt32(str, &state->stream_checksum, &state->stream_checksum_read);
00514 if (state->stream_checksum_read == 4) {
00515 state->finished = 1;
00516 state->stream_checksum = readUInt32((unsigned char*)&state->stream_checksum);
00517 uint32_t checksum = XXH32_digest(state->xxh32_state);
00518 state->xxh32_state = NULL;
00519 if (checksum == state->stream_checksum) {
00520 return ROSLZ4_STREAM_END;
00521 } else {
00522 return ROSLZ4_DATA_ERROR;
00523 }
00524 }
00525 return ROSLZ4_OK;
00526 }
00527
00528 int roslz4_decompress(roslz4_stream *str) {
00529 stream_state *state = str->state;
00530 if (state->finished) {
00531 return ROSLZ4_ERROR;
00532 }
00533
00534
00535 int ret = processHeader(str);
00536 if (ret <= 0) {
00537 return ret;
00538 }
00539
00540
00541 while (str->input_left > 0) {
00542 ret = readBlockSize(str);
00543 if (ret == 0) { return ROSLZ4_OK; }
00544
00545 if (state->block_size == kEndOfStream) {
00546 return readChecksum(str);
00547 }
00548
00549 ret = readBlock(str);
00550 if (ret == 0) { return ROSLZ4_OK; }
00551 else if (ret < 0) { return ret; }
00552
00553 ret = decompressBlock(str);
00554 if (ret < 0) { return ret; }
00555 }
00556 return ROSLZ4_OK;
00557 }
00558
00559 void roslz4_decompressEnd(roslz4_stream *str) {
00560 streamStateFree(str);
00561 }
00562
00563
00564
00565 int roslz4_buffToBuffCompress(char *input, unsigned int input_size,
00566 char *output, unsigned int *output_size,
00567 int block_size_id) {
00568 roslz4_stream stream;
00569 stream.input_next = input;
00570 stream.input_left = input_size;
00571 stream.output_next = output;
00572 stream.output_left = *output_size;
00573
00574 int ret;
00575 ret = roslz4_compressStart(&stream, block_size_id);
00576 if (ret != ROSLZ4_OK) { return ret; }
00577
00578 while (stream.input_left > 0 && ret != ROSLZ4_STREAM_END) {
00579 ret = roslz4_compress(&stream, ROSLZ4_FINISH);
00580 if (ret == ROSLZ4_ERROR || ret == ROSLZ4_OUTPUT_SMALL) {
00581 roslz4_compressEnd(&stream);
00582 return ret;
00583 }
00584 }
00585
00586 *output_size = *output_size - stream.output_left;
00587 roslz4_compressEnd(&stream);
00588
00589 if (stream.input_left == 0 && ret == ROSLZ4_STREAM_END) {
00590 return ROSLZ4_OK;
00591 } else {
00592 return ROSLZ4_ERROR;
00593 }
00594 }
00595
00596 int roslz4_buffToBuffDecompress(char *input, unsigned int input_size,
00597 char *output, unsigned int *output_size) {
00598 roslz4_stream stream;
00599 stream.input_next = input;
00600 stream.input_left = input_size;
00601 stream.output_next = output;
00602 stream.output_left = *output_size;
00603
00604 int ret;
00605 ret = roslz4_decompressStart(&stream);
00606 if (ret != ROSLZ4_OK) { return ret; }
00607
00608 while (stream.input_left > 0 && ret != ROSLZ4_STREAM_END) {
00609 ret = roslz4_decompress(&stream);
00610 if (ret < 0) {
00611 roslz4_decompressEnd(&stream);
00612 return ret;
00613 }
00614 }
00615
00616 *output_size = *output_size - stream.output_left;
00617 roslz4_decompressEnd(&stream);
00618
00619 if (stream.input_left == 0 && ret == ROSLZ4_STREAM_END) {
00620 return ROSLZ4_OK;
00621 } else {
00622 return ROSLZ4_ERROR;
00623 }
00624 }