1 1.1 tls /* 2 1.1 tls Copyright 2011 Google Inc. All Rights Reserved. 3 1.1 tls 4 1.1 tls Licensed under the Apache License, Version 2.0 (the "License"); 5 1.1 tls you may not use this file except in compliance with the License. 6 1.1 tls You may obtain a copy of the License at 7 1.1 tls 8 1.1 tls http://www.apache.org/licenses/LICENSE-2.0 9 1.1 tls 10 1.1 tls Unless required by applicable law or agreed to in writing, software 11 1.1 tls distributed under the License is distributed on an "AS IS" BASIS, 12 1.1 tls WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 1.1 tls See the License for the specific language governing permissions and 14 1.1 tls limitations under the License. 15 1.1 tls 16 1.1 tls Author: lode.vandevenne (at) gmail.com (Lode Vandevenne) 17 1.1 tls Author: jyrki.alakuijala (at) gmail.com (Jyrki Alakuijala) 18 1.1 tls */ 19 1.1 tls 20 1.1 tls #include "blocksplitter.h" 21 1.1 tls 22 1.1 tls #include <assert.h> 23 1.1 tls #include <stdio.h> 24 1.1 tls #include <stdlib.h> 25 1.1 tls 26 1.1 tls #include "deflate.h" 27 1.1 tls #include "lz77.h" 28 1.1 tls #include "squeeze.h" 29 1.1 tls #include "tree.h" 30 1.1 tls #include "util.h" 31 1.1 tls 32 1.1 tls /* 33 1.1 tls The "f" for the FindMinimum function below. 34 1.1 tls i: the current parameter of f(i) 35 1.1 tls context: for your implementation 36 1.1 tls */ 37 1.1 tls typedef double FindMinimumFun(size_t i, void* context); 38 1.1 tls 39 1.1 tls /* 40 1.1 tls Finds minimum of function f(i) where is is of type size_t, f(i) is of type 41 1.1 tls double, i is in range start-end (excluding end). 42 1.1 tls */ 43 1.1 tls static size_t FindMinimum(FindMinimumFun f, void* context, 44 1.1 tls size_t start, size_t end) { 45 1.1 tls if (end - start < 1024) { 46 1.1 tls double best = ZOPFLI_LARGE_FLOAT; 47 1.1 tls size_t result = start; 48 1.1 tls size_t i; 49 1.1 tls for (i = start; i < end; i++) { 50 1.1 tls double v = f(i, context); 51 1.1 tls if (v < best) { 52 1.1 tls best = v; 53 1.1 tls result = i; 54 1.1 tls } 55 1.1 tls } 56 1.1 tls return result; 57 1.1 tls } else { 58 1.1 tls /* Try to find minimum faster by recursively checking multiple points. */ 59 1.1 tls #define NUM 9 /* Good value: 9. */ 60 1.1 tls size_t i; 61 1.1 tls size_t p[NUM]; 62 1.1 tls double vp[NUM]; 63 1.1 tls size_t besti; 64 1.1 tls double best; 65 1.1 tls double lastbest = ZOPFLI_LARGE_FLOAT; 66 1.1 tls size_t pos = start; 67 1.1 tls 68 1.1 tls for (;;) { 69 1.1 tls if (end - start <= NUM) break; 70 1.1 tls 71 1.1 tls for (i = 0; i < NUM; i++) { 72 1.1 tls p[i] = start + (i + 1) * ((end - start) / (NUM + 1)); 73 1.1 tls vp[i] = f(p[i], context); 74 1.1 tls } 75 1.1 tls besti = 0; 76 1.1 tls best = vp[0]; 77 1.1 tls for (i = 1; i < NUM; i++) { 78 1.1 tls if (vp[i] < best) { 79 1.1 tls best = vp[i]; 80 1.1 tls besti = i; 81 1.1 tls } 82 1.1 tls } 83 1.1 tls if (best > lastbest) break; 84 1.1 tls 85 1.1 tls start = besti == 0 ? start : p[besti - 1]; 86 1.1 tls end = besti == NUM - 1 ? end : p[besti + 1]; 87 1.1 tls 88 1.1 tls pos = p[besti]; 89 1.1 tls lastbest = best; 90 1.1 tls } 91 1.1 tls return pos; 92 1.1 tls #undef NUM 93 1.1 tls } 94 1.1 tls } 95 1.1 tls 96 1.1 tls /* 97 1.1 tls Returns estimated cost of a block in bits. It includes the size to encode the 98 1.1 tls tree and the size to encode all literal, length and distance symbols and their 99 1.1 tls extra bits. 100 1.1 tls 101 1.1 tls litlens: lz77 lit/lengths 102 1.1 tls dists: ll77 distances 103 1.1 tls lstart: start of block 104 1.1 tls lend: end of block (not inclusive) 105 1.1 tls */ 106 1.1 tls static double EstimateCost(const unsigned short* litlens, 107 1.1 tls const unsigned short* dists, 108 1.1 tls size_t lstart, size_t lend) { 109 1.1 tls return ZopfliCalculateBlockSize(litlens, dists, lstart, lend, 2); 110 1.1 tls } 111 1.1 tls 112 1.1 tls typedef struct SplitCostContext { 113 1.1 tls const unsigned short* litlens; 114 1.1 tls const unsigned short* dists; 115 1.1 tls size_t llsize; 116 1.1 tls size_t start; 117 1.1 tls size_t end; 118 1.1 tls } SplitCostContext; 119 1.1 tls 120 1.1 tls 121 1.1 tls /* 122 1.1 tls Gets the cost which is the sum of the cost of the left and the right section 123 1.1 tls of the data. 124 1.1 tls type: FindMinimumFun 125 1.1 tls */ 126 1.1 tls static double SplitCost(size_t i, void* context) { 127 1.1 tls SplitCostContext* c = (SplitCostContext*)context; 128 1.1 tls return EstimateCost(c->litlens, c->dists, c->start, i) + 129 1.1 tls EstimateCost(c->litlens, c->dists, i, c->end); 130 1.1 tls } 131 1.1 tls 132 1.1 tls static void AddSorted(size_t value, size_t** out, size_t* outsize) { 133 1.1 tls size_t i; 134 1.1 tls ZOPFLI_APPEND_DATA(value, out, outsize); 135 1.1 tls if (*outsize > 0) { 136 1.1 tls for (i = 0; i < *outsize - 1; i++) { 137 1.1 tls if ((*out)[i] > value) { 138 1.1 tls size_t j; 139 1.1 tls for (j = *outsize - 1; j > i; j--) { 140 1.1 tls (*out)[j] = (*out)[j - 1]; 141 1.1 tls } 142 1.1 tls (*out)[i] = value; 143 1.1 tls break; 144 1.1 tls } 145 1.1 tls } 146 1.1 tls } 147 1.1 tls } 148 1.1 tls 149 1.1 tls /* 150 1.1 tls Prints the block split points as decimal and hex values in the terminal. 151 1.1 tls */ 152 1.1 tls static void PrintBlockSplitPoints(const unsigned short* litlens, 153 1.1 tls const unsigned short* dists, 154 1.1 tls size_t llsize, const size_t* lz77splitpoints, 155 1.1 tls size_t nlz77points) { 156 1.1 tls size_t* splitpoints = 0; 157 1.1 tls size_t npoints = 0; 158 1.1 tls size_t i; 159 1.1 tls /* The input is given as lz77 indices, but we want to see the uncompressed 160 1.1 tls index values. */ 161 1.1 tls size_t pos = 0; 162 1.1 tls if (nlz77points > 0) { 163 1.1 tls for (i = 0; i < llsize; i++) { 164 1.1 tls size_t length = dists[i] == 0 ? 1 : litlens[i]; 165 1.1 tls if (lz77splitpoints[npoints] == i) { 166 1.1 tls ZOPFLI_APPEND_DATA(pos, &splitpoints, &npoints); 167 1.1 tls if (npoints == nlz77points) break; 168 1.1 tls } 169 1.1 tls pos += length; 170 1.1 tls } 171 1.1 tls } 172 1.1 tls assert(npoints == nlz77points); 173 1.1 tls 174 1.1 tls fprintf(stderr, "block split points: "); 175 1.1 tls for (i = 0; i < npoints; i++) { 176 1.1 tls fprintf(stderr, "%d ", (int)splitpoints[i]); 177 1.1 tls } 178 1.1 tls fprintf(stderr, "(hex:"); 179 1.1 tls for (i = 0; i < npoints; i++) { 180 1.1 tls fprintf(stderr, " %x", (int)splitpoints[i]); 181 1.1 tls } 182 1.1 tls fprintf(stderr, ")\n"); 183 1.1 tls 184 1.1 tls free(splitpoints); 185 1.1 tls } 186 1.1 tls 187 1.1 tls /* 188 1.1 tls Finds next block to try to split, the largest of the available ones. 189 1.1 tls The largest is chosen to make sure that if only a limited amount of blocks is 190 1.1 tls requested, their sizes are spread evenly. 191 1.1 tls llsize: the size of the LL77 data, which is the size of the done array here. 192 1.1 tls done: array indicating which blocks starting at that position are no longer 193 1.1 tls splittable (splitting them increases rather than decreases cost). 194 1.1 tls splitpoints: the splitpoints found so far. 195 1.1 tls npoints: the amount of splitpoints found so far. 196 1.1 tls lstart: output variable, giving start of block. 197 1.1 tls lend: output variable, giving end of block. 198 1.1 tls returns 1 if a block was found, 0 if no block found (all are done). 199 1.1 tls */ 200 1.1 tls static int FindLargestSplittableBlock( 201 1.1 tls size_t llsize, const unsigned char* done, 202 1.1 tls const size_t* splitpoints, size_t npoints, 203 1.1 tls size_t* lstart, size_t* lend) { 204 1.1 tls size_t longest = 0; 205 1.1 tls int found = 0; 206 1.1 tls size_t i; 207 1.1 tls for (i = 0; i <= npoints; i++) { 208 1.1 tls size_t start = i == 0 ? 0 : splitpoints[i - 1]; 209 1.1 tls size_t end = i == npoints ? llsize - 1 : splitpoints[i]; 210 1.1 tls if (!done[start] && end - start > longest) { 211 1.1 tls *lstart = start; 212 1.1 tls *lend = end; 213 1.1 tls found = 1; 214 1.1 tls longest = end - start; 215 1.1 tls } 216 1.1 tls } 217 1.1 tls return found; 218 1.1 tls } 219 1.1 tls 220 1.1 tls void ZopfliBlockSplitLZ77(const ZopfliOptions* options, 221 1.1 tls const unsigned short* litlens, 222 1.1 tls const unsigned short* dists, 223 1.1 tls size_t llsize, size_t maxblocks, 224 1.1 tls size_t** splitpoints, size_t* npoints) { 225 1.1 tls size_t lstart, lend; 226 1.1 tls size_t i; 227 1.1 tls size_t llpos = 0; 228 1.1 tls size_t numblocks = 1; 229 1.1 tls unsigned char* done; 230 1.1 tls double splitcost, origcost; 231 1.1 tls 232 1.1 tls if (llsize < 10) return; /* This code fails on tiny files. */ 233 1.1 tls 234 1.1 tls done = (unsigned char*)malloc(llsize); 235 1.1 tls if (!done) exit(-1); /* Allocation failed. */ 236 1.1 tls for (i = 0; i < llsize; i++) done[i] = 0; 237 1.1 tls 238 1.1 tls lstart = 0; 239 1.1 tls lend = llsize; 240 1.1 tls for (;;) { 241 1.1 tls SplitCostContext c; 242 1.1 tls 243 1.1 tls if (maxblocks > 0 && numblocks >= maxblocks) { 244 1.1 tls break; 245 1.1 tls } 246 1.1 tls 247 1.1 tls c.litlens = litlens; 248 1.1 tls c.dists = dists; 249 1.1 tls c.llsize = llsize; 250 1.1 tls c.start = lstart; 251 1.1 tls c.end = lend; 252 1.1 tls assert(lstart < lend); 253 1.1 tls llpos = FindMinimum(SplitCost, &c, lstart + 1, lend); 254 1.1 tls 255 1.1 tls assert(llpos > lstart); 256 1.1 tls assert(llpos < lend); 257 1.1 tls 258 1.1 tls splitcost = EstimateCost(litlens, dists, lstart, llpos) + 259 1.1 tls EstimateCost(litlens, dists, llpos, lend); 260 1.1 tls origcost = EstimateCost(litlens, dists, lstart, lend); 261 1.1 tls 262 1.1 tls if (splitcost > origcost || llpos == lstart + 1 || llpos == lend) { 263 1.1 tls done[lstart] = 1; 264 1.1 tls } else { 265 1.1 tls AddSorted(llpos, splitpoints, npoints); 266 1.1 tls numblocks++; 267 1.1 tls } 268 1.1 tls 269 1.1 tls if (!FindLargestSplittableBlock( 270 1.1 tls llsize, done, *splitpoints, *npoints, &lstart, &lend)) { 271 1.1 tls break; /* No further split will probably reduce compression. */ 272 1.1 tls } 273 1.1 tls 274 1.1 tls if (lend - lstart < 10) { 275 1.1 tls break; 276 1.1 tls } 277 1.1 tls } 278 1.1 tls 279 1.1 tls if (options->verbose) { 280 1.1 tls PrintBlockSplitPoints(litlens, dists, llsize, *splitpoints, *npoints); 281 1.1 tls } 282 1.1 tls 283 1.1 tls free(done); 284 1.1 tls } 285 1.1 tls 286 1.1 tls void ZopfliBlockSplit(const ZopfliOptions* options, 287 1.1 tls const unsigned char* in, size_t instart, size_t inend, 288 1.1 tls size_t maxblocks, size_t** splitpoints, size_t* npoints) { 289 1.1 tls size_t pos = 0; 290 1.1 tls size_t i; 291 1.1 tls ZopfliBlockState s; 292 1.1 tls size_t* lz77splitpoints = 0; 293 1.1 tls size_t nlz77points = 0; 294 1.1 tls ZopfliLZ77Store store; 295 1.1 tls 296 1.1 tls ZopfliInitLZ77Store(&store); 297 1.1 tls 298 1.1 tls s.options = options; 299 1.1 tls s.blockstart = instart; 300 1.1 tls s.blockend = inend; 301 1.1 tls #ifdef ZOPFLI_LONGEST_MATCH_CACHE 302 1.1 tls s.lmc = 0; 303 1.1 tls #endif 304 1.1 tls 305 1.1 tls *npoints = 0; 306 1.1 tls *splitpoints = 0; 307 1.1 tls 308 1.1 tls /* Unintuitively, Using a simple LZ77 method here instead of ZopfliLZ77Optimal 309 1.1 tls results in better blocks. */ 310 1.1 tls ZopfliLZ77Greedy(&s, in, instart, inend, &store); 311 1.1 tls 312 1.1 tls ZopfliBlockSplitLZ77(options, 313 1.1 tls store.litlens, store.dists, store.size, maxblocks, 314 1.1 tls &lz77splitpoints, &nlz77points); 315 1.1 tls 316 1.1 tls /* Convert LZ77 positions to positions in the uncompressed input. */ 317 1.1 tls pos = instart; 318 1.1 tls if (nlz77points > 0) { 319 1.1 tls for (i = 0; i < store.size; i++) { 320 1.1 tls size_t length = store.dists[i] == 0 ? 1 : store.litlens[i]; 321 1.1 tls if (lz77splitpoints[*npoints] == i) { 322 1.1 tls ZOPFLI_APPEND_DATA(pos, splitpoints, npoints); 323 1.1 tls if (*npoints == nlz77points) break; 324 1.1 tls } 325 1.1 tls pos += length; 326 1.1 tls } 327 1.1 tls } 328 1.1 tls assert(*npoints == nlz77points); 329 1.1 tls 330 1.1 tls free(lz77splitpoints); 331 1.1 tls ZopfliCleanLZ77Store(&store); 332 1.1 tls } 333 1.1 tls 334 1.1 tls void ZopfliBlockSplitSimple(const unsigned char* in, 335 1.1 tls size_t instart, size_t inend, 336 1.1 tls size_t blocksize, 337 1.1 tls size_t** splitpoints, size_t* npoints) { 338 1.1 tls size_t i = instart; 339 1.1 tls while (i < inend) { 340 1.1 tls ZOPFLI_APPEND_DATA(i, splitpoints, npoints); 341 1.1 tls i += blocksize; 342 1.1 tls } 343 1.1 tls (void)in; 344 1.1 tls } 345