Welcome to mirror list, hosted at ThFree Co, Russian Federation.

XpressDecoder.cpp « Compress « 7zip « CPP - github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: a38d941812f8ad08991650f066b5dcef686bac87 (plain)
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
129
// XpressDecoder.cpp

#include "StdAfx.h"

// #include <stdio.h>

#include "../../../C/CpuArch.h"

#include "HuffmanDecoder.h"

namespace NCompress {
namespace NXpress {

struct CBitStream
{
  UInt32 Value;
  unsigned BitPos;

  UInt32 GetValue(unsigned numBits) const
  {
    return (Value >> (BitPos - numBits)) & ((1 << numBits) - 1);
  }
  
  void MovePos(unsigned numBits)
  {
    BitPos -= numBits;
  }
};

#define BIT_STREAM_NORMALIZE \
    if (bs.BitPos < 16) { \
      if (in >= lim) return S_FALSE; \
      bs.Value = (bs.Value << 16) | GetUi16(in); \
      in += 2; bs.BitPos += 16; }
 
const unsigned kNumHuffBits = 15;
const unsigned kNumLenSlots = 16;
const unsigned kNumPosSlots = 16;
const unsigned kNumSyms = 256 + kNumPosSlots * kNumLenSlots;

HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize)
{
  NCompress::NHuffman::CDecoder<kNumHuffBits, kNumSyms> huff;
  
  if (inSize < kNumSyms / 2 + 4)
    return S_FALSE;
  {
    Byte levels[kNumSyms];
    for (unsigned i = 0; i < kNumSyms / 2; i++)
    {
      Byte b = in[i];
      levels[(size_t)i * 2] = (Byte)(b & 0xF);
      levels[(size_t)i * 2 + 1] = (Byte)(b >> 4);
    }
    if (!huff.BuildFull(levels))
      return S_FALSE;
  }


  CBitStream bs;

  const Byte *lim = in + inSize - 1;

  in += kNumSyms / 2;
  bs.Value = (GetUi16(in) << 16) | GetUi16(in + 2);
  in += 4;
  bs.BitPos = 32;

  size_t pos = 0;

  for (;;)
  {
    // printf("\n%d", pos);
    UInt32 sym = huff.DecodeFull(&bs);
    // printf(" sym = %d", sym);
    BIT_STREAM_NORMALIZE

    if (pos >= outSize)
      return (sym == 256 && in == lim + 1) ? S_OK : S_FALSE;

    if (sym < 256)
      out[pos++] = (Byte)sym;
    else
    {
      sym -= 256;
      UInt32 dist = sym / kNumLenSlots;
      UInt32 len = sym & (kNumLenSlots - 1);
      
      if (len == kNumLenSlots - 1)
      {
        if (in > lim)
          return S_FALSE;
        len = *in++;
        if (len == 0xFF)
        {
          if (in >= lim)
            return S_FALSE;
          len = GetUi16(in);
          in += 2;
        }
        else
          len += kNumLenSlots - 1;
      }

      bs.BitPos -= dist;
      dist = (UInt32)1 << dist;
      dist += ((bs.Value >> bs.BitPos) & (dist - 1));

      BIT_STREAM_NORMALIZE
      
      if (len > outSize - pos)
        return S_FALSE;
      if (dist > pos)
        return S_FALSE;

      Byte *dest = out + pos;
      const Byte *src = dest - dist;
      pos += len + 3;
      len += 1;
      *dest++ = *src++;
      *dest++ = *src++;
      do
        *dest++ = *src++;
      while (--len);
    }
  }
}

}}