File: crn_lzma_codec.cpp

package info (click to toggle)
crunch-dxtc 0.55.5-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,640 kB
  • sloc: cpp: 64,978; ansic: 633; python: 321; makefile: 116
file content (128 lines) | stat: -rw-r--r-- 3,722 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// File: crn_lzma_codec.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_lzma_codec.h"
#include "crn_strutils.h"
#include "crn_checksum.h"
#include "lzma_LzmaLib.h"
#include "crn_threading.h"

namespace crnlib {
lzma_codec::lzma_codec()
    : m_pCompress(LzmaCompress),
      m_pUncompress(LzmaUncompress) {
  CRNLIB_ASSUME(cLZMAPropsSize == LZMA_PROPS_SIZE);
}

lzma_codec::~lzma_codec() {
}

bool lzma_codec::pack(const void* p, uint n, crnlib::vector<uint8>& buf) {
  if (n > 1024U * 1024U * 1024U)
    return false;

  uint max_comp_size = n + math::maximum<uint>(128, n >> 8);
  buf.resize(sizeof(header) + max_comp_size);

  header* pHDR = reinterpret_cast<header*>(&buf[0]);
  uint8* pComp_data = &buf[sizeof(header)];

  utils::zero_object(*pHDR);

  pHDR->m_uncomp_size = n;
  pHDR->m_adler32 = adler32(p, n);

  if (n) {
    size_t destLen = 0;
    size_t outPropsSize = 0;
    int status = SZ_ERROR_INPUT_EOF;

    for (uint trial = 0; trial < 3; trial++) {
      destLen = max_comp_size;
      outPropsSize = cLZMAPropsSize;

      status = (*m_pCompress)(pComp_data, &destLen, reinterpret_cast<const unsigned char*>(p), n,
                              pHDR->m_lzma_props, &outPropsSize,
                              -1, /* 0 <= level <= 9, default = 5 */
                              0,  /* default = (1 << 24) */
                              -1, /* 0 <= lc <= 8, default = 3  */
                              -1, /* 0 <= lp <= 4, default = 0  */
                              -1, /* 0 <= pb <= 4, default = 2  */
                              -1, /* 5 <= fb <= 273, default = 32 */
                              (g_number_of_processors > 1) ? 2 : 1
                              );

      if (status != SZ_ERROR_OUTPUT_EOF)
        break;

      max_comp_size += ((n + 1) / 2);
      buf.resize(sizeof(header) + max_comp_size);
      pHDR = reinterpret_cast<header*>(&buf[0]);
      pComp_data = &buf[sizeof(header)];
    }

    if (status != SZ_OK) {
      buf.clear();
      return false;
    }

    pHDR->m_comp_size = static_cast<uint>(destLen);

    buf.resize(CRNLIB_SIZEOF_U32(header) + static_cast<uint32>(destLen));
  }

  pHDR->m_sig = header::cSig;
  pHDR->m_checksum = static_cast<uint8>(adler32((uint8*)pHDR + header::cChecksumSkipBytes, sizeof(header) - header::cChecksumSkipBytes));

  return true;
}

bool lzma_codec::unpack(const void* p, uint n, crnlib::vector<uint8>& buf) {
  buf.resize(0);

  if (n < sizeof(header))
    return false;

  const header& hdr = *static_cast<const header*>(p);
  if (hdr.m_sig != header::cSig)
    return false;

  if (static_cast<uint8>(adler32((const uint8*)&hdr + header::cChecksumSkipBytes, sizeof(hdr) - header::cChecksumSkipBytes)) != hdr.m_checksum)
    return false;

  if (!hdr.m_uncomp_size)
    return true;

  if (!hdr.m_comp_size)
    return false;

  if (hdr.m_uncomp_size > 1024U * 1024U * 1024U)
    return false;

  if (!buf.try_resize(hdr.m_uncomp_size))
    return false;

  const uint8* pComp_data = static_cast<const uint8*>(p) + sizeof(header);
  size_t srcLen = n - sizeof(header);
  if (srcLen < hdr.m_comp_size)
    return false;

  size_t destLen = hdr.m_uncomp_size;

  int status = (*m_pUncompress)(&buf[0], &destLen, pComp_data, &srcLen,
                                hdr.m_lzma_props, cLZMAPropsSize);

  if ((status != SZ_OK) || (destLen != hdr.m_uncomp_size)) {
    buf.clear();
    return false;
  }

  if (adler32(&buf[0], buf.size()) != hdr.m_adler32) {
    buf.clear();
    return false;
  }

  return true;
}

}  // namespace crnlib