/* ** Copyright (C) 2004-2007 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ /* ** ** Wrapper around the liblzo compression library. ** */ #include "silk.h" RCSIDENT("$SiLK: lzo-file.c 8267 2007-08-03 18:14:18Z mthomas $"); #include "lzo-file.h" typedef struct compr_buffer { off_t compr_size; uint32_t next_byte; int file; int errorline; int lzo_errno; uint8_t compr_buf[LZO_MAX_COMP_SIZE]; uint8_t uncompr_buf[LZO_MAX_BUF_SIZE]; unsigned internal_error : 1; } compr_buffer_t; typedef struct decompr_buffer { uint32_t uncompr_length; /* Size of data in uncompr_buf */ uint32_t next_byte; /* Offset of next unused data in uncompr_buf */ int file; int errorline; int lzo_errno; uint8_t compr_buf[LZO_MAX_COMP_SIZE]; uint8_t uncompr_buf[LZO_MAX_BUF_SIZE]; unsigned eof : 1; unsigned internal_error : 1; } decompr_buffer_t; #define LZO_INTERNAL_ERROR(fd) \ do { (fd)->lzo_errno = 0; (fd)->internal_error = 1; \ (fd)->errorline = __LINE__; return -1; } while (0) #define LZO_EXTERNAL_ERROR(fd) \ do { (fd)->lzo_errno = errno; (fd)->internal_error = 0; \ (fd)->errorline = __LINE__; return -1; } while (0) static int lzo_file_init() { static int initialized = 0; if (initialized) { return 0; } if (lzo_init()) { return -1; } initialized = 1; return 0; } lzo_compr_buffer_t lzo_create_compr_buffer(void) { if (lzo_file_init() == -1) { return NULL; } return (lzo_compr_buffer_t)calloc(1, sizeof(compr_buffer_t)); } lzo_decompr_buffer_t lzo_create_decompr_buffer(void) { if (lzo_file_init() == -1) { return NULL; } return (lzo_decompr_buffer_t)calloc(1, sizeof(decompr_buffer_t)); } void lzo_bind_compr_buffer(lzo_compr_buffer_t fd, FILE *file) { fflush(file); memset(fd, 0, sizeof(compr_buffer_t)); fd->file = fileno(file); } void lzo_bind_decompr_buffer(lzo_decompr_buffer_t fd, FILE *file) { memset(fd, 0, sizeof(decompr_buffer_t)); fd->file = fileno(file); lseek(fd->file, ftell(file), SEEK_SET); } /* Read from the compressed blocks of an lzo1x compressed file */ ssize_t lzo_read(lzo_decompr_buffer_t fd, void *buf, size_t count) { ssize_t total = 0; /* Take care of boundary conditions */ if (fd == NULL) { return -1; } if (count == 0 || fd->eof) { return 0; } if (count > SSIZE_MAX) { LZO_INTERNAL_ERROR(fd); } /* Transfer the bytes */ while (count) { size_t left = fd->uncompr_length - fd->next_byte; size_t num; ssize_t readlen; /* If we have no bytes, we must get some. */ if (left == 0) { uint32_t comp_block_size, uncomp_block_size; lzo_uint new_block_size; uint32_t num_to_read; uint8_t *bufpos; /* Read in the compressed block sizes */ reread_comp: readlen = read(fd->file, &comp_block_size, sizeof(uint32_t)); if (readlen != sizeof(uint32_t)) { if (readlen == -1 && errno == EINTR) { goto reread_comp; } LZO_EXTERNAL_ERROR(fd); } /* If we have reached the end of the file, we have the bytes we have. */ if (comp_block_size == 0) { fd->eof = 1; return total; } /* Read in the uncompressed block sizes */ reread_uncomp: readlen = read(fd->file, &uncomp_block_size, sizeof(uint32_t)); if (readlen != sizeof(uint32_t)) { if (readlen == -1 && errno == EINTR) { goto reread_uncomp; } LZO_EXTERNAL_ERROR(fd); } comp_block_size = ntohl(comp_block_size); uncomp_block_size = ntohl(uncomp_block_size); new_block_size = uncomp_block_size; /* Verify thay the block sizes are sane */ if (comp_block_size > sizeof(fd->compr_buf) || uncomp_block_size > sizeof(fd->uncompr_buf)) { LZO_INTERNAL_ERROR(fd); } /* Read in the block */ bufpos = fd->compr_buf; num_to_read = comp_block_size; while (num_to_read) { readlen = read(fd->file, bufpos, num_to_read); if (readlen == -1 || readlen == 0) { if (readlen == -1 && errno == EINTR) { continue; } if (readlen == 0) { errno = 0; } LZO_EXTERNAL_ERROR(fd); } num_to_read -= readlen; bufpos += readlen; } /* Decompress it */ if (lzo1x_decompress_safe(fd->compr_buf, (lzo_uint)comp_block_size, fd->uncompr_buf, &new_block_size, NULL)) { LZO_INTERNAL_ERROR(fd); } /* Verify the block's uncompressed size */ if (new_block_size != (lzo_uint)uncomp_block_size) { LZO_INTERNAL_ERROR(fd); } /* Register the new data in the struct */ fd->uncompr_length = left = (size_t)new_block_size; fd->next_byte = 0; } /* Calculate how many bytes to read from our current buffer */ num = (count < left) ? count : left; /* Copy the bytes, and update the data */ memcpy(buf, &fd->uncompr_buf[fd->next_byte], num); fd->next_byte += num; total += num; count -= num; buf = (uint8_t *)buf + num; } return total; } static int32_t lzo_compr(lzo_compr_buffer_t fd, uint32_t size) { uint8_t compressmem[LZO1X_1_15_MEM_COMPRESS]; uint32_t compr_size, uncompr_size; uint32_t old_size = size; ssize_t writelen; uint8_t *bufpos; lzo_uint lzo_size = size; /* Compress the block */ if (lzo1x_1_15_compress(fd->uncompr_buf, (lzo_uint)fd->next_byte, fd->compr_buf, &lzo_size, compressmem) != LZO_E_OK) { assert(0); abort(); } size = (uint32_t)lzo_size; fd->compr_size += size + sizeof(uint32_t) * 2; compr_size = htonl(size); uncompr_size = htonl(old_size); /* Write out compressed size */ rewrite_comp: writelen = write(fd->file, &compr_size, sizeof(uint32_t)); if (writelen != sizeof(uint32_t)) { if (writelen == -1 && errno == EINTR) { goto rewrite_comp; } LZO_EXTERNAL_ERROR(fd); } /* Write out uncompressed size */ rewrite_uncomp: writelen = write(fd->file, &uncompr_size, sizeof(uint32_t)); if (writelen != sizeof(uint32_t)) { if (writelen == -1 && errno == EINTR) { goto rewrite_uncomp; } LZO_EXTERNAL_ERROR(fd); } /* Write out compressed data */ bufpos = fd->compr_buf; while (size) { writelen = write(fd->file, bufpos, size); if (writelen == -1 || writelen == 0) { if (writelen == -1 && errno == EINTR) { continue; } LZO_EXTERNAL_ERROR(fd); } bufpos += writelen; size -= writelen; } fd->next_byte = 0; return (int32_t)size; } /* Write to the compressed blocks of an lzo1x compressed file */ ssize_t lzo_write(lzo_compr_buffer_t fd, void *buf, size_t count) { ssize_t total = 0; /* Take care of boundary conditions */ if (count == 0) { return 0; } if (fd == NULL) { return -1; } if (buf == NULL || count > SSIZE_MAX) { LZO_INTERNAL_ERROR(fd); } /* Transfer the bytes */ while (count) { size_t left = LZO_MAX_BUF_SIZE - fd->next_byte; size_t num; /* If we have filled the buffer, we must write it out. */ if (left == 0) { int32_t compr_size = lzo_compr(fd, LZO_MAX_BUF_SIZE); if (compr_size == -1) { return -1; } left = LZO_MAX_BUF_SIZE; } /* Calculate how many bytes to write into our current buffer */ num = (count < left) ? count : left; /* Copy the bytes, and update the data */ memcpy(&fd->uncompr_buf[fd->next_byte], buf, num); fd->next_byte += num; total += num; count -= num; buf = (uint8_t *)buf + num; } return total; } off_t lzo_flush(lzo_compr_buffer_t fd) { static uint32_t zero = 0; ssize_t writelen; if (fd == NULL) { return -1; } if (fd->next_byte) { int32_t compr_size = lzo_compr(fd, fd->next_byte); if (compr_size == -1) { return -1; } } /* Write EOF mark */ rewrite_eof: writelen = write(fd->file, &zero, sizeof(uint32_t)); if (writelen != sizeof(uint32_t)) { if (writelen == -1 && errno == EINTR) { goto rewrite_eof; } LZO_EXTERNAL_ERROR(fd); } fd->compr_size += sizeof(uint32_t); return fd->compr_size; } off_t lzo_compr_size(lzo_compr_buffer_t fd) { if (fd == NULL) { return -1; } return fd->compr_size; } off_t lzo_compr_size_upper_bound(lzo_compr_buffer_t fd) { if (fd == NULL) { return -1; } return fd->compr_size + fd->next_byte + (LZO_MAX_COMP_SIZE - LZO_MAX_BUF_SIZE) + sizeof(uint32_t) * 2; } char *lzo_compr_strerror(lzo_compr_buffer_t fd) { static char buf[256]; static char *message; message = buf; if (fd->errorline == 0) { message = "No error"; } else if (fd->internal_error == 1) { snprintf(buf, sizeof(buf), "Compression error at lzo-file.c:%d", fd->errorline); } else { snprintf(buf, sizeof(buf), "System error at lzo-file.c:%d (%d)[%s]", fd->errorline, fd->lzo_errno, strerror(fd->lzo_errno)); } return message; } char *lzo_decompr_strerror(lzo_decompr_buffer_t fd) { static char buf[256]; static char *message; message = buf; if (fd->errorline == 0) { message = "No error"; } else if (fd->internal_error == 1) { snprintf(buf, sizeof(buf), "Decompression error at lzo-file.c:%d", fd->errorline); } else { snprintf(buf, sizeof(buf), "System error at lzo-file.c:%d (%d)[%s]", fd->errorline, fd->lzo_errno, strerror(fd->lzo_errno)); } return message; }