PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/system/jlib/jlz4.cpp

http://github.com/hpcc-systems/HPCC-Platform
C++ | 313 lines | 263 code | 28 blank | 22 comment | 41 complexity | 1e1db7bcba84dd9fdb56e28c429522ac MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, MIT
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "jfcmp.hpp"
  15. #include "jlz4.hpp"
  16. #include "lz4.h"
  17. /* Format:
  18. size32_t totalexpsize;
  19. { size32_t subcmpsize; bytes subcmpdata; }
  20. size32_t trailsize; bytes traildata; // unexpanded
  21. */
  22. class jlib_decl CLZ4Compressor : public CFcmpCompressor
  23. {
  24. virtual void setinmax()
  25. {
  26. inmax = blksz-outlen-sizeof(size32_t);
  27. if (inmax<256)
  28. trailing = true; // too small to bother compressing
  29. else
  30. {
  31. trailing = false;
  32. size32_t slack = LZ4_COMPRESSBOUND(inmax) - inmax;
  33. int inmax2 = inmax - (slack + sizeof(size32_t));
  34. if (inmax2<256)
  35. trailing = true;
  36. else
  37. inmax = inmax2;
  38. }
  39. }
  40. virtual void flushcommitted()
  41. {
  42. // only does non trailing
  43. if (trailing)
  44. return;
  45. size32_t toflush = (inlenblk==COMMITTED)?inlen:inlenblk;
  46. if (toflush == 0)
  47. return;
  48. if (toflush < 256)
  49. {
  50. trailing = true;
  51. return;
  52. }
  53. size32_t outSzRequired = outlen+sizeof(size32_t)*2+LZ4_COMPRESSBOUND(toflush);
  54. if (!dynamicOutSz)
  55. assertex(outSzRequired<=blksz);
  56. else
  57. {
  58. if (outSzRequired>dynamicOutSz)
  59. {
  60. verifyex(outBufMb->ensureCapacity(outBufStart+outSzRequired));
  61. dynamicOutSz = outBufMb->capacity();
  62. outbuf = ((byte *)outBufMb->bufferBase()+outBufStart);
  63. }
  64. }
  65. size32_t *cmpsize = (size32_t *)(outbuf+outlen);
  66. byte *out = (byte *)(cmpsize+1);
  67. *cmpsize = LZ4_compress_default((const char *)inbuf, (char *)out, toflush, LZ4_COMPRESSBOUND(toflush));
  68. if (*cmpsize && *cmpsize<toflush)
  69. {
  70. *(size32_t *)outbuf += toflush;
  71. outlen += *cmpsize+sizeof(size32_t);
  72. if (inlenblk==COMMITTED)
  73. inlen = 0;
  74. else
  75. {
  76. inlen -= inlenblk;
  77. memmove(inbuf,inbuf+toflush,inlen);
  78. }
  79. setinmax();
  80. return;
  81. }
  82. trailing = true;
  83. }
  84. };
  85. class jlib_decl CLZ4Expander : public CFcmpExpander
  86. {
  87. public:
  88. virtual void expand(void *buf)
  89. {
  90. if (!outlen)
  91. return;
  92. if (buf)
  93. {
  94. if (bufalloc)
  95. free(outbuf);
  96. bufalloc = 0;
  97. outbuf = (unsigned char *)buf;
  98. }
  99. else if (outlen>bufalloc)
  100. {
  101. if (bufalloc)
  102. free(outbuf);
  103. bufalloc = outlen;
  104. outbuf = (unsigned char *)malloc(bufalloc);
  105. if (!outbuf)
  106. throw MakeStringException(MSGAUD_operator,0, "Out of memory in LZ4Expander::expand, requesting %d bytes", bufalloc);
  107. }
  108. size32_t done = 0;
  109. for (;;)
  110. {
  111. const size32_t szchunk = *in;
  112. in++;
  113. if (szchunk+done<outlen)
  114. {
  115. size32_t written = LZ4_decompress_safe((const char *)in, (char *)((byte *)buf+done), szchunk, outlen-done);
  116. done += written;
  117. if (!written||(done>outlen))
  118. throw MakeStringException(0, "LZ4Expander - corrupt data(1) %d %d",written,szchunk);
  119. }
  120. else
  121. {
  122. if (szchunk+done!=outlen)
  123. throw MakeStringException(0, "LZ4Expander - corrupt data(2) %d %d",szchunk,outlen);
  124. memcpy((byte *)buf+done,in,szchunk);
  125. break;
  126. }
  127. in = (const size32_t *)(((const byte *)in)+szchunk);
  128. }
  129. }
  130. };
  131. void LZ4CompressToBuffer(MemoryBuffer & out, size32_t len, const void * src)
  132. {
  133. size32_t outbase = out.length();
  134. out.append(len);
  135. DelayedMarker<size32_t> cmpSzMarker(out);
  136. void *cmpData = out.reserve(LZ4_COMPRESSBOUND(len));
  137. if (len < 64)
  138. memcpy(cmpData, src, len);
  139. else
  140. {
  141. size32_t cmpSz = LZ4_compress_default((const char *)src, (char *)cmpData, len, LZ4_COMPRESSBOUND(len));
  142. if (!cmpSz)
  143. memcpy(cmpData, src, len);
  144. else
  145. len = cmpSz;
  146. }
  147. cmpSzMarker.write(len);
  148. out.setLength(outbase+len+sizeof(size32_t)*2);
  149. }
  150. void LZ4DecompressToBuffer(MemoryBuffer & out, const void * src)
  151. {
  152. size32_t *sz = (size32_t *)src;
  153. size32_t expsz = *(sz++);
  154. size32_t cmpsz = *(sz++);
  155. void *o = out.reserve(expsz);
  156. if (cmpsz!=expsz)
  157. {
  158. size32_t written = LZ4_decompress_safe((const char *)sz, (char *)o, cmpsz, expsz);
  159. if (written!=expsz)
  160. throw MakeStringException(0, "LZ4DecompressToBuffer - corrupt data(1) %d %d",written,expsz);
  161. }
  162. else
  163. memcpy(o,sz,expsz);
  164. }
  165. void LZ4DecompressToBuffer(MemoryBuffer & out, MemoryBuffer & in)
  166. {
  167. size32_t expsz;
  168. size32_t cmpsz;
  169. in.read(expsz).read(cmpsz);
  170. void *o = out.reserve(expsz);
  171. if (cmpsz!=expsz)
  172. {
  173. size32_t written = LZ4_decompress_safe((const char *)in.readDirect(cmpsz), (char *)o, cmpsz, expsz);
  174. if (written!=expsz)
  175. throw MakeStringException(0, "LZ4DecompressToBuffer - corrupt data(3) %d %d",written,expsz);
  176. }
  177. else
  178. memcpy(o,in.readDirect(cmpsz),expsz);
  179. }
  180. void LZ4DecompressToAttr(MemoryAttr & out, const void * src)
  181. {
  182. size32_t *sz = (size32_t *)src;
  183. size32_t expsz = *(sz++);
  184. size32_t cmpsz = *(sz++);
  185. void *o = out.allocate(expsz);
  186. if (cmpsz!=expsz)
  187. {
  188. size32_t written = LZ4_decompress_safe((const char *)sz, (char *)o, cmpsz, expsz);
  189. if (written!=expsz)
  190. throw MakeStringException(0, "LZ4DecompressToBuffer - corrupt data(2) %d %d",written,expsz);
  191. }
  192. else
  193. memcpy(o,sz,expsz);
  194. }
  195. void LZ4DecompressToBuffer(MemoryAttr & out, MemoryBuffer & in)
  196. {
  197. size32_t expsz;
  198. size32_t cmpsz;
  199. in.read(expsz).read(cmpsz);
  200. void *o = out.allocate(expsz);
  201. if (cmpsz!=expsz)
  202. {
  203. size32_t written = LZ4_decompress_safe((const char *)in.readDirect(cmpsz), (char *)o, cmpsz, expsz);
  204. if (written!=expsz)
  205. throw MakeStringException(0, "LZ4DecompressToBuffer - corrupt data(4) %d %d",written,expsz);
  206. }
  207. else
  208. memcpy(o,in.readDirect(cmpsz),expsz);
  209. }
  210. ICompressor *createLZ4Compressor()
  211. {
  212. return new CLZ4Compressor;
  213. }
  214. IExpander *createLZ4Expander()
  215. {
  216. return new CLZ4Expander;
  217. }
  218. #define LZ4STRMCOMPRESSEDFILEFLAG (I64C(0xc129b02d53545e91))
  219. class CLZ4Stream : public CFcmpStream
  220. {
  221. bool load()
  222. {
  223. bufpos = 0;
  224. bufsize = 0;
  225. if (expOffset==expSize)
  226. return false;
  227. size32_t sz[2];
  228. if (baseio->read(cmpOffset,sizeof(size32_t)*2,&sz)!=sizeof(size32_t)*2)
  229. return false;
  230. bufsize = sz[0];
  231. if (!bufsize)
  232. return false;
  233. cmpOffset += sizeof(size32_t)*2;
  234. if (ma.length()<bufsize)
  235. ma.allocate(bufsize);
  236. MemoryAttr cmpma;
  237. byte *cmpbuf = (byte *)cmpma.allocate(sz[1]);
  238. if (baseio->read(cmpOffset,sz[1],cmpbuf)!=sz[1])
  239. throw MakeStringException(-1,"CLZ4Stream: file corrupt.1");
  240. size32_t amnt = LZ4_decompress_safe((const char *)cmpbuf, (char *)ma.bufferBase(), sz[1], bufsize);
  241. if (amnt!=bufsize)
  242. throw MakeStringException(-1,"CLZ4Stream: file corrupt.2");
  243. cmpOffset += sz[1];
  244. return true;
  245. }
  246. void save()
  247. {
  248. if (bufsize)
  249. {
  250. MemoryAttr dstma;
  251. byte *dst = (byte *)dstma.allocate(sizeof(size32_t)*2+LZ4_COMPRESSBOUND(bufsize));
  252. size32_t sz = LZ4_compress_default((const char *)ma.get(), (char *)(sizeof(size32_t)*2+dst), bufsize, LZ4_COMPRESSBOUND(bufsize));
  253. if (!sz)
  254. {
  255. sz = bufsize;
  256. memcpy((sizeof(size32_t)*2+dst), ma.get(), bufsize);
  257. }
  258. memcpy(dst,&bufsize,sizeof(size32_t));
  259. memcpy(dst+sizeof(size32_t),&sz,sizeof(size32_t));
  260. baseio->write(cmpOffset,sz+sizeof(size32_t)*2,dst);
  261. cmpOffset += sz+sizeof(size32_t)*2;
  262. }
  263. bufsize = 0;
  264. }
  265. public:
  266. CLZ4Stream() { compType = LZ4STRMCOMPRESSEDFILEFLAG; }
  267. virtual ~CLZ4Stream() { flush(); }
  268. };
  269. IFileIOStream *createLZ4StreamRead(IFileIO *base)
  270. {
  271. Owned<CLZ4Stream> strm = new CLZ4Stream();
  272. if (strm->attach(base))
  273. return strm.getClear();
  274. return NULL;
  275. }
  276. IFileIOStream *createLZ4StreamWrite(IFileIO *base)
  277. {
  278. Owned<CLZ4Stream> strm = new CLZ4Stream();
  279. strm->create(base);
  280. return strm.getClear();
  281. }