1 /++ 2 Provides LZMA (aka .xz) and .tar file read-only support. 3 Combine to read .tar.xz files, or use in conjunction with 4 other files to read other types of .tar files. 5 6 Also has a custom archive called arcz read and write support. 7 It is designed to efficiently pack and randomly access large 8 numbers of similar files. Unlike .zip files, it will do 9 cross-file compression (meaning it can significantly shrink 10 archives with several small but similar files), and unlike 11 tar.gz files, it supports random access without decompressing 12 the whole archive to get an individual file. It is designed 13 for large numbers of small, similar files. 14 +/ 15 module arsd.archive; 16 17 version(WithoutLzmaDecoder) {} else 18 version=WithLzmaDecoder; 19 20 version(WithoutArczCode) {} else 21 version=WithArczCode; 22 23 /+ 24 /++ 25 Reads a tar file and passes the chunks to your handler. Use it like: 26 27 TarFile f = TarFile("filename.tar"); 28 foreach(part; f) { 29 if(part.isNewFile) { 30 31 } 32 } 33 34 FIXME not implemented 35 +/ 36 struct TarFile { 37 this(string filename) { 38 39 } 40 } 41 +/ 42 43 inout(char)[] upToZero(inout(char)[] a) { 44 int i = 0; 45 while(i < a.length && a[i]) i++; 46 return a[0 .. i]; 47 } 48 49 50 /++ 51 A header of a file in the archive. This represents the 52 binary format of the header block. 53 +/ 54 align(512) 55 struct TarFileHeader { 56 align(1): 57 char[100] fileName_ = 0; 58 char[8] fileMode_ = 0; 59 char[8] ownerUid_ = 0; 60 char[8] ownerGid_ = 0; 61 char[12] size_ = 0; // in octal 62 char[12] mtime_ = 0; // octal unix timestamp 63 char[8] checksum_ = 0; // right????? 64 char[1] fileType_ = 0; // hard link, soft link, etc 65 char[100] linkFileName_ = 0; 66 char[6] ustarMagic_ = 0; // if "ustar\0", remaining fields are set 67 char[2] ustarVersion_ = 0; 68 char[32] ownerName_ = 0; 69 char[32] groupName_ = 0; 70 char[8] deviceMajorNumber_ = 0; 71 char[8] deviceMinorNumber_ = 0; 72 char[155] filenamePrefix_ = 0; 73 74 /// Returns the filename. You should cache the return value as long as TarFileHeader is in scope (it returns a slice after calling strlen) 75 const(char)[] filename() { 76 import core.stdc.string; 77 if(filenamePrefix_[0]) 78 return upToZero(filenamePrefix_[]) ~ upToZero(fileName_[]); 79 return upToZero(fileName_[]); 80 } 81 82 /// 83 ulong size() { 84 import core.stdc.stdlib; 85 return strtoul(size_.ptr, null, 8); 86 } 87 88 /// 89 TarFileType type() { 90 if(fileType_[0] == 0) 91 return TarFileType.normal; 92 else 93 return cast(TarFileType) (fileType_[0] - '0'); 94 } 95 } 96 97 /// There's other types but this is all I care about. You can still detect the char by `((cast(char) type) + '0')` 98 enum TarFileType { 99 normal = 0, /// 100 hardLink = 1, /// 101 symLink = 2, /// 102 characterSpecial = 3, /// 103 blockSpecial = 4, /// 104 directory = 5, /// 105 fifo = 6 /// 106 } 107 108 109 110 111 /++ 112 Low level tar file processor. You must pass it a 113 TarFileHeader buffer as well as a size_t for context. 114 Both must be initialized to all zeroes on first call, 115 then not modified in between calls. 116 117 Each call must populate the dataBuffer with 512 bytes. 118 119 returns true if still work to do. 120 +/ 121 bool processTar( 122 TarFileHeader* header, 123 long* bytesRemainingOnCurrentFile, 124 ubyte[] dataBuffer, 125 scope void delegate(TarFileHeader* header, bool isNewFile, bool fileFinished, ubyte[] data) handleData 126 ) 127 { 128 assert(dataBuffer.length == 512); 129 assert(bytesRemainingOnCurrentFile !is null); 130 assert(header !is null); 131 132 if(*bytesRemainingOnCurrentFile) { 133 bool isNew = *bytesRemainingOnCurrentFile == header.size(); 134 if(*bytesRemainingOnCurrentFile <= 512) { 135 handleData(header, isNew, true, dataBuffer[0 .. cast(size_t) *bytesRemainingOnCurrentFile]); 136 *bytesRemainingOnCurrentFile = 0; 137 } else { 138 handleData(header, isNew, false, dataBuffer[]); 139 *bytesRemainingOnCurrentFile -= 512; 140 } 141 } else { 142 *header = *(cast(TarFileHeader*) dataBuffer.ptr); 143 auto s = header.size(); 144 *bytesRemainingOnCurrentFile = s; 145 if(header.type() == TarFileType.directory) 146 handleData(header, true, false, null); 147 if(s == 0 && header.type == TarFileType.normal) 148 return false; 149 } 150 151 return true; 152 } 153 154 /// 155 unittest { 156 void main() { 157 TarFileHeader tfh; 158 long size; 159 160 import std.stdio; 161 ubyte[512] buffer; 162 foreach(chunk; File("/home/me/test/pl.tar", "r").byChunk(buffer[])) { 163 processTar(&tfh, &size, buffer[], 164 (header, isNewFile, fileFinished, data) { 165 if(isNewFile) 166 writeln("**** " , header.filename, " ", header.size); 167 write(cast(string) data); 168 if(fileFinished) 169 writeln("+++++++++++++++"); 170 171 }); 172 } 173 } 174 175 main(); 176 } 177 178 179 ulong readVla(ref ubyte[] data) { 180 ulong n; 181 182 n = data[0] & 0x7f; 183 if(!(data[0] & 0x80)) 184 data = data[1 .. $]; 185 186 int i = 0; 187 while(data[0] & 0x80) { 188 i++; 189 data = data[1 .. $]; 190 191 ubyte b = data[0]; 192 if(b == 0) return 0; 193 194 195 n |= cast(ulong) (b & 0x7F) << (i * 7); 196 } 197 return n; 198 } 199 200 /++ 201 A simple .xz file decoder. 202 203 FIXME: it doesn't implement very many checks, instead 204 assuming things are what it expects. Don't use this without 205 assertions enabled! 206 207 Use it by feeding it xz file data chunks. It will give you 208 back decompressed data chunks; 209 210 BEWARE OF REUSED BUFFERS. See the example. 211 +/ 212 version(WithLzmaDecoder) 213 struct XzDecoder { 214 /++ 215 Start decoding by feeding it some initial data. You must 216 send it at least enough bytes for the header (> 16 bytes prolly); 217 try to send it a reasonably sized chunk. 218 +/ 219 this(ubyte[] initialData) { 220 221 ubyte[6] magic; 222 223 magic[] = initialData[0 .. magic.length]; 224 initialData = initialData[magic.length .. $]; 225 226 if(cast(string) magic != "\xFD7zXZ\0") 227 throw new Exception("not an xz file"); 228 229 ubyte[2] streamFlags = initialData[0 .. 2]; 230 initialData = initialData[2 .. $]; 231 232 // size of the check at the end in the footer. im just ignoring tbh 233 checkSize = streamFlags[1] == 0 ? 0 : (4 << ((streamFlags[1]-1) / 3)); 234 235 //uint crc32 = initialData[0 .. 4]; // FIXME just cast it. this is the crc of the flags. 236 initialData = initialData[4 .. $]; 237 238 239 // now we are into an xz block... 240 241 int blockHeaderSize = (initialData[0] + 1) * 4; 242 243 auto srcPostHeader = initialData[blockHeaderSize .. $]; 244 245 initialData = initialData[1 .. $]; 246 247 ubyte blockFlags = initialData[0]; 248 initialData = initialData[1 .. $]; 249 250 if(blockFlags & 0x40) { 251 compressedSize = readVla(initialData); 252 } 253 254 if(blockFlags & 0x80) { 255 uncompressedSize = readVla(initialData); 256 } 257 258 auto filterCount = (blockFlags & 0b11) + 1; 259 260 ubyte props; 261 262 foreach(f; 0 .. filterCount) { 263 auto fid = readVla(initialData); 264 auto sz = readVla(initialData); 265 266 assert(fid == 0x21); 267 assert(sz == 1); 268 269 props = initialData[0]; 270 initialData = initialData[1 .. $]; 271 } 272 273 //writeln(src.ptr); 274 //writeln(srcPostHeader.ptr); 275 276 // there should be some padding to a multiple of 4... 277 // three bytes of zeroes given the assumptions here 278 279 initialData = initialData[3 .. $]; 280 281 // and then a header crc 282 283 initialData = initialData[4 .. $]; // skip header crc 284 285 assert(initialData.ptr is srcPostHeader.ptr); 286 287 // skip unknown header bytes 288 while(initialData.ptr < srcPostHeader.ptr) { 289 initialData = initialData[1 .. $]; 290 } 291 292 // should finally be at compressed data... 293 294 //writeln(compressedSize); 295 //writeln(uncompressedSize); 296 297 if(Lzma2Dec_Allocate(&lzmaDecoder, props) != SRes.OK) { 298 assert(0); 299 } 300 301 Lzma2Dec_Init(&lzmaDecoder); 302 303 unprocessed = initialData; 304 } 305 306 ~this() { 307 LzmaDec_FreeProbs(&lzmaDecoder.decoder); 308 } 309 310 /++ 311 You tell it where you want the data. 312 313 You must pass it the existing unprocessed data 314 315 Returns slice of dest that is actually filled up so far. 316 +/ 317 ubyte[] processData(ubyte[] dest, ubyte[] src) { 318 319 size_t destLen = dest.length; 320 size_t srcLen = src.length; 321 322 ELzmaStatus status; 323 324 auto res = Lzma2Dec_DecodeToBuf( 325 &lzmaDecoder, 326 dest.ptr, 327 &destLen, 328 src.ptr, 329 &srcLen, 330 LZMA_FINISH_ANY, 331 &status 332 ); 333 334 if(res != 0) { 335 import std.conv; 336 throw new Exception(to!string(res)); 337 } 338 339 /+ 340 import std.stdio; 341 writeln(res, " ", status); 342 writeln(srcLen); 343 writeln(destLen, ": ", cast(string) dest[0 .. destLen]); 344 +/ 345 346 if(status == LZMA_STATUS_NEEDS_MORE_INPUT) { 347 unprocessed = src[srcLen .. $]; 348 finished_ = false; 349 needsMoreData_ = true; 350 } else if(status == LZMA_STATUS_FINISHED_WITH_MARK || status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) { 351 unprocessed = null; 352 finished_ = true; 353 needsMoreData_ = false; 354 } else if(status == LZMA_STATUS_NOT_FINISHED) { 355 unprocessed = src[srcLen .. $]; 356 finished_ = false; 357 needsMoreData_ = false; 358 } else { 359 // wtf 360 import std.conv; 361 assert(0, to!string(status)); 362 } 363 364 return dest[0 .. destLen]; 365 } 366 367 /// 368 bool finished() { 369 return finished_; 370 } 371 372 /// 373 bool needsMoreData() { 374 return needsMoreData_; 375 } 376 377 bool finished_; 378 bool needsMoreData_; 379 380 CLzma2Dec lzmaDecoder; 381 int checkSize; 382 ulong compressedSize; /// 383 ulong uncompressedSize; /// 384 385 ubyte[] unprocessed; /// 386 } 387 388 /// 389 version(WithLzmaDecoder) 390 unittest { 391 392 void main() { 393 ubyte[512] dest; // into tar size chunks! 394 ubyte[1024] src; 395 396 import std.stdio; 397 398 //auto file = File("/home/me/test/amazing.txt.xz", "rb"); 399 auto file = File("/home/me/Android/ldcdl/test.tar.xz", "rb"); 400 auto bfr = file.rawRead(src[]); 401 402 XzDecoder xzd = XzDecoder(bfr); 403 404 // not necessarily set, don't rely on them 405 writeln(xzd.compressedSize, " / ", xzd.uncompressedSize); 406 407 // for tar 408 TarFileHeader tfh; 409 long size; 410 411 long sum = 0; 412 while(!xzd.finished) { 413 // as long as your are not finished, there is more work to do. But it doesn't 414 // necessarily need more data, so that is a separate check. 415 if(xzd.needsMoreData) { 416 // if it needs more data, append new stuff to the end of the buffer, after 417 // the existing unprocessed stuff. If your buffer is too small, you may be 418 // forced to grow it here, but anything >= 1 KB seems OK in my tests. 419 bfr = file.rawRead(src[bfr.length - xzd.unprocessed.length .. $]); 420 } else { 421 // otherwise, you want to continue working with existing unprocessed data 422 bfr = xzd.unprocessed; 423 } 424 //write(cast(string) xzd.processData(dest[], bfr)); 425 426 auto buffer = xzd.processData(dest[], bfr); 427 428 // if the buffer is empty we are probably done 429 // or need more data, so continue the loop to evaluate. 430 if(buffer.length == 0) 431 continue; 432 433 // our tar code requires specifically 512 byte pieces 434 while(!xzd.finished && buffer.length != 512) { 435 // need more data hopefully 436 assert(xzd.needsMoreData); 437 // using the existing buffer... 438 bfr = file.rawRead(src[bfr.length - xzd.unprocessed.length .. $]); 439 auto nbuffer = xzd.processData(dest[buffer.length .. $], bfr); 440 buffer = dest[0 .. buffer.length + nbuffer.length]; 441 } 442 443 sum += buffer.length; 444 445 // process the buffer through the tar file handler 446 processTar(&tfh, &size, buffer[], 447 (header, isNewFile, fileFinished, data) { 448 if(isNewFile) 449 writeln("**** " , header.filename, " ", header.size); 450 //write(cast(string) data); 451 if(fileFinished) 452 writeln("+++++++++++++++"); 453 454 }); 455 } 456 457 writeln(sum); 458 } 459 460 main(); 461 } 462 463 version(WithArczCode) { 464 /* The code in this section was originally written by Ketmar Dark for his arcz.d module. I modified it afterward. */ 465 466 /** ARZ chunked archive format processor. 467 * 468 * This module provides `std.stdio.File`-like interface to ARZ archives. 469 * 470 * Copyright: Copyright Ketmar Dark, 2016 471 * 472 * License: Boost License 1.0 473 */ 474 // module iv.arcz; 475 476 // use Balz compressor if available 477 static if (__traits(compiles, { import iv.balz; })) enum arcz_has_balz = true; else enum arcz_has_balz = false; 478 static if (__traits(compiles, { import iv.zopfli; })) enum arcz_has_zopfli = true; else enum arcz_has_zopfli = false; 479 static if (arcz_has_balz) import iv.balz; 480 static if (arcz_has_zopfli) import iv.zopfli; 481 482 // comment this to free pakced chunk buffer right after using 483 // i.e. `AZFile` will allocate new block for each new chunk 484 //version = arcz_use_more_memory; 485 486 public import core.stdc.stdio : SEEK_SET, SEEK_CUR, SEEK_END; 487 488 489 // ////////////////////////////////////////////////////////////////////////// // 490 /// ARZ archive accessor. Use this to open ARZ archives, and open packed files from ARZ archives. 491 public struct ArzArchive { 492 private: 493 static assert(size_t.sizeof >= (void*).sizeof); 494 private import core.stdc.stdio : FILE, fopen, fclose, fread, fseek; 495 private import etc.c.zlib; 496 497 static struct ChunkInfo { 498 uint ofs; // offset in file 499 uint pksize; // packed chunk size (same as chunk size: chunk is unpacked) 500 } 501 502 static struct FileInfo { 503 string name; 504 uint chunk; 505 uint chunkofs; // offset of first file byte in unpacked chunk 506 uint size; // unpacked file size 507 } 508 509 static struct Nfo { 510 uint rc = 1; // refcounter 511 ChunkInfo[] chunks; 512 FileInfo[string] files; 513 uint chunkSize; 514 uint lastChunkSize; 515 bool useBalz; 516 FILE* afl; // archive file, we'll keep it opened 517 518 @disable this (this); // no copies! 519 520 static void decRef (size_t me) { 521 if (me) { 522 auto nfo = cast(Nfo*)me; 523 assert(nfo.rc); 524 if (--nfo.rc == 0) { 525 import core.memory : GC; 526 import core.stdc.stdlib : free; 527 if (nfo.afl !is null) fclose(nfo.afl); 528 nfo.chunks.destroy; 529 nfo.files.destroy; 530 nfo.afl = null; 531 GC.removeRange(cast(void*)nfo/*, Nfo.sizeof*/); 532 free(nfo); 533 debug(arcz_rc) { import core.stdc.stdio : printf; printf("Nfo %p freed\n", nfo); } 534 } 535 } 536 } 537 } 538 539 size_t nfop; // hide it from GC 540 541 private @property Nfo* nfo () { pragma(inline, true); return cast(Nfo*)nfop; } 542 void decRef () { pragma(inline, true); Nfo.decRef(nfop); nfop = 0; } 543 544 static uint readUint (FILE* fl) { 545 if (fl is null) throw new Exception("cannot read from closed file"); 546 uint v; 547 if (fread(&v, 1, v.sizeof, fl) != v.sizeof) throw new Exception("file reading error"); 548 version(BigEndian) { 549 import core.bitop : bswap; 550 v = bswap(v); 551 } else version(LittleEndian) { 552 // nothing to do 553 } else { 554 static assert(0, "wtf?!"); 555 } 556 return v; 557 } 558 559 static uint readUbyte (FILE* fl) { 560 if (fl is null) throw new Exception("cannot read from closed file"); 561 ubyte v; 562 if (fread(&v, 1, v.sizeof, fl) != v.sizeof) throw new Exception("file reading error"); 563 return v; 564 } 565 566 static void readBuf (FILE* fl, void[] buf) { 567 if (buf.length > 0) { 568 if (fl is null) throw new Exception("cannot read from closed file"); 569 if (fread(buf.ptr, 1, buf.length, fl) != buf.length) throw new Exception("file reading error"); 570 } 571 } 572 573 static T* xalloc(T, bool clear=true) (uint mem) if (T.sizeof > 0) { 574 import core.exception : onOutOfMemoryError; 575 assert(mem != 0); 576 static if (clear) { 577 import core.stdc.stdlib : calloc; 578 auto res = calloc(mem, T.sizeof); 579 if (res is null) onOutOfMemoryError(); 580 static if (is(T == struct)) { 581 import core.stdc.string : memcpy; 582 static immutable T i = T.init; 583 foreach (immutable idx; 0..mem) memcpy(res+idx, &i, T.sizeof); 584 } 585 debug(arcz_alloc) { import core.stdc.stdio : printf; printf("allocated %u bytes at %p\n", cast(uint)(mem*T.sizeof), res); } 586 return cast(T*)res; 587 } else { 588 import core.stdc.stdlib : malloc; 589 auto res = malloc(mem*T.sizeof); 590 if (res is null) onOutOfMemoryError(); 591 static if (is(T == struct)) { 592 import core.stdc.string : memcpy; 593 static immutable T i = T.init; 594 foreach (immutable idx; 0..mem) memcpy(res+idx, &i, T.sizeof); 595 } 596 debug(arcz_alloc) { import core.stdc.stdio : printf; printf("allocated %u bytes at %p\n", cast(uint)(mem*T.sizeof), res); } 597 return cast(T*)res; 598 } 599 } 600 601 static void xfree(T) (T* ptr) { 602 if (ptr !is null) { 603 import core.stdc.stdlib : free; 604 debug(arcz_alloc) { import core.stdc.stdio : printf; printf("freing at %p\n", ptr); } 605 free(ptr); 606 } 607 } 608 609 static if (arcz_has_balz) static ubyte balzDictSize (uint blockSize) { 610 foreach (ubyte bits; Balz.MinDictBits..Balz.MaxDictBits+1) { 611 if ((1U<<bits) >= blockSize) return bits; 612 } 613 return Balz.MaxDictBits; 614 } 615 616 // unpack exactly `destlen` bytes 617 static if (arcz_has_balz) static void unpackBlockBalz (void* dest, uint destlen, const(void)* src, uint srclen, uint blocksize) { 618 Unbalz bz; 619 bz.reinit(balzDictSize(blocksize)); 620 int ipos, opos; 621 auto dc = bz.decompress( 622 // reader 623 (buf) { 624 import core.stdc.string : memcpy; 625 if (ipos >= srclen) return 0; 626 uint rd = destlen-ipos; 627 if (rd > buf.length) rd = cast(uint)buf.length; 628 memcpy(buf.ptr, src+ipos, rd); 629 ipos += rd; 630 return rd; 631 }, 632 // writer 633 (buf) { 634 //if (opos+buf.length > destlen) throw new Exception("error unpacking archive"); 635 uint wr = destlen-opos; 636 if (wr > buf.length) wr = cast(uint)buf.length; 637 if (wr > 0) { 638 import core.stdc.string : memcpy; 639 memcpy(dest+opos, buf.ptr, wr); 640 opos += wr; 641 } 642 }, 643 // unpack length 644 destlen 645 ); 646 if (opos != destlen) throw new Exception("error unpacking archive"); 647 } 648 649 static void unpackBlockZLib (void* dest, uint destlen, const(void)* src, uint srclen, uint blocksize) { 650 z_stream zs; 651 zs.avail_in = 0; 652 zs.avail_out = 0; 653 // initialize unpacker 654 if (inflateInit2(&zs, 15) != Z_OK) throw new Exception("can't initialize zlib"); 655 scope(exit) inflateEnd(&zs); 656 zs.next_in = cast(typeof(zs.next_in))src; 657 zs.avail_in = srclen; 658 zs.next_out = cast(typeof(zs.next_out))dest; 659 zs.avail_out = destlen; 660 while (zs.avail_out > 0) { 661 auto err = inflate(&zs, Z_SYNC_FLUSH); 662 if (err != Z_STREAM_END && err != Z_OK) throw new Exception("error unpacking archive"); 663 if (err == Z_STREAM_END) break; 664 } 665 if (zs.avail_out != 0) throw new Exception("error unpacking archive"); 666 } 667 668 static void unpackBlock (void* dest, uint destlen, const(void)* src, uint srclen, uint blocksize, bool useBalz) { 669 if (useBalz) { 670 static if (arcz_has_balz) { 671 unpackBlockBalz(dest, destlen, src, srclen, blocksize); 672 } else { 673 throw new Exception("no Balz support was compiled in ArcZ"); 674 } 675 } else { 676 unpackBlockZLib(dest, destlen, src, srclen, blocksize); 677 } 678 } 679 680 public: 681 this (in ArzArchive arc) { 682 assert(nfop == 0); 683 nfop = arc.nfop; 684 if (nfop) ++nfo.rc; 685 } 686 687 this (this) { 688 if (nfop) ++nfo.rc; 689 } 690 691 ~this () { close(); } 692 693 void opAssign (in ArzArchive arc) { 694 if (arc.nfop) { 695 auto n = cast(Nfo*)arc.nfop; 696 ++n.rc; 697 } 698 decRef(); 699 nfop = arc.nfop; 700 } 701 702 void close () { decRef(); } 703 704 @property FileInfo[string] files () { return (nfop ? nfo.files : null); } 705 706 void openArchive (const(char)[] filename) { 707 debug/*(arcz)*/ import core.stdc.stdio : printf; 708 FILE* fl = null; 709 scope(exit) if (fl !is null) fclose(fl); 710 close(); 711 if (filename.length == 0) throw new Exception("cannot open unnamed archive file"); 712 if (false && filename.length < 2048) { // FIXME the alloca fails on win64 for some reason 713 import core.stdc.stdlib : alloca; 714 auto tfn = (cast(char*)alloca(filename.length+1))[0..filename.length+1]; 715 tfn[0..filename.length] = filename[]; 716 tfn[filename.length] = 0; 717 fl = fopen(tfn.ptr, "rb"); 718 } else { 719 import core.stdc.stdlib : malloc, free; 720 auto tfn = (cast(char*)malloc(filename.length+1))[0..filename.length+1]; 721 if (tfn !is null) { 722 scope(exit) free(tfn.ptr); 723 fl = fopen(tfn.ptr, "rb"); 724 } 725 } 726 if (fl is null) throw new Exception("cannot open archive file '"~filename.idup~"'"); 727 char[4] sign; 728 bool useBalz; 729 readBuf(fl, sign[]); 730 if (sign != "CZA2") throw new Exception("invalid archive file '"~filename.idup~"'"); 731 switch (readUbyte(fl)) { 732 case 0: useBalz = false; break; 733 case 1: useBalz = true; break; 734 default: throw new Exception("invalid version of archive file '"~filename.idup~"'"); 735 } 736 uint indexofs = readUint(fl); // index offset in file 737 uint pkidxsize = readUint(fl); // packed index size 738 uint idxsize = readUint(fl); // unpacked index size 739 if (pkidxsize == 0 || idxsize == 0 || indexofs == 0) throw new Exception("invalid archive file '"~filename.idup~"'"); 740 // now read index 741 ubyte* idxbuf = null; 742 scope(exit) xfree(idxbuf); 743 { 744 auto pib = xalloc!ubyte(pkidxsize); 745 scope(exit) xfree(pib); 746 if (fseek(fl, indexofs, 0) < 0) throw new Exception("seek error in archive file '"~filename.idup~"'"); 747 readBuf(fl, pib[0..pkidxsize]); 748 idxbuf = xalloc!ubyte(idxsize); 749 unpackBlock(idxbuf, idxsize, pib, pkidxsize, idxsize, useBalz); 750 } 751 752 // parse index and build structures 753 uint idxbufpos = 0; 754 755 ubyte getUbyte () { 756 if (idxsize-idxbufpos < ubyte.sizeof) throw new Exception("invalid index for archive file '"~filename.idup~"'"); 757 return idxbuf[idxbufpos++]; 758 } 759 760 uint getUint () { 761 if (idxsize-idxbufpos < uint.sizeof) throw new Exception("invalid index for archive file '"~filename.idup~"'"); 762 version(BigEndian) { 763 import core.bitop : bswap; 764 uint v = *cast(uint*)(idxbuf+idxbufpos); 765 idxbufpos += 4; 766 return bswap(v); 767 } else version(LittleEndian) { 768 uint v = *cast(uint*)(idxbuf+idxbufpos); 769 idxbufpos += 4; 770 return v; 771 } else { 772 static assert(0, "wtf?!"); 773 } 774 } 775 776 void getBuf (void[] buf) { 777 if (buf.length > 0) { 778 import core.stdc.string : memcpy; 779 if (idxsize-idxbufpos < buf.length) throw new Exception("invalid index for archive file '"~filename.idup~"'"); 780 memcpy(buf.ptr, idxbuf+idxbufpos, buf.length); 781 idxbufpos += buf.length; 782 } 783 } 784 785 // allocate shared info struct 786 Nfo* nfo = xalloc!Nfo(1); 787 assert(nfo.rc == 1); 788 debug(arcz_rc) { import core.stdc.stdio : printf; printf("Nfo %p allocated\n", nfo); } 789 scope(failure) decRef(); 790 nfop = cast(size_t)nfo; 791 { 792 import core.memory : GC; 793 GC.addRange(nfo, Nfo.sizeof); 794 } 795 796 // read chunk info and data 797 nfo.useBalz = useBalz; 798 nfo.chunkSize = getUint; 799 auto ccount = getUint; // chunk count 800 nfo.lastChunkSize = getUint; 801 debug(arcz_dirread) printf("chunk size: %u\nchunk count: %u\nlast chunk size:%u\n", nfo.chunkSize, ccount, nfo.lastChunkSize); 802 if (ccount == 0 || nfo.chunkSize < 1 || nfo.lastChunkSize < 1 || nfo.lastChunkSize > nfo.chunkSize) throw new Exception("invalid archive file '"~filename.idup~"'"); 803 nfo.chunks.length = ccount; 804 // chunk offsets and sizes 805 foreach (ref ci; nfo.chunks) { 806 ci.ofs = getUint; 807 ci.pksize = getUint; 808 } 809 // read file count and info 810 auto fcount = getUint; 811 if (fcount == 0) throw new Exception("empty archive file '"~filename.idup~"'"); 812 // calc name buffer position and size 813 //immutable uint nbofs = idxbufpos+fcount*(5*4); 814 //if (nbofs >= idxsize) throw new Exception("invalid index in archive file '"~filename.idup~"'"); 815 //immutable uint nbsize = idxsize-nbofs; 816 debug(arcz_dirread) printf("file count: %u\n", fcount); 817 foreach (immutable _; 0..fcount) { 818 uint nameofs = getUint; 819 uint namelen = getUint; 820 if (namelen == 0) { 821 // skip unnamed file 822 //throw new Exception("invalid archive file '"~filename.idup~"'"); 823 getUint; // chunk number 824 getUint; // offset in chunk 825 getUint; // unpacked size 826 debug(arcz_dirread) printf("skipped empty file\n"); 827 } else { 828 //if (nameofs >= nbsize || namelen > nbsize || nameofs+namelen > nbsize) throw new Exception("invalid index in archive file '"~filename.idup~"'"); 829 if (nameofs >= idxsize || namelen > idxsize || nameofs+namelen > idxsize) throw new Exception("invalid index in archive file '"~filename.idup~"'"); 830 FileInfo fi; 831 auto nb = new char[](namelen); 832 nb[0..namelen] = (cast(char*)idxbuf)[nameofs..nameofs+namelen]; 833 fi.name = cast(string)(nb); // it is safe here 834 fi.chunk = getUint; // chunk number 835 fi.chunkofs = getUint; // offset in chunk 836 fi.size = getUint; // unpacked size 837 debug(arcz_dirread) printf("file size: %u\nfile chunk: %u\noffset in chunk:%u; name: [%.*s]\n", fi.size, fi.chunk, fi.chunkofs, cast(uint)fi.name.length, fi.name.ptr); 838 nfo.files[fi.name] = fi; 839 } 840 } 841 // transfer achive file ownership 842 nfo.afl = fl; 843 fl = null; 844 } 845 846 bool exists (const(char)[] name) { if (nfop) return ((name in nfo.files) !is null); else return false; } 847 848 AZFile open (const(char)[] name) { 849 if (!nfop) throw new Exception("can't open file from non-opened archive"); 850 if (auto fi = name in nfo.files) { 851 auto zl = xalloc!LowLevelPackedRO(1); 852 scope(failure) xfree(zl); 853 debug(arcz_rc) { import core.stdc.stdio : printf; printf("Zl %p allocated\n", zl); } 854 zl.setup(nfo, fi.chunk, fi.chunkofs, fi.size); 855 AZFile fl; 856 fl.zlp = cast(size_t)zl; 857 return fl; 858 } 859 throw new Exception("can't open file '"~name.idup~"' from archive"); 860 } 861 862 private: 863 static struct LowLevelPackedRO { 864 private import etc.c.zlib; 865 866 uint rc = 1; 867 size_t nfop; // hide it from GC 868 869 private @property inout(Nfo*) nfo () inout pure nothrow @trusted @nogc { pragma(inline, true); return cast(typeof(return))nfop; } 870 static void decRef (size_t me) { 871 if (me) { 872 auto zl = cast(LowLevelPackedRO*)me; 873 assert(zl.rc); 874 if (--zl.rc == 0) { 875 import core.stdc.stdlib : free; 876 if (zl.chunkData !is null) free(zl.chunkData); 877 version(arcz_use_more_memory) if (zl.pkdata !is null) free(zl.pkdata); 878 Nfo.decRef(zl.nfop); 879 free(zl); 880 debug(arcz_rc) { import core.stdc.stdio : printf; printf("Zl %p freed\n", zl); } 881 } else { 882 //debug(arcz_rc) { import core.stdc.stdio : printf; printf("Zl %p; rc after decRef is %u\n", zl, zl.rc); } 883 } 884 } 885 } 886 887 uint nextchunk; // next chunk to read 888 uint curcpos; // position in current chunk 889 uint curcsize; // number of valid bytes in `chunkData` 890 uint stchunk; // starting chunk 891 uint stofs; // offset in starting chunk 892 uint totalsize; // total file size 893 uint pos; // current file position 894 uint lastrdpos; // last actual read position 895 z_stream zs; 896 ubyte* chunkData; // can be null 897 version(arcz_use_more_memory) { 898 ubyte* pkdata; 899 uint pkdatasize; 900 } 901 902 @disable this (this); 903 904 void setup (Nfo* anfo, uint astchunk, uint astofs, uint asize) { 905 assert(anfo !is null); 906 assert(rc == 1); 907 nfop = cast(size_t)anfo; 908 ++anfo.rc; 909 nextchunk = stchunk = astchunk; 910 //curcpos = 0; 911 stofs = astofs; 912 totalsize = asize; 913 } 914 915 @property bool eof () { pragma(inline, true); return (pos >= totalsize); } 916 917 // return less than chunk size if our file fits in one non-full chunk completely 918 uint justEnoughMemory () pure const nothrow @safe @nogc { 919 pragma(inline, true); 920 version(none) { 921 return nfo.chunkSize; 922 } else { 923 return (totalsize < nfo.chunkSize && stofs+totalsize < nfo.chunkSize ? stofs+totalsize : nfo.chunkSize); 924 } 925 } 926 927 void unpackNextChunk () { 928 if (nfop == 0) assert(0, "wtf?!"); 929 //scope(failure) if (chunkData !is null) { xfree(chunkData); chunkData = null; } 930 debug(arcz_unp) { import core.stdc.stdio : printf; printf("unpacking chunk %u\n", nextchunk); } 931 // allocate buffer for unpacked data 932 if (chunkData is null) { 933 // optimize things a little: if our file fits in less then one chunk, allocate "just enough" memory 934 chunkData = xalloc!(ubyte, false)(justEnoughMemory); 935 } 936 auto chunk = &nfo.chunks[nextchunk]; 937 if (chunk.pksize == nfo.chunkSize) { 938 // unpacked chunk, just read it 939 debug(arcz_unp) { import core.stdc.stdio : printf; printf(" chunk is not packed\n"); } 940 if (fseek(nfo.afl, chunk.ofs, 0) < 0) throw new Exception("ARCZ reading error"); 941 if (fread(chunkData, 1, nfo.chunkSize, nfo.afl) != nfo.chunkSize) throw new Exception("ARCZ reading error"); 942 curcsize = nfo.chunkSize; 943 } else { 944 // packed chunk, unpack it 945 // allocate buffer for packed data 946 version(arcz_use_more_memory) { 947 import core.stdc.stdlib : realloc; 948 if (pkdatasize < chunk.pksize) { 949 import core.exception : onOutOfMemoryError; 950 auto newpk = realloc(pkdata, chunk.pksize); 951 if (newpk is null) onOutOfMemoryError(); 952 debug(arcz_alloc) { import core.stdc.stdio : printf; printf("reallocated from %u to %u bytes; %p -> %p\n", cast(uint)pkdatasize, cast(uint)chunk.pksize, pkdata, newpk); } 953 pkdata = cast(ubyte*)newpk; 954 pkdatasize = chunk.pksize; 955 } 956 alias pkd = pkdata; 957 } else { 958 auto pkd = xalloc!(ubyte, false)(chunk.pksize); 959 scope(exit) xfree(pkd); 960 } 961 if (fseek(nfo.afl, chunk.ofs, 0) < 0) throw new Exception("ARCZ reading error"); 962 if (fread(pkd, 1, chunk.pksize, nfo.afl) != chunk.pksize) throw new Exception("ARCZ reading error"); 963 uint upsize = (nextchunk == nfo.chunks.length-1 ? nfo.lastChunkSize : nfo.chunkSize); // unpacked chunk size 964 immutable uint cksz = upsize; 965 immutable uint jem = justEnoughMemory; 966 if (upsize > jem) upsize = jem; 967 debug(arcz_unp) { import core.stdc.stdio : printf; printf(" unpacking %u bytes to %u bytes\n", chunk.pksize, upsize); } 968 ArzArchive.unpackBlock(chunkData, upsize, pkd, chunk.pksize, cksz, nfo.useBalz); 969 curcsize = upsize; 970 } 971 curcpos = 0; 972 // fix first chunk offset if necessary 973 if (nextchunk == stchunk && stofs > 0) { 974 // it's easier to just memmove it 975 import core.stdc.string : memmove; 976 assert(stofs < curcsize); 977 memmove(chunkData, chunkData+stofs, curcsize-stofs); 978 curcsize -= stofs; 979 } 980 ++nextchunk; // advance to next chunk 981 } 982 983 void syncReadPos () { 984 if (pos >= totalsize || pos == lastrdpos) return; 985 immutable uint fcdata = nfo.chunkSize-stofs; // number of our bytes in the first chunk 986 // does our pos lie in the first chunk? 987 if (pos < fcdata) { 988 // yep, just read it 989 if (nextchunk != stchunk+1) { 990 nextchunk = stchunk; 991 unpackNextChunk(); // we'll need it anyway 992 } else { 993 // just rewind 994 curcpos = 0; 995 } 996 curcpos += pos; 997 lastrdpos = pos; 998 return; 999 } 1000 // find the chunk we want 1001 uint npos = pos-fcdata; 1002 uint xblock = stchunk+1+npos/nfo.chunkSize; 1003 uint curcstart = (xblock-(stchunk+1))*nfo.chunkSize+fcdata; 1004 if (xblock != nextchunk-1) { 1005 // read and unpack this chunk 1006 nextchunk = xblock; 1007 unpackNextChunk(); 1008 } else { 1009 // just rewind 1010 curcpos = 0; 1011 } 1012 assert(pos >= curcstart && pos < curcstart+nfo.chunkSize); 1013 uint skip = pos-curcstart; 1014 lastrdpos = pos; 1015 curcpos += skip; 1016 } 1017 1018 int read (void* buf, uint count) { 1019 if (buf is null) return -1; 1020 if (count == 0 || totalsize == 0) return 0; 1021 if (totalsize >= 0 && pos >= totalsize) return 0; // EOF 1022 syncReadPos(); 1023 assert(lastrdpos == pos); 1024 if (cast(long)pos+count > totalsize) count = totalsize-pos; 1025 auto res = count; 1026 while (count > 0) { 1027 debug(arcz_read) { import core.stdc.stdio : printf; printf("reading %u bytes; pos=%u; lastrdpos=%u; curcpos=%u; curcsize=%u\n", count, pos, lastrdpos, curcpos, curcsize); } 1028 import core.stdc.string : memcpy; 1029 if (curcpos >= curcsize) { 1030 unpackNextChunk(); // we want next chunk! 1031 debug(arcz_read) { import core.stdc.stdio : printf; printf(" *reading %u bytes; pos=%u; lastrdpos=%u; curcpos=%u; curcsize=%u\n", count, pos, lastrdpos, curcpos, curcsize); } 1032 } 1033 assert(curcpos < curcsize && curcsize != 0); 1034 int rd = (curcsize-curcpos >= count ? count : curcsize-curcpos); 1035 assert(rd > 0); 1036 memcpy(buf, chunkData+curcpos, rd); 1037 curcpos += rd; 1038 pos += rd; 1039 lastrdpos += rd; 1040 buf += rd; 1041 count -= rd; 1042 } 1043 assert(pos == lastrdpos); 1044 return res; 1045 } 1046 1047 long lseek (long ofs, int origin) { 1048 //TODO: overflow checks 1049 switch (origin) { 1050 case SEEK_SET: break; 1051 case SEEK_CUR: ofs += pos; break; 1052 case SEEK_END: 1053 if (ofs > 0) ofs = 0; 1054 if (-ofs > totalsize) ofs = -cast(long)totalsize; 1055 ofs += totalsize; 1056 break; 1057 default: 1058 return -1; 1059 } 1060 if (ofs < 0) return -1; 1061 if (totalsize >= 0 && ofs > totalsize) ofs = totalsize; 1062 pos = cast(uint)ofs; 1063 return pos; 1064 } 1065 } 1066 } 1067 1068 1069 // ////////////////////////////////////////////////////////////////////////// // 1070 /// Opened file. 1071 public struct AZFile { 1072 private: 1073 size_t zlp; 1074 1075 private @property inout(ArzArchive.LowLevelPackedRO)* zl () inout pure nothrow @trusted @nogc { pragma(inline, true); return cast(typeof(return))zlp; } 1076 private void decRef () { pragma(inline, true); ArzArchive.LowLevelPackedRO.decRef(zlp); zlp = 0; } 1077 1078 public: 1079 this (in AZFile afl) { 1080 assert(zlp == 0); 1081 zlp = afl.zlp; 1082 if (zlp) ++zl.rc; 1083 } 1084 1085 this (this) { 1086 if (zlp) ++zl.rc; 1087 } 1088 1089 ~this () { close(); } 1090 1091 void opAssign (in AZFile afl) { 1092 if (afl.zlp) { 1093 auto n = cast(ArzArchive.LowLevelPackedRO*)afl.zlp; 1094 ++n.rc; 1095 } 1096 decRef(); 1097 zlp = afl.zlp; 1098 } 1099 1100 void close () { decRef(); } 1101 1102 @property bool isOpen () const pure nothrow @safe @nogc { pragma(inline, true); return (zlp != 0); } 1103 @property uint size () const pure nothrow @safe @nogc { pragma(inline, true); return (zlp ? zl.totalsize : 0); } 1104 @property uint tell () const pure nothrow @safe @nogc { pragma(inline, true); return (zlp ? zl.pos : 0); } 1105 1106 void seek (long ofs, int origin=SEEK_SET) { 1107 if (!zlp) throw new Exception("can't seek in closed file"); 1108 auto res = zl.lseek(ofs, origin); 1109 if (res < 0) throw new Exception("seek error"); 1110 } 1111 1112 private import std.traits : isMutable; 1113 1114 //TODO: overflow check 1115 T[] rawRead(T) (T[] buf) if (isMutable!T) { 1116 if (!zlp) throw new Exception("can't read from closed file"); 1117 if (buf.length > 0) { 1118 auto res = zl.read(buf.ptr, cast(int) (buf.length*T.sizeof)); 1119 if (res == -1 || res%T.sizeof != 0) throw new Exception("read error"); 1120 return buf[0..res/T.sizeof]; 1121 } else { 1122 return buf[0..0]; 1123 } 1124 } 1125 } 1126 1127 1128 // ////////////////////////////////////////////////////////////////////////// // 1129 /** this class can be used to create archive file. 1130 * 1131 * Example: 1132 * -------------------- 1133 * import std.file, std.path, std.stdio : File; 1134 * 1135 * enum ArcName = "z00.arz"; 1136 * enum DirName = "experimental-docs"; 1137 * 1138 * ubyte[] rdbuf; 1139 * rdbuf.length = 65536; 1140 * 1141 * auto arcz = new ArzCreator(ArcName); 1142 * long total = 0; 1143 * foreach (DirEntry e; dirEntries(DirName, SpanMode.breadth)) { 1144 * if (e.isFile) { 1145 * assert(e.size < uint.max); 1146 * //writeln(e.name); 1147 * total += e.size; 1148 * string fname = e.name[DirName.length+1..$]; 1149 * arcz.newFile(fname, cast(uint)e.size); 1150 * auto fi = File(e.name); 1151 * for (;;) { 1152 * auto rd = fi.rawRead(rdbuf[]); 1153 * if (rd.length == 0) break; 1154 * arcz.rawWrite(rd[]); 1155 * } 1156 * } 1157 * } 1158 * arcz.close(); 1159 * writeln(total, " bytes packed to ", getSize(ArcName), " (", arcz.chunksWritten, " chunks, ", arcz.filesWritten, " files)"); 1160 * -------------------- 1161 */ 1162 final class ArzCreator { 1163 private import etc.c.zlib; 1164 private import core.stdc.stdio : FILE, fopen, fclose, ftell, fseek, fwrite; 1165 1166 public: 1167 //WARNING! don't change the order! 1168 enum Compressor { 1169 ZLib, // default 1170 Balz, 1171 BalzMax, // Balz, maximum compression 1172 Zopfli, // this will fallback to zlib if no zopfli support was compiled in 1173 } 1174 1175 private: 1176 static struct ChunkInfo { 1177 uint ofs; // offset in file 1178 uint pksize; // packed chunk size 1179 } 1180 1181 static struct FileInfo { 1182 string name; 1183 uint chunk; 1184 uint chunkofs; // offset of first file byte in unpacked chunk 1185 uint size; // unpacked file size 1186 } 1187 1188 private: 1189 ubyte[] chunkdata; 1190 uint cdpos; 1191 FILE* arcfl; 1192 ChunkInfo[] chunks; 1193 FileInfo[] files; 1194 uint lastChunkSize; 1195 uint statChunks, statFiles; 1196 Compressor cpr = Compressor.ZLib; 1197 1198 private: 1199 void writeUint (uint v) { 1200 if (arcfl is null) throw new Exception("write error"); 1201 version(BigEndian) { 1202 import core.bitop : bswap; 1203 v = bswap(v); 1204 } else version(LittleEndian) { 1205 // nothing to do 1206 } else { 1207 static assert(0, "wtf?!"); 1208 } 1209 if (fwrite(&v, 1, v.sizeof, arcfl) != v.sizeof) throw new Exception("write error"); // signature 1210 } 1211 1212 void writeUbyte (ubyte v) { 1213 if (arcfl is null) throw new Exception("write error"); 1214 if (fwrite(&v, 1, v.sizeof, arcfl) != v.sizeof) throw new Exception("write error"); // signature 1215 } 1216 1217 void writeBuf (const(void)[] buf) { 1218 if (buf.length > 0) { 1219 if (arcfl is null) throw new Exception("write error"); 1220 if (fwrite(buf.ptr, 1, buf.length, arcfl) != buf.length) throw new Exception("write error"); // signature 1221 } 1222 } 1223 1224 static if (arcz_has_balz) long writePackedBalz (const(void)[] upbuf) { 1225 assert(upbuf.length > 0 && upbuf.length < int.max); 1226 long res = 0; 1227 Balz bz; 1228 int ipos, opos; 1229 bz.reinit(ArzArchive.balzDictSize(cast(uint)upbuf.length)); 1230 bz.compress( 1231 // reader 1232 (buf) { 1233 import core.stdc.string : memcpy; 1234 if (ipos >= upbuf.length) return 0; 1235 uint rd = cast(uint)upbuf.length-ipos; 1236 if (rd > buf.length) rd = cast(uint)buf.length; 1237 memcpy(buf.ptr, upbuf.ptr+ipos, rd); 1238 ipos += rd; 1239 return rd; 1240 }, 1241 // writer 1242 (buf) { 1243 res += buf.length; 1244 writeBuf(buf[]); 1245 }, 1246 // max mode 1247 (cpr == Compressor.BalzMax) 1248 ); 1249 return res; 1250 } 1251 1252 static if (arcz_has_zopfli) long writePackedZopfli (const(void)[] upbuf) { 1253 ubyte[] indata; 1254 void* odata; 1255 size_t osize; 1256 ZopfliOptions opts; 1257 ZopfliCompress(opts, ZOPFLI_FORMAT_ZLIB, upbuf.ptr, upbuf.length, &odata, &osize); 1258 writeBuf(odata[0..osize]); 1259 ZopfliFree(odata); 1260 return cast(long)osize; 1261 } 1262 1263 long writePackedZLib (const(void)[] upbuf) { 1264 assert(upbuf.length > 0 && upbuf.length < int.max); 1265 long res = 0; 1266 z_stream zs; 1267 ubyte[2048] obuf; 1268 zs.next_out = obuf.ptr; 1269 zs.avail_out = cast(uint)obuf.length; 1270 zs.next_in = null; 1271 zs.avail_in = 0; 1272 // initialize packer 1273 if (deflateInit2(&zs, Z_BEST_COMPRESSION, Z_DEFLATED, 15, 9, 0) != Z_OK) throw new Exception("can't write packed data"); 1274 scope(exit) deflateEnd(&zs); 1275 zs.next_in = cast(typeof(zs.next_in))upbuf.ptr; 1276 zs.avail_in = cast(uint)upbuf.length; 1277 while (zs.avail_in > 0) { 1278 if (zs.avail_out == 0) { 1279 res += cast(uint)obuf.length; 1280 writeBuf(obuf[]); 1281 zs.next_out = obuf.ptr; 1282 zs.avail_out = cast(uint)obuf.length; 1283 } 1284 auto err = deflate(&zs, Z_NO_FLUSH); 1285 if (err != Z_OK) throw new Exception("zlib compression error"); 1286 } 1287 while (zs.avail_out != obuf.length) { 1288 res += cast(uint)obuf.length-zs.avail_out; 1289 writeBuf(obuf[0..$-zs.avail_out]); 1290 zs.next_out = obuf.ptr; 1291 zs.avail_out = cast(uint)obuf.length; 1292 auto err = deflate(&zs, Z_FINISH); 1293 if (err != Z_OK && err != Z_STREAM_END) throw new Exception("zlib compression error"); 1294 // succesfully flushed? 1295 //if (err != Z_STREAM_END) throw new VFSException("zlib compression error"); 1296 } 1297 return res; 1298 } 1299 1300 // return size of packed data written 1301 uint writePackedBuf (const(void)[] upbuf) { 1302 assert(upbuf.length > 0 && upbuf.length < int.max); 1303 long res = 0; 1304 final switch (cpr) { 1305 case Compressor.ZLib: 1306 res = writePackedZLib(upbuf); 1307 break; 1308 case Compressor.Balz: 1309 case Compressor.BalzMax: 1310 static if (arcz_has_balz) { 1311 res = writePackedBalz(upbuf); 1312 break; 1313 } else { 1314 throw new Exception("no Balz support was compiled in ArcZ"); 1315 } 1316 case Compressor.Zopfli: 1317 static if (arcz_has_zopfli) { 1318 res = writePackedZopfli(upbuf); 1319 //break; 1320 } else { 1321 //new Exception("no Zopfli support was compiled in ArcZ"); 1322 res = writePackedZLib(upbuf); 1323 } 1324 break; 1325 } 1326 if (res > uint.max) throw new Exception("output archive too big"); 1327 return cast(uint)res; 1328 } 1329 1330 void flushData () { 1331 if (cdpos > 0) { 1332 ChunkInfo ci; 1333 auto pos = ftell(arcfl); 1334 if (pos < 0 || pos >= uint.max) throw new Exception("output archive too big"); 1335 ci.ofs = cast(uint)pos; 1336 auto wlen = writePackedBuf(chunkdata[0..cdpos]); 1337 ci.pksize = wlen; 1338 if (cdpos == chunkdata.length && ci.pksize >= chunkdata.length) { 1339 // wow, this chunk is unpackable 1340 //{ import std.stdio; writeln("unpackable chunk found!"); } 1341 if (fseek(arcfl, pos, 0) < 0) throw new Exception("can't seek in output file"); 1342 writeBuf(chunkdata[0..cdpos]); 1343 version(Posix) { 1344 import core.stdc.stdio : fileno; 1345 import core.sys.posix.unistd : ftruncate; 1346 pos = ftell(arcfl); 1347 if (pos < 0 || pos >= uint.max) throw new Exception("output archive too big"); 1348 if (ftruncate(fileno(arcfl), cast(uint)pos) < 0) throw new Exception("error truncating output file"); 1349 } 1350 ci.pksize = cdpos; 1351 } 1352 if (cdpos < chunkdata.length) lastChunkSize = cast(uint)cdpos; 1353 cdpos = 0; 1354 chunks ~= ci; 1355 } else { 1356 lastChunkSize = cast(uint)chunkdata.length; 1357 } 1358 } 1359 1360 void closeArc () { 1361 flushData(); 1362 // write index 1363 //assert(ftell(arcfl) > 0 && ftell(arcfl) < uint.max); 1364 assert(chunkdata.length < uint.max); 1365 assert(chunks.length < uint.max); 1366 assert(files.length < uint.max); 1367 // create index in memory 1368 ubyte[] index; 1369 1370 void putUint (uint v) { 1371 index ~= v&0xff; 1372 index ~= (v>>8)&0xff; 1373 index ~= (v>>16)&0xff; 1374 index ~= (v>>24)&0xff; 1375 } 1376 1377 void putUbyte (ubyte v) { 1378 index ~= v; 1379 } 1380 1381 void putBuf (const(void)[] buf) { 1382 assert(buf.length > 0); 1383 index ~= (cast(const(ubyte)[])buf)[]; 1384 } 1385 1386 // create index in memory 1387 { 1388 // chunk size 1389 putUint(cast(uint)chunkdata.length); 1390 // chunk count 1391 putUint(cast(uint)chunks.length); 1392 // last chunk size 1393 putUint(lastChunkSize); // 0: last chunk is full 1394 // chunk offsets and sizes 1395 foreach (ref ci; chunks) { 1396 putUint(ci.ofs); 1397 putUint(ci.pksize); 1398 } 1399 // file count 1400 putUint(cast(uint)files.length); 1401 uint nbofs = cast(uint)index.length+cast(uint)files.length*(5*4); 1402 //uint nbofs = 0; 1403 // files 1404 foreach (ref fi; files) { 1405 // name: length(byte), chars 1406 assert(fi.name.length > 0 && fi.name.length <= 16384); 1407 putUint(nbofs); 1408 putUint(cast(uint)fi.name.length); 1409 nbofs += cast(uint)fi.name.length+1; // put zero byte there to ease C interfacing 1410 //putBuf(fi.name[]); 1411 // chunk number 1412 putUint(fi.chunk); 1413 // offset in unpacked chunk 1414 putUint(fi.chunkofs); 1415 // unpacked size 1416 putUint(fi.size); 1417 } 1418 // names 1419 foreach (ref fi; files) { 1420 putBuf(fi.name[]); 1421 putUbyte(0); // this means nothing, it is here just for convenience (hello, C!) 1422 } 1423 assert(index.length < uint.max); 1424 } 1425 auto cpos = ftell(arcfl); 1426 if (cpos < 0 || cpos > uint.max) throw new Exception("output archive too big"); 1427 // write packed index 1428 debug(arcz_writer) { import core.stdc.stdio : pinrtf; printf("index size: %u\n", cast(uint)index.length); } 1429 auto pkisz = writePackedBuf(index[]); 1430 debug(arcz_writer) { import core.stdc.stdio : pinrtf; printf("packed index size: %u\n", cast(uint)pkisz); } 1431 // write index info 1432 if (fseek(arcfl, 5, 0) < 0) throw new Exception("seek error"); 1433 // index offset in file 1434 writeUint(cast(uint) cpos); 1435 // packed index size 1436 writeUint(pkisz); 1437 // unpacked index size 1438 writeUint(cast(uint)index.length); 1439 // done 1440 statChunks = cast(uint)chunks.length; 1441 statFiles = cast(uint)files.length; 1442 } 1443 1444 public: 1445 this (const(char)[] fname, uint chunkSize=256*1024, Compressor acpr=Compressor.ZLib) { 1446 import std.internal.cstring; 1447 assert(chunkSize > 0 && chunkSize < 32*1024*1024); // arbitrary limit 1448 static if (!arcz_has_balz) { 1449 if (acpr == Compressor.Balz || acpr == Compressor.BalzMax) throw new Exception("no Balz support was compiled in ArcZ"); 1450 } 1451 static if (!arcz_has_zopfli) { 1452 //if (acpr == Compressor.Zopfli) throw new Exception("no Zopfli support was compiled in ArcZ"); 1453 } 1454 cpr = acpr; 1455 arcfl = fopen(fname.tempCString, "wb"); 1456 if (arcfl is null) throw new Exception("can't create output file '"~fname.idup~"'"); 1457 cdpos = 0; 1458 chunkdata.length = chunkSize; 1459 scope(failure) { fclose(arcfl); arcfl = null; } 1460 writeBuf("CZA2"); // signature 1461 if (cpr == Compressor.Balz || cpr == Compressor.BalzMax) { 1462 writeUbyte(1); // version 1463 } else { 1464 writeUbyte(0); // version 1465 } 1466 writeUint(0); // offset to index 1467 writeUint(0); // packed index size 1468 writeUint(0); // unpacked index size 1469 } 1470 1471 ~this () { close(); } 1472 1473 void close () { 1474 if (arcfl !is null) { 1475 scope(exit) { fclose(arcfl); arcfl = null; } 1476 closeArc(); 1477 } 1478 chunkdata = null; 1479 chunks = null; 1480 files = null; 1481 lastChunkSize = 0; 1482 cdpos = 0; 1483 } 1484 1485 // valid after closing 1486 @property uint chunksWritten () const pure nothrow @safe @nogc { pragma(inline, true); return statChunks; } 1487 @property uint filesWritten () const pure nothrow @safe @nogc { pragma(inline, true); return statFiles; } 1488 1489 void newFile (string name, uint size) { 1490 FileInfo fi; 1491 assert(name.length <= 255); 1492 fi.name = name; 1493 fi.chunk = cast(uint)chunks.length; 1494 fi.chunkofs = cast(uint)cdpos; 1495 fi.size = size; 1496 files ~= fi; 1497 } 1498 1499 void rawWrite(T) (const(T)[] buffer) { 1500 if (buffer.length > 0) { 1501 auto src = cast(const(ubyte)*)buffer.ptr; 1502 auto len = buffer.length*T.sizeof; 1503 while (len > 0) { 1504 if (cdpos == chunkdata.length) flushData(); 1505 if (cdpos < chunkdata.length) { 1506 auto wr = chunkdata.length-cdpos; 1507 if (wr > len) wr = len; 1508 chunkdata[cdpos..cdpos+wr] = src[0..wr]; 1509 cdpos += wr; 1510 len -= wr; 1511 src += wr; 1512 } 1513 } 1514 } 1515 } 1516 } 1517 1518 1519 // ////////////////////////////////////////////////////////////////////////// // 1520 /* arcz file format: 1521 header 1522 ====== 1523 db 'CZA2' ; signature 1524 db version ; 0: zlib; 1: balz 1525 dd indexofs ; offset to packed index 1526 dd pkindexsz ; size of packed index 1527 dd upindexsz ; size of unpacked index 1528 1529 1530 index 1531 ===== 1532 dd chunksize ; unpacked chunk size in bytes 1533 dd chunkcount ; number of chunks in file 1534 dd lastchunksz ; size of last chunk (it may be incomplete); 0: last chunk is completely used (all `chunksize` bytes) 1535 1536 then chunk offsets and sizes follows: 1537 dd chunkofs ; from file start 1538 dd pkchunksz ; size of (possibly packed) chunk data; if it equals to `chunksize`, this chunk is not packed 1539 1540 then file list follows: 1541 dd filecount ; number of files in archive 1542 1543 then file info follows: 1544 dd nameofs ; (in index) 1545 dd namelen ; length of name (can't be 0) 1546 dd firstchunk ; chunk where file starts 1547 dd firstofs ; offset in first chunk (unpacked) where file starts 1548 dd filesize ; unpacked file size 1549 1550 then name buffer follows -- just bytes 1551 */ 1552 1553 } 1554 1555 version(WithLzmaDecoder) { 1556 1557 /* *************************************************** */ 1558 /* The rest of the file is copy/paste of external code */ 1559 /* *************************************************** */ 1560 1561 /* LzmaDec.h -- LZMA Decoder 1562 2017-04-03 : Igor Pavlov : Public domain */ 1563 // also by Lasse Collin 1564 /* ported to D by ketmar */ 1565 private nothrow @trusted @nogc: 1566 1567 //version = _LZMA_PROB32; 1568 /* _LZMA_PROB32 can increase the speed on some CPUs, 1569 but memory usage for CLzmaDec::probs will be doubled in that case */ 1570 1571 //version = _LZMA_SIZE_OPT; 1572 1573 alias Byte = ubyte; 1574 alias UInt16 = ushort; 1575 alias UInt32 = uint; 1576 alias SizeT = size_t; 1577 1578 version(_LZMA_PROB32) { 1579 alias CLzmaProb = UInt32; 1580 } else { 1581 alias CLzmaProb = UInt16; 1582 } 1583 1584 public enum SRes { 1585 OK, 1586 ERROR_UNSUPPORTED, 1587 ERROR_MEM, 1588 ERROR_DATA, 1589 ERROR_INPUT_EOF, 1590 ERROR_FAIL, 1591 } 1592 1593 /* ---------- LZMA Properties ---------- */ 1594 1595 public enum LZMA_PROPS_SIZE = 5; 1596 1597 public struct CLzmaProps { 1598 uint lc, lp, pb; 1599 UInt32 dicSize; 1600 } 1601 1602 /* LzmaProps_Decode - decodes properties 1603 Returns: 1604 SRes.OK 1605 SRes.ERROR_UNSUPPORTED - Unsupported properties 1606 */ 1607 1608 //!SRes LzmaProps_Decode(CLzmaProps *p, const(Byte)* data, uint size); 1609 1610 1611 /* ---------- LZMA Decoder state ---------- */ 1612 1613 /* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. 1614 Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ 1615 1616 enum LZMA_REQUIRED_INPUT_MAX = 20; 1617 1618 public struct CLzmaDec { 1619 private: 1620 CLzmaProps prop; 1621 CLzmaProb* probs; 1622 public Byte* dic; 1623 const(Byte)* buf; 1624 UInt32 range, code; 1625 public SizeT dicPos; 1626 public SizeT dicBufSize; 1627 UInt32 processedPos; 1628 UInt32 checkDicSize; 1629 uint state; 1630 UInt32[4] reps; 1631 uint remainLen; 1632 int needFlush; 1633 int needInitState; 1634 UInt32 numProbs; 1635 uint tempBufSize; 1636 Byte[LZMA_REQUIRED_INPUT_MAX] tempBuf; 1637 } 1638 1639 //#define LzmaDec_Construct(p) { (p).dic = 0; (p).probs = 0; } 1640 1641 //void LzmaDec_Init(CLzmaDec *p); 1642 1643 /* There are two types of LZMA streams: 1644 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. 1645 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ 1646 1647 public alias ELzmaFinishMode = int; 1648 public enum /*ELzmaFinishMode*/ { 1649 LZMA_FINISH_ANY, /* finish at any point */ 1650 LZMA_FINISH_END /* block must be finished at the end */ 1651 } 1652 1653 /* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! 1654 1655 You must use LZMA_FINISH_END, when you know that current output buffer 1656 covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. 1657 1658 If LZMA decoder sees end marker before reaching output limit, it returns SRes.OK, 1659 and output value of destLen will be less than output buffer size limit. 1660 You can check status result also. 1661 1662 You can use multiple checks to test data integrity after full decompression: 1663 1) Check Result and "status" variable. 1664 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. 1665 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. 1666 You must use correct finish mode in that case. */ 1667 1668 public alias ELzmaStatus = int; 1669 public enum /*ELzmaStatus*/ { 1670 LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ 1671 LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ 1672 LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ 1673 LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ 1674 LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ 1675 } 1676 1677 /* ELzmaStatus is used only as output value for function call */ 1678 1679 1680 /* ---------- Interfaces ---------- */ 1681 1682 /* There are 3 levels of interfaces: 1683 1) Dictionary Interface 1684 2) Buffer Interface 1685 3) One Call Interface 1686 You can select any of these interfaces, but don't mix functions from different 1687 groups for same object. */ 1688 1689 1690 /* There are two variants to allocate state for Dictionary Interface: 1691 1) LzmaDec_Allocate / LzmaDec_Free 1692 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs 1693 You can use variant 2, if you set dictionary buffer manually. 1694 For Buffer Interface you must always use variant 1. 1695 1696 LzmaDec_Allocate* can return: 1697 SRes.OK 1698 SRes.ERROR_MEM - Memory allocation error 1699 SRes.ERROR_UNSUPPORTED - Unsupported properties 1700 */ 1701 1702 /* 1703 SRes LzmaDec_AllocateProbs(CLzmaDec *p, const(Byte)* props, uint propsSize); 1704 void LzmaDec_FreeProbs(CLzmaDec *p); 1705 1706 SRes LzmaDec_Allocate(CLzmaDec *state, const(Byte)* prop, uint propsSize); 1707 void LzmaDec_Free(CLzmaDec *state); 1708 */ 1709 1710 /* ---------- Dictionary Interface ---------- */ 1711 1712 /* You can use it, if you want to eliminate the overhead for data copying from 1713 dictionary to some other external buffer. 1714 You must work with CLzmaDec variables directly in this interface. 1715 1716 STEPS: 1717 LzmaDec_Constr() 1718 LzmaDec_Allocate() 1719 for (each new stream) 1720 { 1721 LzmaDec_Init() 1722 while (it needs more decompression) 1723 { 1724 LzmaDec_DecodeToDic() 1725 use data from CLzmaDec::dic and update CLzmaDec::dicPos 1726 } 1727 } 1728 LzmaDec_Free() 1729 */ 1730 1731 /* LzmaDec_DecodeToDic 1732 1733 The decoding to internal dictionary buffer (CLzmaDec::dic). 1734 You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! 1735 1736 finishMode: 1737 It has meaning only if the decoding reaches output limit (dicLimit). 1738 LZMA_FINISH_ANY - Decode just dicLimit bytes. 1739 LZMA_FINISH_END - Stream must be finished after dicLimit. 1740 1741 Returns: 1742 SRes.OK 1743 status: 1744 LZMA_STATUS_FINISHED_WITH_MARK 1745 LZMA_STATUS_NOT_FINISHED 1746 LZMA_STATUS_NEEDS_MORE_INPUT 1747 LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK 1748 SRes.ERROR_DATA - Data error 1749 */ 1750 1751 //SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const(Byte)* src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); 1752 1753 1754 /* ---------- Buffer Interface ---------- */ 1755 1756 /* It's zlib-like interface. 1757 See LzmaDec_DecodeToDic description for information about STEPS and return results, 1758 but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need 1759 to work with CLzmaDec variables manually. 1760 1761 finishMode: 1762 It has meaning only if the decoding reaches output limit (*destLen). 1763 LZMA_FINISH_ANY - Decode just destLen bytes. 1764 LZMA_FINISH_END - Stream must be finished after (*destLen). 1765 */ 1766 1767 //SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const(Byte)* src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); 1768 1769 1770 /* ---------- One Call Interface ---------- */ 1771 1772 /* LzmaDecode 1773 1774 finishMode: 1775 It has meaning only if the decoding reaches output limit (*destLen). 1776 LZMA_FINISH_ANY - Decode just destLen bytes. 1777 LZMA_FINISH_END - Stream must be finished after (*destLen). 1778 1779 Returns: 1780 SRes.OK 1781 status: 1782 LZMA_STATUS_FINISHED_WITH_MARK 1783 LZMA_STATUS_NOT_FINISHED 1784 LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK 1785 SRes.ERROR_DATA - Data error 1786 SRes.ERROR_MEM - Memory allocation error 1787 SRes.ERROR_UNSUPPORTED - Unsupported properties 1788 SRes.ERROR_INPUT_EOF - It needs more bytes in input buffer (src). 1789 */ 1790 1791 /* 1792 SRes LzmaDecode(Byte *dest, SizeT *destLen, const(Byte)* src, SizeT *srcLen, 1793 const(Byte)* propData, uint propSize, ELzmaFinishMode finishMode, 1794 ELzmaStatus *status, ISzAllocPtr alloc); 1795 */ 1796 1797 // ////////////////////////////////////////////////////////////////////////// // 1798 private: 1799 1800 enum kNumTopBits = 24; 1801 enum kTopValue = 1U<<kNumTopBits; 1802 1803 enum kNumBitModelTotalBits = 11; 1804 enum kBitModelTotal = 1<<kNumBitModelTotalBits; 1805 enum kNumMoveBits = 5; 1806 1807 enum RC_INIT_SIZE = 5; 1808 1809 //enum NORMALIZE = "if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }"; 1810 1811 //#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 1812 //#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); 1813 //#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); 1814 enum GET_BIT2(string p, string i, string A0, string A1) = 1815 "ttt = *("~p~"); if (range < kTopValue) { range <<= 8; code = (code<<8)|(*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound)\n"~ 1816 "{ range = bound; *("~p~") = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); "~i~" = ("~i~"+"~i~"); "~A0~" } else\n"~ 1817 "{ range -= bound; code -= bound; *("~p~") = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); "~i~" = ("~i~"+"~i~")+1; "~A1~" }"; 1818 //#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) 1819 enum GET_BIT(string p, string i) = GET_BIT2!(p, i, "", ""); 1820 1821 enum TREE_GET_BIT(string probs, string i) = "{"~GET_BIT!("("~probs~"+"~i~")", i)~"}"; 1822 1823 enum TREE_DECODE(string probs, string limit, string i) = 1824 "{ "~i~" = 1; do { "~TREE_GET_BIT!(probs, i)~" } while ("~i~" < "~limit~"); "~i~" -= "~limit~"; }"; 1825 1826 1827 version(_LZMA_SIZE_OPT) { 1828 enum TREE_6_DECODE(string probs, string i) = TREE_DECODE!(probs, "(1<<6)", i); 1829 } else { 1830 enum TREE_6_DECODE(string probs, string i) = 1831 "{ "~i~" = 1;\n"~ 1832 TREE_GET_BIT!(probs, i)~ 1833 TREE_GET_BIT!(probs, i)~ 1834 TREE_GET_BIT!(probs, i)~ 1835 TREE_GET_BIT!(probs, i)~ 1836 TREE_GET_BIT!(probs, i)~ 1837 TREE_GET_BIT!(probs, i)~ 1838 i~" -= 0x40; }"; 1839 } 1840 1841 enum NORMAL_LITER_DEC = GET_BIT!("prob + symbol", "symbol"); 1842 enum MATCHED_LITER_DEC = 1843 "matchByte <<= 1;\n"~ 1844 "bit = (matchByte & offs);\n"~ 1845 "probLit = prob + offs + bit + symbol;\n"~ 1846 GET_BIT2!("probLit", "symbol", "offs &= ~bit;", "offs &= bit;"); 1847 1848 enum NORMALIZE_CHECK = "if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }"; 1849 1850 //#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 1851 //#define UPDATE_0_CHECK range = bound; 1852 //#define UPDATE_1_CHECK range -= bound; code -= bound; 1853 enum GET_BIT2_CHECK(string p, string i, string A0, string A1) = 1854 "ttt = *("~p~"); if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)\n"~ 1855 "{ range = bound; "~i~" = ("~i~" + "~i~"); "~A0~" } else\n"~ 1856 "{ range -= bound; code -= bound; "~i~" = ("~i~" + "~i~") + 1; "~A1~" }"; 1857 enum GET_BIT_CHECK(string p, string i) = GET_BIT2_CHECK!(p, i, "{}", "{}"); 1858 enum TREE_DECODE_CHECK(string probs, string limit, string i) = 1859 "{ "~i~" = 1; do { "~GET_BIT_CHECK!(probs~"+"~i, i)~" } while ("~i~" < "~limit~"); "~i~" -= "~limit~"; }"; 1860 1861 1862 enum kNumPosBitsMax = 4; 1863 enum kNumPosStatesMax = (1 << kNumPosBitsMax); 1864 1865 enum kLenNumLowBits = 3; 1866 enum kLenNumLowSymbols = (1 << kLenNumLowBits); 1867 enum kLenNumMidBits = 3; 1868 enum kLenNumMidSymbols = (1 << kLenNumMidBits); 1869 enum kLenNumHighBits = 8; 1870 enum kLenNumHighSymbols = (1 << kLenNumHighBits); 1871 1872 enum LenChoice = 0; 1873 enum LenChoice2 = (LenChoice + 1); 1874 enum LenLow = (LenChoice2 + 1); 1875 enum LenMid = (LenLow + (kNumPosStatesMax << kLenNumLowBits)); 1876 enum LenHigh = (LenMid + (kNumPosStatesMax << kLenNumMidBits)); 1877 enum kNumLenProbs = (LenHigh + kLenNumHighSymbols); 1878 1879 1880 enum kNumStates = 12; 1881 enum kNumLitStates = 7; 1882 1883 enum kStartPosModelIndex = 4; 1884 enum kEndPosModelIndex = 14; 1885 enum kNumFullDistances = (1 << (kEndPosModelIndex >> 1)); 1886 1887 enum kNumPosSlotBits = 6; 1888 enum kNumLenToPosStates = 4; 1889 1890 enum kNumAlignBits = 4; 1891 enum kAlignTableSize = (1 << kNumAlignBits); 1892 1893 enum kMatchMinLen = 2; 1894 enum kMatchSpecLenStart = (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols); 1895 1896 enum IsMatch = 0; 1897 enum IsRep = (IsMatch + (kNumStates << kNumPosBitsMax)); 1898 enum IsRepG0 = (IsRep + kNumStates); 1899 enum IsRepG1 = (IsRepG0 + kNumStates); 1900 enum IsRepG2 = (IsRepG1 + kNumStates); 1901 enum IsRep0Long = (IsRepG2 + kNumStates); 1902 enum PosSlot = (IsRep0Long + (kNumStates << kNumPosBitsMax)); 1903 enum SpecPos = (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)); 1904 enum Align = (SpecPos + kNumFullDistances - kEndPosModelIndex); 1905 enum LenCoder = (Align + kAlignTableSize); 1906 enum RepLenCoder = (LenCoder + kNumLenProbs); 1907 enum Literal = (RepLenCoder + kNumLenProbs); 1908 1909 enum LZMA_BASE_SIZE = 1846; 1910 enum LZMA_LIT_SIZE = 0x300; 1911 1912 static assert(Literal == LZMA_BASE_SIZE); 1913 1914 //#define LzmaProps_GetNumProbs(p) (Literal + ((UInt32)LZMA_LIT_SIZE << ((p).lc + (p).lp))) 1915 1916 enum LZMA_DIC_MIN = (1 << 12); 1917 1918 /* First LZMA-symbol is always decoded. 1919 And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization 1920 Out: 1921 Result: 1922 SRes.OK - OK 1923 SRes.ERROR_DATA - Error 1924 p->remainLen: 1925 < kMatchSpecLenStart : normal remain 1926 = kMatchSpecLenStart : finished 1927 = kMatchSpecLenStart + 1 : Flush marker (unused now) 1928 = kMatchSpecLenStart + 2 : State Init Marker (unused now) 1929 */ 1930 1931 private SRes LzmaDec_DecodeReal (CLzmaDec* p, SizeT limit, const(Byte)* bufLimit) { 1932 CLzmaProb* probs = p.probs; 1933 1934 uint state = p.state; 1935 UInt32 rep0 = p.reps.ptr[0], rep1 = p.reps.ptr[1], rep2 = p.reps.ptr[2], rep3 = p.reps.ptr[3]; 1936 uint pbMask = (1U<<(p.prop.pb))-1; 1937 uint lpMask = (1U<<(p.prop.lp))-1; 1938 uint lc = p.prop.lc; 1939 1940 Byte* dic = p.dic; 1941 SizeT dicBufSize = p.dicBufSize; 1942 SizeT dicPos = p.dicPos; 1943 1944 UInt32 processedPos = p.processedPos; 1945 UInt32 checkDicSize = p.checkDicSize; 1946 uint len = 0; 1947 1948 const(Byte)* buf = p.buf; 1949 UInt32 range = p.range; 1950 UInt32 code = p.code; 1951 1952 do { 1953 CLzmaProb *prob; 1954 UInt32 bound; 1955 uint ttt; 1956 uint posState = processedPos & pbMask; 1957 1958 prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; 1959 ttt = *(prob); if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound) 1960 { 1961 uint symbol; 1962 range = bound; *(prob) = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); 1963 prob = probs + Literal; 1964 if (processedPos != 0 || checkDicSize != 0) 1965 prob += (cast(UInt32)LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + 1966 (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); 1967 processedPos++; 1968 1969 if (state < kNumLitStates) 1970 { 1971 state -= (state < 4) ? state : 3; 1972 symbol = 1; 1973 version(_LZMA_SIZE_OPT) { 1974 do { mixin(NORMAL_LITER_DEC); } while (symbol < 0x100); 1975 } else { 1976 mixin(NORMAL_LITER_DEC); 1977 mixin(NORMAL_LITER_DEC); 1978 mixin(NORMAL_LITER_DEC); 1979 mixin(NORMAL_LITER_DEC); 1980 mixin(NORMAL_LITER_DEC); 1981 mixin(NORMAL_LITER_DEC); 1982 mixin(NORMAL_LITER_DEC); 1983 mixin(NORMAL_LITER_DEC); 1984 } 1985 } 1986 else 1987 { 1988 uint matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; 1989 uint offs = 0x100; 1990 state -= (state < 10) ? 3 : 6; 1991 symbol = 1; 1992 version(_LZMA_SIZE_OPT) { 1993 do 1994 { 1995 uint bit; 1996 CLzmaProb *probLit; 1997 mixin(MATCHED_LITER_DEC); 1998 } 1999 while (symbol < 0x100); 2000 } else { 2001 { 2002 uint bit; 2003 CLzmaProb *probLit; 2004 mixin(MATCHED_LITER_DEC); 2005 mixin(MATCHED_LITER_DEC); 2006 mixin(MATCHED_LITER_DEC); 2007 mixin(MATCHED_LITER_DEC); 2008 mixin(MATCHED_LITER_DEC); 2009 mixin(MATCHED_LITER_DEC); 2010 mixin(MATCHED_LITER_DEC); 2011 mixin(MATCHED_LITER_DEC); 2012 } 2013 } 2014 } 2015 2016 dic[dicPos++] = cast(Byte)symbol; 2017 continue; 2018 } 2019 2020 { 2021 range -= bound; code -= bound; *(prob) = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); 2022 prob = probs + IsRep + state; 2023 ttt = *(prob); if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound) 2024 { 2025 range = bound; *(prob) = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); 2026 state += kNumStates; 2027 prob = probs + LenCoder; 2028 } 2029 else 2030 { 2031 range -= bound; code -= bound; *(prob) = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); 2032 if (checkDicSize == 0 && processedPos == 0) 2033 return SRes.ERROR_DATA; 2034 prob = probs + IsRepG0 + state; 2035 ttt = *(prob); if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound) 2036 { 2037 range = bound; *(prob) = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); 2038 prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; 2039 ttt = *(prob); if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound) 2040 { 2041 range = bound; *(prob) = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); 2042 dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; 2043 dicPos++; 2044 processedPos++; 2045 state = state < kNumLitStates ? 9 : 11; 2046 continue; 2047 } 2048 range -= bound; code -= bound; *(prob) = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); 2049 } 2050 else 2051 { 2052 UInt32 distance; 2053 range -= bound; code -= bound; *(prob) = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); 2054 prob = probs + IsRepG1 + state; 2055 ttt = *(prob); if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound) 2056 { 2057 range = bound; *(prob) = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); 2058 distance = rep1; 2059 } 2060 else 2061 { 2062 range -= bound; code -= bound; *(prob) = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); 2063 prob = probs + IsRepG2 + state; 2064 ttt = *(prob); if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound) 2065 { 2066 range = bound; *(prob) = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); 2067 distance = rep2; 2068 } 2069 else 2070 { 2071 range -= bound; code -= bound; *(prob) = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); 2072 distance = rep3; 2073 rep3 = rep2; 2074 } 2075 rep2 = rep1; 2076 } 2077 rep1 = rep0; 2078 rep0 = distance; 2079 } 2080 state = state < kNumLitStates ? 8 : 11; 2081 prob = probs + RepLenCoder; 2082 } 2083 2084 version(_LZMA_SIZE_OPT) { 2085 { 2086 uint lim, offset; 2087 CLzmaProb *probLen = prob + LenChoice; 2088 ttt = *(probLen); if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound) 2089 { 2090 range = bound; *(probLen) = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); 2091 probLen = prob + LenLow + (posState << kLenNumLowBits); 2092 offset = 0; 2093 lim = (1 << kLenNumLowBits); 2094 } 2095 else 2096 { 2097 range -= bound; code -= bound; *(probLen) = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); 2098 probLen = prob + LenChoice2; 2099 ttt = *(probLen); if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound) 2100 { 2101 range = bound; *(probLen) = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); 2102 probLen = prob + LenMid + (posState << kLenNumMidBits); 2103 offset = kLenNumLowSymbols; 2104 lim = (1 << kLenNumMidBits); 2105 } 2106 else 2107 { 2108 range -= bound; code -= bound; *(probLen) = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); 2109 probLen = prob + LenHigh; 2110 offset = kLenNumLowSymbols + kLenNumMidSymbols; 2111 lim = (1 << kLenNumHighBits); 2112 } 2113 } 2114 mixin(TREE_DECODE!("probLen", "lim", "len")); 2115 len += offset; 2116 } 2117 } else { 2118 { 2119 CLzmaProb *probLen = prob + LenChoice; 2120 ttt = *(probLen); if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound) 2121 { 2122 range = bound; *(probLen) = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); 2123 probLen = prob + LenLow + (posState << kLenNumLowBits); 2124 len = 1; 2125 mixin(TREE_GET_BIT!("probLen", "len")); 2126 mixin(TREE_GET_BIT!("probLen", "len")); 2127 mixin(TREE_GET_BIT!("probLen", "len")); 2128 len -= 8; 2129 } 2130 else 2131 { 2132 range -= bound; code -= bound; *(probLen) = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); 2133 probLen = prob + LenChoice2; 2134 ttt = *(probLen); if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } bound = (range>>kNumBitModelTotalBits)*ttt; if (code < bound) 2135 { 2136 range = bound; *(probLen) = cast(CLzmaProb)(ttt+((kBitModelTotal-ttt)>>kNumMoveBits)); 2137 probLen = prob + LenMid + (posState << kLenNumMidBits); 2138 len = 1; 2139 mixin(TREE_GET_BIT!("probLen", "len")); 2140 mixin(TREE_GET_BIT!("probLen", "len")); 2141 mixin(TREE_GET_BIT!("probLen", "len")); 2142 } 2143 else 2144 { 2145 range -= bound; code -= bound; *(probLen) = cast(CLzmaProb)(ttt-(ttt>>kNumMoveBits)); 2146 probLen = prob + LenHigh; 2147 mixin(TREE_DECODE!("probLen", "(1 << kLenNumHighBits)", "len")); 2148 len += kLenNumLowSymbols + kLenNumMidSymbols; 2149 } 2150 } 2151 } 2152 } 2153 2154 if (state >= kNumStates) 2155 { 2156 UInt32 distance; 2157 prob = probs + PosSlot + 2158 ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); 2159 mixin(TREE_6_DECODE!("prob", "distance")); 2160 if (distance >= kStartPosModelIndex) 2161 { 2162 uint posSlot = cast(uint)distance; 2163 uint numDirectBits = cast(uint)(((distance >> 1) - 1)); 2164 distance = (2 | (distance & 1)); 2165 if (posSlot < kEndPosModelIndex) 2166 { 2167 distance <<= numDirectBits; 2168 prob = probs + SpecPos + distance - posSlot - 1; 2169 { 2170 UInt32 mask = 1; 2171 uint i = 1; 2172 do 2173 { 2174 mixin(GET_BIT2!("prob + i", "i", "{}" , "distance |= mask;")); 2175 mask <<= 1; 2176 } 2177 while (--numDirectBits != 0); 2178 } 2179 } 2180 else 2181 { 2182 numDirectBits -= kNumAlignBits; 2183 do 2184 { 2185 if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } 2186 range >>= 1; 2187 2188 { 2189 UInt32 t; 2190 code -= range; 2191 t = (0 - (cast(UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ 2192 distance = (distance << 1) + (t + 1); 2193 code += range & t; 2194 } 2195 /* 2196 distance <<= 1; 2197 if (code >= range) 2198 { 2199 code -= range; 2200 distance |= 1; 2201 } 2202 */ 2203 } 2204 while (--numDirectBits != 0); 2205 prob = probs + Align; 2206 distance <<= kNumAlignBits; 2207 { 2208 uint i = 1; 2209 mixin(GET_BIT2!("prob + i", "i", "", "distance |= 1;")); 2210 mixin(GET_BIT2!("prob + i", "i", "", "distance |= 2;")); 2211 mixin(GET_BIT2!("prob + i", "i", "", "distance |= 4;")); 2212 mixin(GET_BIT2!("prob + i", "i", "", "distance |= 8;")); 2213 } 2214 if (distance == cast(UInt32)0xFFFFFFFF) 2215 { 2216 len += kMatchSpecLenStart; 2217 state -= kNumStates; 2218 break; 2219 } 2220 } 2221 } 2222 2223 rep3 = rep2; 2224 rep2 = rep1; 2225 rep1 = rep0; 2226 rep0 = distance + 1; 2227 if (checkDicSize == 0) 2228 { 2229 if (distance >= processedPos) 2230 { 2231 p.dicPos = dicPos; 2232 return SRes.ERROR_DATA; 2233 } 2234 } 2235 else if (distance >= checkDicSize) 2236 { 2237 p.dicPos = dicPos; 2238 return SRes.ERROR_DATA; 2239 } 2240 state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; 2241 } 2242 2243 len += kMatchMinLen; 2244 2245 { 2246 SizeT rem; 2247 uint curLen; 2248 SizeT pos; 2249 2250 if ((rem = limit - dicPos) == 0) 2251 { 2252 p.dicPos = dicPos; 2253 return SRes.ERROR_DATA; 2254 } 2255 2256 curLen = ((rem < len) ? cast(uint)rem : len); 2257 pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); 2258 2259 processedPos += curLen; 2260 2261 len -= curLen; 2262 if (curLen <= dicBufSize - pos) 2263 { 2264 Byte *dest = dic + dicPos; 2265 ptrdiff_t src = cast(ptrdiff_t)pos - cast(ptrdiff_t)dicPos; 2266 const(Byte)* lim = dest + curLen; 2267 dicPos += curLen; 2268 do 2269 *(dest) = cast(Byte)*(dest + src); 2270 while (++dest != lim); 2271 } 2272 else 2273 { 2274 do 2275 { 2276 dic[dicPos++] = dic[pos]; 2277 if (++pos == dicBufSize) 2278 pos = 0; 2279 } 2280 while (--curLen != 0); 2281 } 2282 } 2283 } 2284 } 2285 while (dicPos < limit && buf < bufLimit); 2286 2287 if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } 2288 2289 p.buf = buf; 2290 p.range = range; 2291 p.code = code; 2292 p.remainLen = len; 2293 p.dicPos = dicPos; 2294 p.processedPos = processedPos; 2295 p.reps.ptr[0] = rep0; 2296 p.reps.ptr[1] = rep1; 2297 p.reps.ptr[2] = rep2; 2298 p.reps.ptr[3] = rep3; 2299 p.state = state; 2300 2301 return SRes.OK; 2302 } 2303 2304 private void LzmaDec_WriteRem (CLzmaDec* p, SizeT limit) { 2305 if (p.remainLen != 0 && p.remainLen < kMatchSpecLenStart) 2306 { 2307 Byte *dic = p.dic; 2308 SizeT dicPos = p.dicPos; 2309 SizeT dicBufSize = p.dicBufSize; 2310 uint len = p.remainLen; 2311 SizeT rep0 = p.reps.ptr[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ 2312 SizeT rem = limit - dicPos; 2313 if (rem < len) 2314 len = cast(uint)(rem); 2315 2316 if (p.checkDicSize == 0 && p.prop.dicSize - p.processedPos <= len) 2317 p.checkDicSize = p.prop.dicSize; 2318 2319 p.processedPos += len; 2320 p.remainLen -= len; 2321 while (len != 0) 2322 { 2323 len--; 2324 dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; 2325 dicPos++; 2326 } 2327 p.dicPos = dicPos; 2328 } 2329 } 2330 2331 private SRes LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const(Byte)* bufLimit) 2332 { 2333 do 2334 { 2335 SizeT limit2 = limit; 2336 if (p.checkDicSize == 0) 2337 { 2338 UInt32 rem = p.prop.dicSize - p.processedPos; 2339 if (limit - p.dicPos > rem) 2340 limit2 = p.dicPos + rem; 2341 } 2342 2343 if (auto sres = LzmaDec_DecodeReal(p, limit2, bufLimit)) return sres; 2344 2345 if (p.checkDicSize == 0 && p.processedPos >= p.prop.dicSize) 2346 p.checkDicSize = p.prop.dicSize; 2347 2348 LzmaDec_WriteRem(p, limit); 2349 } 2350 while (p.dicPos < limit && p.buf < bufLimit && p.remainLen < kMatchSpecLenStart); 2351 2352 if (p.remainLen > kMatchSpecLenStart) 2353 p.remainLen = kMatchSpecLenStart; 2354 2355 return SRes.OK; 2356 } 2357 2358 alias ELzmaDummy = int; 2359 enum /*ELzmaDummy*/ { 2360 DUMMY_ERROR, /* unexpected end of input stream */ 2361 DUMMY_LIT, 2362 DUMMY_MATCH, 2363 DUMMY_REP 2364 } 2365 2366 private ELzmaDummy LzmaDec_TryDummy(const(CLzmaDec)* p, const(Byte)* buf, SizeT inSize) 2367 { 2368 UInt32 range = p.range; 2369 UInt32 code = p.code; 2370 const(Byte)* bufLimit = buf + inSize; 2371 const(CLzmaProb)* probs = p.probs; 2372 uint state = p.state; 2373 ELzmaDummy res; 2374 2375 { 2376 const(CLzmaProb)* prob; 2377 UInt32 bound; 2378 uint ttt; 2379 uint posState = (p.processedPos) & ((1 << p.prop.pb) - 1); 2380 2381 prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; 2382 ttt = *(prob); if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 2383 { 2384 range = bound; 2385 2386 /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ 2387 2388 prob = probs + Literal; 2389 if (p.checkDicSize != 0 || p.processedPos != 0) 2390 prob += (cast(UInt32)LZMA_LIT_SIZE * 2391 ((((p.processedPos) & ((1 << (p.prop.lp)) - 1)) << p.prop.lc) + 2392 (p.dic[(p.dicPos == 0 ? p.dicBufSize : p.dicPos) - 1] >> (8 - p.prop.lc)))); 2393 2394 if (state < kNumLitStates) 2395 { 2396 uint symbol = 1; 2397 do { mixin(GET_BIT_CHECK!("prob + symbol", "symbol")); } while (symbol < 0x100); 2398 } 2399 else 2400 { 2401 uint matchByte = p.dic[p.dicPos - p.reps.ptr[0] + 2402 (p.dicPos < p.reps.ptr[0] ? p.dicBufSize : 0)]; 2403 uint offs = 0x100; 2404 uint symbol = 1; 2405 do 2406 { 2407 uint bit; 2408 const(CLzmaProb)* probLit; 2409 matchByte <<= 1; 2410 bit = (matchByte & offs); 2411 probLit = prob + offs + bit + symbol; 2412 mixin(GET_BIT2_CHECK!("probLit", "symbol", "offs &= ~bit;", "offs &= bit;")); 2413 } 2414 while (symbol < 0x100); 2415 } 2416 res = DUMMY_LIT; 2417 } 2418 else 2419 { 2420 uint len; 2421 range -= bound; code -= bound; 2422 2423 prob = probs + IsRep + state; 2424 ttt = *(prob); if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 2425 { 2426 range = bound; 2427 state = 0; 2428 prob = probs + LenCoder; 2429 res = DUMMY_MATCH; 2430 } 2431 else 2432 { 2433 range -= bound; code -= bound; 2434 res = DUMMY_REP; 2435 prob = probs + IsRepG0 + state; 2436 ttt = *(prob); if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 2437 { 2438 range = bound; 2439 prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; 2440 ttt = *(prob); if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 2441 { 2442 range = bound; 2443 if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } 2444 return DUMMY_REP; 2445 } 2446 else 2447 { 2448 range -= bound; code -= bound; 2449 } 2450 } 2451 else 2452 { 2453 range -= bound; code -= bound; 2454 prob = probs + IsRepG1 + state; 2455 ttt = *(prob); if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 2456 { 2457 range = bound; 2458 } 2459 else 2460 { 2461 range -= bound; code -= bound; 2462 prob = probs + IsRepG2 + state; 2463 ttt = *(prob); if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 2464 { 2465 range = bound; 2466 } 2467 else 2468 { 2469 range -= bound; code -= bound; 2470 } 2471 } 2472 } 2473 state = kNumStates; 2474 prob = probs + RepLenCoder; 2475 } 2476 { 2477 uint limit, offset; 2478 const(CLzmaProb)* probLen = prob + LenChoice; 2479 ttt = *(probLen); if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 2480 { 2481 range = bound; 2482 probLen = prob + LenLow + (posState << kLenNumLowBits); 2483 offset = 0; 2484 limit = 1 << kLenNumLowBits; 2485 } 2486 else 2487 { 2488 range -= bound; code -= bound; 2489 probLen = prob + LenChoice2; 2490 ttt = *(probLen); if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) 2491 { 2492 range = bound; 2493 probLen = prob + LenMid + (posState << kLenNumMidBits); 2494 offset = kLenNumLowSymbols; 2495 limit = 1 << kLenNumMidBits; 2496 } 2497 else 2498 { 2499 range -= bound; code -= bound; 2500 probLen = prob + LenHigh; 2501 offset = kLenNumLowSymbols + kLenNumMidSymbols; 2502 limit = 1 << kLenNumHighBits; 2503 } 2504 } 2505 mixin(TREE_DECODE_CHECK!("probLen", "limit", "len")); 2506 len += offset; 2507 } 2508 2509 if (state < 4) 2510 { 2511 uint posSlot; 2512 prob = probs + PosSlot + 2513 ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 2514 kNumPosSlotBits); 2515 mixin(TREE_DECODE_CHECK!("prob", "1 << kNumPosSlotBits", "posSlot")); 2516 if (posSlot >= kStartPosModelIndex) 2517 { 2518 uint numDirectBits = ((posSlot >> 1) - 1); 2519 2520 /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ 2521 2522 if (posSlot < kEndPosModelIndex) 2523 { 2524 prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; 2525 } 2526 else 2527 { 2528 numDirectBits -= kNumAlignBits; 2529 do 2530 { 2531 if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } 2532 range >>= 1; 2533 code -= range & (((code - range) >> 31) - 1); 2534 /* if (code >= range) code -= range; */ 2535 } 2536 while (--numDirectBits != 0); 2537 prob = probs + Align; 2538 numDirectBits = kNumAlignBits; 2539 } 2540 { 2541 uint i = 1; 2542 do 2543 { 2544 mixin(GET_BIT_CHECK!("prob + i", "i")); 2545 } 2546 while (--numDirectBits != 0); 2547 } 2548 } 2549 } 2550 } 2551 } 2552 if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } 2553 return res; 2554 } 2555 2556 2557 void LzmaDec_InitDicAndState(CLzmaDec *p, bool initDic, bool initState) 2558 { 2559 p.needFlush = 1; 2560 p.remainLen = 0; 2561 p.tempBufSize = 0; 2562 2563 if (initDic) 2564 { 2565 p.processedPos = 0; 2566 p.checkDicSize = 0; 2567 p.needInitState = 1; 2568 } 2569 if (initState) 2570 p.needInitState = 1; 2571 } 2572 2573 public void LzmaDec_Init(CLzmaDec *p) 2574 { 2575 p.dicPos = 0; 2576 LzmaDec_InitDicAndState(p, true, true); 2577 } 2578 2579 private void LzmaDec_InitStateReal(CLzmaDec *p) 2580 { 2581 SizeT numProbs = (Literal+(cast(UInt32)LZMA_LIT_SIZE<<((&p.prop).lc+(&p.prop).lp))); 2582 SizeT i; 2583 CLzmaProb *probs = p.probs; 2584 for (i = 0; i < numProbs; i++) 2585 probs[i] = kBitModelTotal >> 1; 2586 p.reps.ptr[0] = p.reps.ptr[1] = p.reps.ptr[2] = p.reps.ptr[3] = 1; 2587 p.state = 0; 2588 p.needInitState = 0; 2589 } 2590 2591 public SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const(Byte)* src, SizeT *srcLen, 2592 ELzmaFinishMode finishMode, ELzmaStatus *status) 2593 { 2594 SizeT inSize = *srcLen; 2595 (*srcLen) = 0; 2596 LzmaDec_WriteRem(p, dicLimit); 2597 2598 *status = LZMA_STATUS_NOT_SPECIFIED; 2599 2600 while (p.remainLen != kMatchSpecLenStart) 2601 { 2602 int checkEndMarkNow; 2603 2604 if (p.needFlush) 2605 { 2606 for (; inSize > 0 && p.tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) 2607 p.tempBuf.ptr[p.tempBufSize++] = *src++; 2608 if (p.tempBufSize < RC_INIT_SIZE) 2609 { 2610 *status = LZMA_STATUS_NEEDS_MORE_INPUT; 2611 return SRes.OK; 2612 } 2613 if (p.tempBuf.ptr[0] != 0) 2614 return SRes.ERROR_DATA; 2615 p.code = 2616 (cast(UInt32)p.tempBuf.ptr[1] << 24) 2617 | (cast(UInt32)p.tempBuf.ptr[2] << 16) 2618 | (cast(UInt32)p.tempBuf.ptr[3] << 8) 2619 | (cast(UInt32)p.tempBuf.ptr[4]); 2620 p.range = 0xFFFFFFFF; 2621 p.needFlush = 0; 2622 p.tempBufSize = 0; 2623 } 2624 2625 checkEndMarkNow = 0; 2626 if (p.dicPos >= dicLimit) 2627 { 2628 if (p.remainLen == 0 && p.code == 0) 2629 { 2630 *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; 2631 return SRes.OK; 2632 } 2633 if (finishMode == LZMA_FINISH_ANY) 2634 { 2635 *status = LZMA_STATUS_NOT_FINISHED; 2636 return SRes.OK; 2637 } 2638 if (p.remainLen != 0) 2639 { 2640 *status = LZMA_STATUS_NOT_FINISHED; 2641 return SRes.ERROR_DATA; 2642 } 2643 checkEndMarkNow = 1; 2644 } 2645 2646 if (p.needInitState) 2647 LzmaDec_InitStateReal(p); 2648 2649 if (p.tempBufSize == 0) 2650 { 2651 SizeT processed; 2652 const(Byte)* bufLimit; 2653 if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) 2654 { 2655 int dummyRes = LzmaDec_TryDummy(p, src, inSize); 2656 if (dummyRes == DUMMY_ERROR) 2657 { 2658 import core.stdc.string : memcpy; 2659 memcpy(p.tempBuf.ptr, src, inSize); 2660 p.tempBufSize = cast(uint)inSize; 2661 (*srcLen) += inSize; 2662 *status = LZMA_STATUS_NEEDS_MORE_INPUT; 2663 return SRes.OK; 2664 } 2665 if (checkEndMarkNow && dummyRes != DUMMY_MATCH) 2666 { 2667 *status = LZMA_STATUS_NOT_FINISHED; 2668 return SRes.ERROR_DATA; 2669 } 2670 bufLimit = src; 2671 } 2672 else 2673 bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; 2674 p.buf = src; 2675 if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) 2676 return SRes.ERROR_DATA; 2677 processed = cast(SizeT)(p.buf - src); 2678 (*srcLen) += processed; 2679 src += processed; 2680 inSize -= processed; 2681 } 2682 else 2683 { 2684 uint rem = p.tempBufSize, lookAhead = 0; 2685 while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) 2686 p.tempBuf.ptr[rem++] = src[lookAhead++]; 2687 p.tempBufSize = rem; 2688 if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) 2689 { 2690 int dummyRes = LzmaDec_TryDummy(p, p.tempBuf.ptr, rem); 2691 if (dummyRes == DUMMY_ERROR) 2692 { 2693 (*srcLen) += lookAhead; 2694 *status = LZMA_STATUS_NEEDS_MORE_INPUT; 2695 return SRes.OK; 2696 } 2697 if (checkEndMarkNow && dummyRes != DUMMY_MATCH) 2698 { 2699 *status = LZMA_STATUS_NOT_FINISHED; 2700 return SRes.ERROR_DATA; 2701 } 2702 } 2703 p.buf = p.tempBuf.ptr; 2704 if (LzmaDec_DecodeReal2(p, dicLimit, p.buf) != 0) 2705 return SRes.ERROR_DATA; 2706 2707 { 2708 uint kkk = cast(uint)(p.buf - p.tempBuf.ptr); 2709 if (rem < kkk) 2710 return SRes.ERROR_FAIL; /* some internal error */ 2711 rem -= kkk; 2712 if (lookAhead < rem) 2713 return SRes.ERROR_FAIL; /* some internal error */ 2714 lookAhead -= rem; 2715 } 2716 (*srcLen) += lookAhead; 2717 src += lookAhead; 2718 inSize -= lookAhead; 2719 p.tempBufSize = 0; 2720 } 2721 } 2722 if (p.code == 0) 2723 *status = LZMA_STATUS_FINISHED_WITH_MARK; 2724 return (p.code == 0) ? SRes.OK : SRes.ERROR_DATA; 2725 } 2726 2727 public SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const(Byte)* src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) 2728 { 2729 import core.stdc.string : memcpy; 2730 SizeT outSize = *destLen; 2731 SizeT inSize = *srcLen; 2732 *srcLen = *destLen = 0; 2733 for (;;) 2734 { 2735 SizeT inSizeCur = inSize, outSizeCur, dicPos; 2736 ELzmaFinishMode curFinishMode; 2737 SRes res; 2738 if (p.dicPos == p.dicBufSize) 2739 p.dicPos = 0; 2740 dicPos = p.dicPos; 2741 if (outSize > p.dicBufSize - dicPos) 2742 { 2743 outSizeCur = p.dicBufSize; 2744 curFinishMode = LZMA_FINISH_ANY; 2745 } 2746 else 2747 { 2748 outSizeCur = dicPos + outSize; 2749 curFinishMode = finishMode; 2750 } 2751 2752 res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); 2753 src += inSizeCur; 2754 inSize -= inSizeCur; 2755 *srcLen += inSizeCur; 2756 outSizeCur = p.dicPos - dicPos; 2757 memcpy(dest, p.dic + dicPos, outSizeCur); 2758 dest += outSizeCur; 2759 outSize -= outSizeCur; 2760 *destLen += outSizeCur; 2761 if (res != 0) 2762 return res; 2763 if (outSizeCur == 0 || outSize == 0) 2764 return SRes.OK; 2765 } 2766 } 2767 2768 public void LzmaDec_FreeProbs(CLzmaDec *p) { 2769 import core.stdc.stdlib : free; 2770 if (p.probs !is null) free(p.probs); 2771 p.probs = null; 2772 } 2773 2774 private void LzmaDec_FreeDict(CLzmaDec *p) { 2775 import core.stdc.stdlib : free; 2776 if (p.dic !is null) free(p.dic); 2777 p.dic = null; 2778 } 2779 2780 public void LzmaDec_Free(CLzmaDec *p) { 2781 LzmaDec_FreeProbs(p); 2782 LzmaDec_FreeDict(p); 2783 } 2784 2785 public SRes LzmaProps_Decode(CLzmaProps *p, const(Byte)*data, uint size) 2786 { 2787 UInt32 dicSize; 2788 Byte d; 2789 2790 if (size < LZMA_PROPS_SIZE) 2791 return SRes.ERROR_UNSUPPORTED; 2792 else 2793 dicSize = data[1] | (data[2] << 8) | (data[3] << 16) | (data[4] << 24); 2794 2795 if (dicSize < LZMA_DIC_MIN) 2796 dicSize = LZMA_DIC_MIN; 2797 p.dicSize = dicSize; 2798 2799 d = data[0]; 2800 if (d >= (9 * 5 * 5)) 2801 return SRes.ERROR_UNSUPPORTED; 2802 2803 p.lc = d % 9; 2804 d /= 9; 2805 p.pb = d / 5; 2806 p.lp = d % 5; 2807 2808 return SRes.OK; 2809 } 2810 2811 private SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const(CLzmaProps)* propNew) { 2812 import core.stdc.stdlib : malloc; 2813 UInt32 numProbs = (Literal+(cast(UInt32)LZMA_LIT_SIZE<<((propNew).lc+(propNew).lp))); 2814 if (!p.probs || numProbs != p.numProbs) 2815 { 2816 LzmaDec_FreeProbs(p); 2817 p.probs = cast(CLzmaProb *)malloc(numProbs * CLzmaProb.sizeof); 2818 p.numProbs = numProbs; 2819 if (!p.probs) 2820 return SRes.ERROR_MEM; 2821 } 2822 return SRes.OK; 2823 } 2824 2825 public SRes LzmaDec_AllocateProbs(CLzmaDec *p, const(Byte)* props, uint propsSize) 2826 { 2827 CLzmaProps propNew; 2828 if (auto sres = LzmaProps_Decode(&propNew, props, propsSize)) return sres; 2829 if (auto sres = LzmaDec_AllocateProbs2(p, &propNew)) return sres; 2830 p.prop = propNew; 2831 return SRes.OK; 2832 } 2833 2834 public SRes LzmaDec_Allocate(CLzmaDec *p, const(Byte)*props, uint propsSize) 2835 { 2836 import core.stdc.stdlib : malloc; 2837 CLzmaProps propNew; 2838 SizeT dicBufSize; 2839 if (auto sres = LzmaProps_Decode(&propNew, props, propsSize)) return sres; 2840 if (auto sres = LzmaDec_AllocateProbs2(p, &propNew)) return sres; 2841 2842 { 2843 UInt32 dictSize = propNew.dicSize; 2844 SizeT mask = (1U << 12) - 1; 2845 if (dictSize >= (1U << 30)) mask = (1U << 22) - 1; 2846 else if (dictSize >= (1U << 22)) mask = (1U << 20) - 1; 2847 dicBufSize = (cast(SizeT)dictSize + mask) & ~mask; 2848 if (dicBufSize < dictSize) 2849 dicBufSize = dictSize; 2850 } 2851 2852 if (!p.dic || dicBufSize != p.dicBufSize) 2853 { 2854 LzmaDec_FreeDict(p); 2855 p.dic = cast(Byte *)malloc(dicBufSize); 2856 if (!p.dic) 2857 { 2858 LzmaDec_FreeProbs(p); 2859 return SRes.ERROR_MEM; 2860 } 2861 } 2862 p.dicBufSize = dicBufSize; 2863 p.prop = propNew; 2864 return SRes.OK; 2865 } 2866 2867 public SRes LzmaDecode(Byte *dest, SizeT *destLen, const(Byte)* src, SizeT *srcLen, 2868 const(Byte)* propData, uint propSize, ELzmaFinishMode finishMode, 2869 ELzmaStatus *status) 2870 { 2871 CLzmaDec p; 2872 SRes res; 2873 SizeT outSize = *destLen, inSize = *srcLen; 2874 *destLen = *srcLen = 0; 2875 *status = LZMA_STATUS_NOT_SPECIFIED; 2876 if (inSize < RC_INIT_SIZE) 2877 return SRes.ERROR_INPUT_EOF; 2878 //LzmaDec_Construct(&p); 2879 p.dic = null; p.probs = null; 2880 if (auto sres = LzmaDec_AllocateProbs(&p, propData, propSize)) return sres; 2881 p.dic = dest; 2882 p.dicBufSize = outSize; 2883 LzmaDec_Init(&p); 2884 *srcLen = inSize; 2885 res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); 2886 *destLen = p.dicPos; 2887 if (res == SRes.OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) 2888 res = SRes.ERROR_INPUT_EOF; 2889 LzmaDec_FreeProbs(&p); 2890 return res; 2891 } 2892 2893 2894 2895 /* Lzma2Dec.c -- LZMA2 Decoder 2896 2009-05-03 : Igor Pavlov : Public domain */ 2897 // also by Lasse Collin 2898 // ported to D by adr. 2899 2900 /* 2901 00000000 - EOS 2902 00000001 U U - Uncompressed Reset Dic 2903 00000010 U U - Uncompressed No Reset 2904 100uuuuu U U P P - LZMA no reset 2905 101uuuuu U U P P - LZMA reset state 2906 110uuuuu U U P P S - LZMA reset state + new prop 2907 111uuuuu U U P P S - LZMA reset state + new prop + reset dic 2908 2909 u, U - Unpack Size 2910 P - Pack Size 2911 S - Props 2912 */ 2913 2914 struct CLzma2Dec 2915 { 2916 CLzmaDec decoder; 2917 UInt32 packSize; 2918 UInt32 unpackSize; 2919 int state; 2920 Byte control; 2921 bool needInitDic; 2922 bool needInitState; 2923 bool needInitProp; 2924 } 2925 2926 enum LZMA2_CONTROL_LZMA = (1 << 7); 2927 enum LZMA2_CONTROL_COPY_NO_RESET = 2; 2928 enum LZMA2_CONTROL_COPY_RESET_DIC = 1; 2929 enum LZMA2_CONTROL_EOF = 0; 2930 2931 auto LZMA2_IS_UNCOMPRESSED_STATE(P)(P p) { return (((p).control & LZMA2_CONTROL_LZMA) == 0); } 2932 2933 auto LZMA2_GET_LZMA_MODE(P)(P p) { return (((p).control >> 5) & 3); } 2934 auto LZMA2_IS_THERE_PROP(P)(P mode) { return ((mode) >= 2); } 2935 2936 enum LZMA2_LCLP_MAX = 4; 2937 auto LZMA2_DIC_SIZE_FROM_PROP(P)(P p) { return ((cast(UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)); } 2938 2939 enum ELzma2State 2940 { 2941 LZMA2_STATE_CONTROL, 2942 LZMA2_STATE_UNPACK0, 2943 LZMA2_STATE_UNPACK1, 2944 LZMA2_STATE_PACK0, 2945 LZMA2_STATE_PACK1, 2946 LZMA2_STATE_PROP, 2947 LZMA2_STATE_DATA, 2948 LZMA2_STATE_DATA_CONT, 2949 LZMA2_STATE_FINISHED, 2950 LZMA2_STATE_ERROR 2951 } 2952 2953 static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) 2954 { 2955 UInt32 dicSize; 2956 if (prop > 40) 2957 return SRes.ERROR_UNSUPPORTED; 2958 dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); 2959 props[0] = cast(Byte)LZMA2_LCLP_MAX; 2960 props[1] = cast(Byte)(dicSize); 2961 props[2] = cast(Byte)(dicSize >> 8); 2962 props[3] = cast(Byte)(dicSize >> 16); 2963 props[4] = cast(Byte)(dicSize >> 24); 2964 return SRes.OK; 2965 } 2966 2967 SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop) 2968 { 2969 Byte[LZMA_PROPS_SIZE] props; 2970 auto wtf = Lzma2Dec_GetOldProps(prop, props.ptr); 2971 if(wtf != 0) return wtf; 2972 return LzmaDec_AllocateProbs(&p.decoder, props.ptr, LZMA_PROPS_SIZE); 2973 } 2974 2975 SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop) 2976 { 2977 Byte[LZMA_PROPS_SIZE] props; 2978 auto wtf = Lzma2Dec_GetOldProps(prop, props.ptr); 2979 if(wtf != 0) return wtf; 2980 return LzmaDec_Allocate(&p.decoder, props.ptr, LZMA_PROPS_SIZE); 2981 } 2982 2983 void Lzma2Dec_Init(CLzma2Dec *p) 2984 { 2985 p.state = ELzma2State.LZMA2_STATE_CONTROL; 2986 p.needInitDic = true; 2987 p.needInitState = true; 2988 p.needInitProp = true; 2989 LzmaDec_Init(&p.decoder); 2990 } 2991 2992 static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) 2993 { 2994 switch(p.state) 2995 { 2996 default: return ELzma2State.LZMA2_STATE_ERROR; 2997 case ELzma2State.LZMA2_STATE_CONTROL: 2998 p.control = b; 2999 if (p.control == 0) 3000 return ELzma2State.LZMA2_STATE_FINISHED; 3001 if (LZMA2_IS_UNCOMPRESSED_STATE(p)) 3002 { 3003 if ((p.control & 0x7F) > 2) 3004 return ELzma2State.LZMA2_STATE_ERROR; 3005 p.unpackSize = 0; 3006 } 3007 else 3008 p.unpackSize = cast(UInt32)(p.control & 0x1F) << 16; 3009 return ELzma2State.LZMA2_STATE_UNPACK0; 3010 3011 case ELzma2State.LZMA2_STATE_UNPACK0: 3012 p.unpackSize |= cast(UInt32)b << 8; 3013 return ELzma2State.LZMA2_STATE_UNPACK1; 3014 3015 case ELzma2State.LZMA2_STATE_UNPACK1: 3016 p.unpackSize |= cast(UInt32)b; 3017 p.unpackSize++; 3018 return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? ELzma2State.LZMA2_STATE_DATA : ELzma2State.LZMA2_STATE_PACK0; 3019 3020 case ELzma2State.LZMA2_STATE_PACK0: 3021 p.packSize = cast(UInt32)b << 8; 3022 return ELzma2State.LZMA2_STATE_PACK1; 3023 3024 case ELzma2State.LZMA2_STATE_PACK1: 3025 p.packSize |= cast(UInt32)b; 3026 p.packSize++; 3027 return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? ELzma2State.LZMA2_STATE_PROP: 3028 (p.needInitProp ? ELzma2State.LZMA2_STATE_ERROR : ELzma2State.LZMA2_STATE_DATA); 3029 3030 case ELzma2State.LZMA2_STATE_PROP: 3031 { 3032 int lc, lp; 3033 if (b >= (9 * 5 * 5)) 3034 return ELzma2State.LZMA2_STATE_ERROR; 3035 lc = b % 9; 3036 b /= 9; 3037 p.decoder.prop.pb = b / 5; 3038 lp = b % 5; 3039 if (lc + lp > LZMA2_LCLP_MAX) 3040 return ELzma2State.LZMA2_STATE_ERROR; 3041 p.decoder.prop.lc = lc; 3042 p.decoder.prop.lp = lp; 3043 p.needInitProp = false; 3044 return ELzma2State.LZMA2_STATE_DATA; 3045 } 3046 } 3047 } 3048 3049 static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, Byte *src, SizeT size) 3050 { 3051 import core.stdc.string; 3052 memcpy(p.dic + p.dicPos, src, size); 3053 p.dicPos += size; 3054 if (p.checkDicSize == 0 && p.prop.dicSize - p.processedPos <= size) 3055 p.checkDicSize = p.prop.dicSize; 3056 p.processedPos += cast(UInt32)size; 3057 } 3058 3059 SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, 3060 Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) 3061 { 3062 SizeT inSize = *srcLen; 3063 *srcLen = 0; 3064 *status = LZMA_STATUS_NOT_SPECIFIED; 3065 3066 while (p.state != ELzma2State.LZMA2_STATE_FINISHED) 3067 { 3068 SizeT dicPos = p.decoder.dicPos; 3069 if (p.state == ELzma2State.LZMA2_STATE_ERROR) 3070 return SRes.ERROR_DATA; 3071 if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) 3072 { 3073 *status = LZMA_STATUS_NOT_FINISHED; 3074 return SRes.OK; 3075 } 3076 if (p.state != ELzma2State.LZMA2_STATE_DATA && p.state != ELzma2State.LZMA2_STATE_DATA_CONT) 3077 { 3078 if (*srcLen == inSize) 3079 { 3080 *status = LZMA_STATUS_NEEDS_MORE_INPUT; 3081 return SRes.OK; 3082 } 3083 (*srcLen)++; 3084 p.state = Lzma2Dec_UpdateState(p, *src++); 3085 continue; 3086 } 3087 { 3088 SizeT destSizeCur = dicLimit - dicPos; 3089 SizeT srcSizeCur = inSize - *srcLen; 3090 ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; 3091 3092 if (p.unpackSize <= destSizeCur) 3093 { 3094 destSizeCur = cast(SizeT)p.unpackSize; 3095 curFinishMode = LZMA_FINISH_END; 3096 } 3097 3098 if (LZMA2_IS_UNCOMPRESSED_STATE(p)) 3099 { 3100 if (*srcLen == inSize) 3101 { 3102 *status = LZMA_STATUS_NEEDS_MORE_INPUT; 3103 return SRes.OK; 3104 } 3105 3106 if (p.state == ELzma2State.LZMA2_STATE_DATA) 3107 { 3108 bool initDic = (p.control == LZMA2_CONTROL_COPY_RESET_DIC); 3109 if (initDic) 3110 p.needInitProp = p.needInitState = true; 3111 else if (p.needInitDic) 3112 return SRes.ERROR_DATA; 3113 p.needInitDic = false; 3114 LzmaDec_InitDicAndState(&p.decoder, initDic, false); 3115 } 3116 3117 if (srcSizeCur > destSizeCur) 3118 srcSizeCur = destSizeCur; 3119 3120 if (srcSizeCur == 0) 3121 return SRes.ERROR_DATA; 3122 3123 LzmaDec_UpdateWithUncompressed(&p.decoder, src, srcSizeCur); 3124 3125 src += srcSizeCur; 3126 *srcLen += srcSizeCur; 3127 p.unpackSize -= cast(UInt32)srcSizeCur; 3128 p.state = (p.unpackSize == 0) ? ELzma2State.LZMA2_STATE_CONTROL : ELzma2State.LZMA2_STATE_DATA_CONT; 3129 } 3130 else 3131 { 3132 SizeT outSizeProcessed; 3133 SRes res; 3134 3135 if (p.state == ELzma2State.LZMA2_STATE_DATA) 3136 { 3137 int mode = LZMA2_GET_LZMA_MODE(p); 3138 bool initDic = (mode == 3); 3139 bool initState = (mode > 0); 3140 if ((!initDic && p.needInitDic) || (!initState && p.needInitState)) 3141 return SRes.ERROR_DATA; 3142 3143 LzmaDec_InitDicAndState(&p.decoder, initDic, initState); 3144 p.needInitDic = false; 3145 p.needInitState = false; 3146 p.state = ELzma2State.LZMA2_STATE_DATA_CONT; 3147 } 3148 if (srcSizeCur > p.packSize) 3149 srcSizeCur = cast(SizeT)p.packSize; 3150 3151 res = LzmaDec_DecodeToDic(&p.decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status); 3152 3153 src += srcSizeCur; 3154 *srcLen += srcSizeCur; 3155 p.packSize -= cast(UInt32)srcSizeCur; 3156 3157 outSizeProcessed = p.decoder.dicPos - dicPos; 3158 p.unpackSize -= cast(UInt32)outSizeProcessed; 3159 3160 if(res != 0) return res; 3161 if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) 3162 return res; 3163 3164 if (srcSizeCur == 0 && outSizeProcessed == 0) 3165 { 3166 if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || 3167 p.unpackSize != 0 || p.packSize != 0) 3168 return SRes.ERROR_DATA; 3169 p.state = ELzma2State.LZMA2_STATE_CONTROL; 3170 } 3171 if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) 3172 *status = LZMA_STATUS_NOT_FINISHED; 3173 } 3174 } 3175 } 3176 *status = LZMA_STATUS_FINISHED_WITH_MARK; 3177 return SRes.OK; 3178 } 3179 3180 SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) 3181 { 3182 import core.stdc.string; 3183 SizeT outSize = *destLen, inSize = *srcLen; 3184 *srcLen = *destLen = 0; 3185 for (;;) 3186 { 3187 SizeT srcSizeCur = inSize, outSizeCur, dicPos; 3188 ELzmaFinishMode curFinishMode; 3189 SRes res; 3190 if (p.decoder.dicPos == p.decoder.dicBufSize) 3191 p.decoder.dicPos = 0; 3192 dicPos = p.decoder.dicPos; 3193 if (outSize > p.decoder.dicBufSize - dicPos) 3194 { 3195 outSizeCur = p.decoder.dicBufSize; 3196 curFinishMode = LZMA_FINISH_ANY; 3197 } 3198 else 3199 { 3200 outSizeCur = dicPos + outSize; 3201 curFinishMode = finishMode; 3202 } 3203 3204 res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status); 3205 src += srcSizeCur; 3206 inSize -= srcSizeCur; 3207 *srcLen += srcSizeCur; 3208 outSizeCur = p.decoder.dicPos - dicPos; 3209 memcpy(dest, p.decoder.dic + dicPos, outSizeCur); 3210 dest += outSizeCur; 3211 outSize -= outSizeCur; 3212 *destLen += outSizeCur; 3213 if (res != 0) 3214 return res; 3215 if (outSizeCur == 0 || outSize == 0) 3216 return SRes.OK; 3217 } 3218 } 3219 3220 SRes Lzma2Decode(Byte *dest, SizeT *destLen, Byte *src, SizeT *srcLen, 3221 Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status) 3222 { 3223 CLzma2Dec decoder; 3224 SRes res; 3225 SizeT outSize = *destLen, inSize = *srcLen; 3226 Byte[LZMA_PROPS_SIZE] props; 3227 3228 //Lzma2Dec_Construct(&decoder); 3229 3230 *destLen = *srcLen = 0; 3231 *status = LZMA_STATUS_NOT_SPECIFIED; 3232 decoder.decoder.dic = dest; 3233 decoder.decoder.dicBufSize = outSize; 3234 3235 auto wtf = Lzma2Dec_GetOldProps(prop, props.ptr); 3236 if(wtf != 0) return wtf; 3237 wtf = LzmaDec_AllocateProbs(&decoder.decoder, props.ptr, LZMA_PROPS_SIZE); 3238 if(wtf != 0) return wtf; 3239 3240 *srcLen = inSize; 3241 res = Lzma2Dec_DecodeToDic(&decoder, outSize, src, srcLen, finishMode, status); 3242 *destLen = decoder.decoder.dicPos; 3243 if (res == SRes.OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) 3244 res = SRes.ERROR_INPUT_EOF; 3245 3246 LzmaDec_FreeProbs(&decoder.decoder); 3247 return res; 3248 } 3249 3250 }