Go to the documentation of this file.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 "rosbag/chunked_file.h"
00036
00037 #include <iostream>
00038 #include <cstring>
00039 #include "console_bridge/console.h"
00040
00041 using std::string;
00042
00043 namespace rosbag {
00044
00045 LZ4Stream::LZ4Stream(ChunkedFile* file)
00046 : Stream(file), block_size_id_(6) {
00047 buff_size_ = roslz4_blockSizeFromIndex(block_size_id_) + 64;
00048 buff_ = new char[buff_size_];
00049 }
00050
00051 LZ4Stream::~LZ4Stream() {
00052 delete[] buff_;
00053 }
00054
00055 CompressionType LZ4Stream::getCompressionType() const {
00056 return compression::LZ4;
00057 }
00058
00059 void LZ4Stream::startWrite() {
00060 setCompressedIn(0);
00061
00062 int ret = roslz4_compressStart(&lz4s_, block_size_id_);
00063 switch(ret) {
00064 case ROSLZ4_OK: break;
00065 case ROSLZ4_MEMORY_ERROR: throw BagIOException("ROSLZ4_MEMORY_ERROR: insufficient memory available"); break;
00066 case ROSLZ4_PARAM_ERROR: throw BagIOException("ROSLZ4_PARAM_ERROR: bad block size"); break;
00067 default: throw BagException("Unhandled return code");
00068 }
00069 lz4s_.output_next = buff_;
00070 lz4s_.output_left = buff_size_;
00071 }
00072
00073 void LZ4Stream::write(void* ptr, size_t size) {
00074 lz4s_.input_left = size;
00075 lz4s_.input_next = (char*) ptr;
00076
00077 writeStream(ROSLZ4_RUN);
00078 setCompressedIn(getCompressedIn() + size);
00079 }
00080
00081 void LZ4Stream::writeStream(int action) {
00082 int ret = ROSLZ4_OK;
00083 while (lz4s_.input_left > 0 ||
00084 (action == ROSLZ4_FINISH && ret != ROSLZ4_STREAM_END)) {
00085 ret = roslz4_compress(&lz4s_, action);
00086 switch(ret) {
00087 case ROSLZ4_OK: break;
00088 case ROSLZ4_OUTPUT_SMALL:
00089 if (lz4s_.output_next - buff_ == buff_size_) {
00090 throw BagIOException("ROSLZ4_OUTPUT_SMALL: output buffer is too small");
00091 } else {
00092
00093 break;
00094 }
00095 case ROSLZ4_STREAM_END: break;
00096 case ROSLZ4_PARAM_ERROR: throw BagIOException("ROSLZ4_PARAM_ERROR: bad block size"); break;
00097 case ROSLZ4_ERROR: throw BagIOException("ROSLZ4_ERROR: compression error"); break;
00098 default: throw BagException("Unhandled return code");
00099 }
00100
00101
00102 int to_write = lz4s_.output_next - buff_;
00103 if (to_write > 0) {
00104 if (fwrite(buff_, 1, to_write, getFilePointer()) != static_cast<size_t>(to_write)) {
00105 throw BagException("Problem writing data to disk");
00106 }
00107 advanceOffset(to_write);
00108 lz4s_.output_next = buff_;
00109 lz4s_.output_left = buff_size_;
00110 }
00111 }
00112 }
00113
00114 void LZ4Stream::stopWrite() {
00115 writeStream(ROSLZ4_FINISH);
00116 setCompressedIn(0);
00117 roslz4_compressEnd(&lz4s_);
00118 }
00119
00120 void LZ4Stream::startRead() {
00121 int ret = roslz4_decompressStart(&lz4s_);
00122 switch(ret) {
00123 case ROSLZ4_OK: break;
00124 case ROSLZ4_MEMORY_ERROR: throw BagException("ROSLZ4_MEMORY_ERROR: insufficient memory available"); break;
00125 default: throw BagException("Unhandled return code");
00126 }
00127
00128 if (getUnusedLength() > buff_size_) {
00129 throw BagException("Too many unused bytes to decompress");
00130 }
00131
00132
00133 memmove(buff_, getUnused(), getUnusedLength());
00134 lz4s_.input_next = buff_;
00135 lz4s_.input_left = getUnusedLength();
00136 clearUnused();
00137 }
00138
00139 void LZ4Stream::read(void* ptr, size_t size) {
00140
00141 int to_read = buff_size_ - lz4s_.input_left;
00142 char *input_start = buff_ + lz4s_.input_left;
00143 int nread = fread(input_start, 1, to_read, getFilePointer());
00144 if (ferror(getFilePointer())) {
00145 throw BagIOException("Problem reading from file");
00146 }
00147 lz4s_.input_next = buff_;
00148 lz4s_.input_left += nread;
00149 lz4s_.output_next = (char*) ptr;
00150 lz4s_.output_left = size;
00151
00152
00153 int ret = roslz4_decompress(&lz4s_);
00154 switch (ret) {
00155 case ROSLZ4_OK: break;
00156 case ROSLZ4_STREAM_END:
00157 if (getUnused() || getUnusedLength() > 0)
00158 logError("unused data already available");
00159 else {
00160 setUnused(lz4s_.input_next);
00161 setUnusedLength(lz4s_.input_left);
00162 }
00163 return;
00164 case ROSLZ4_ERROR: throw BagException("ROSLZ4_ERROR: decompression error"); break;
00165 case ROSLZ4_MEMORY_ERROR: throw BagException("ROSLZ4_MEMORY_ERROR: insufficient memory available"); break;
00166 case ROSLZ4_OUTPUT_SMALL: throw BagException("ROSLZ4_OUTPUT_SMALL: output buffer is too small"); break;
00167 case ROSLZ4_DATA_ERROR: throw BagException("ROSLZ4_DATA_ERROR: malformed data to decompress"); break;
00168 default: throw BagException("Unhandled return code");
00169 }
00170 if (feof(getFilePointer())) {
00171 throw BagIOException("Reached end of file before reaching end of stream");
00172 }
00173
00174 size_t total_out = lz4s_.output_next - (char*)ptr;
00175 advanceOffset(total_out);
00176
00177
00178 if (lz4s_.input_left > 0) {
00179 memmove(buff_, lz4s_.input_next, lz4s_.input_left);
00180 }
00181 }
00182
00183 void LZ4Stream::stopRead() {
00184 roslz4_decompressEnd(&lz4s_);
00185 }
00186
00187 void LZ4Stream::decompress(uint8_t* dest, unsigned int dest_len, uint8_t* source, unsigned int source_len) {
00188 unsigned int actual_dest_len = dest_len;
00189 int ret = roslz4_buffToBuffDecompress((char*)source, source_len,
00190 (char*)dest, &actual_dest_len);
00191 switch(ret) {
00192 case ROSLZ4_OK: break;
00193 case ROSLZ4_ERROR: throw BagException("ROSLZ4_ERROR: decompression error"); break;
00194 case ROSLZ4_MEMORY_ERROR: throw BagException("ROSLZ4_MEMORY_ERROR: insufficient memory available"); break;
00195 case ROSLZ4_OUTPUT_SMALL: throw BagException("ROSLZ4_OUTPUT_SMALL: output buffer is too small"); break;
00196 case ROSLZ4_DATA_ERROR: throw BagException("ROSLZ4_DATA_ERROR: malformed data to decompress"); break;
00197 default: throw BagException("Unhandled return code");
00198 }
00199 if (actual_dest_len != dest_len) {
00200 throw BagException("Decompression size mismatch in LZ4 chunk");
00201 }
00202 }
00203
00204 }