annotate src/win32/7zip/7z/CPP/7zip/Compress/LzhDecoder.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
rev   line source
rlm@1 1 // LzhDecoder.cpp
rlm@1 2
rlm@1 3 #include "StdAfx.h"
rlm@1 4
rlm@1 5 #include "LzhDecoder.h"
rlm@1 6
rlm@1 7 #include "Windows/Defs.h"
rlm@1 8
rlm@1 9 namespace NCompress{
rlm@1 10 namespace NLzh {
rlm@1 11 namespace NDecoder {
rlm@1 12
rlm@1 13 static const UInt32 kHistorySize = (1 << 16);
rlm@1 14
rlm@1 15 static const int kBlockSizeBits = 16;
rlm@1 16 static const int kNumCBits = 9;
rlm@1 17 static const int kNumLevelBits = 5; // smallest integer such that (1 << kNumLevelBits) > kNumLevelSymbols/
rlm@1 18
rlm@1 19 UInt32 CCoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
rlm@1 20
rlm@1 21 HRESULT CCoder::ReadLevelTable()
rlm@1 22 {
rlm@1 23 int n = ReadBits(kNumLevelBits);
rlm@1 24 if (n == 0)
rlm@1 25 {
rlm@1 26 m_LevelHuffman.Symbol = ReadBits(kNumLevelBits);
rlm@1 27 if (m_LevelHuffman.Symbol >= kNumLevelSymbols)
rlm@1 28 return S_FALSE;
rlm@1 29 }
rlm@1 30 else
rlm@1 31 {
rlm@1 32 if (n > kNumLevelSymbols)
rlm@1 33 return S_FALSE;
rlm@1 34 m_LevelHuffman.Symbol = -1;
rlm@1 35 Byte lens[kNumLevelSymbols];
rlm@1 36 int i = 0;
rlm@1 37 while (i < n)
rlm@1 38 {
rlm@1 39 int c = m_InBitStream.ReadBits(3);
rlm@1 40 if (c == 7)
rlm@1 41 while (ReadBits(1))
rlm@1 42 if (c++ > kMaxHuffmanLen)
rlm@1 43 return S_FALSE;
rlm@1 44 lens[i++] = (Byte)c;
rlm@1 45 if (i == kNumSpecLevelSymbols)
rlm@1 46 {
rlm@1 47 c = ReadBits(2);
rlm@1 48 while (--c >= 0)
rlm@1 49 lens[i++] = 0;
rlm@1 50 }
rlm@1 51 }
rlm@1 52 while (i < kNumLevelSymbols)
rlm@1 53 lens[i++] = 0;
rlm@1 54 m_LevelHuffman.SetCodeLengths(lens);
rlm@1 55 }
rlm@1 56 return S_OK;
rlm@1 57 }
rlm@1 58
rlm@1 59 HRESULT CCoder::ReadPTable(int numBits)
rlm@1 60 {
rlm@1 61 int n = ReadBits(numBits);
rlm@1 62 if (n == 0)
rlm@1 63 {
rlm@1 64 m_PHuffmanDecoder.Symbol = ReadBits(numBits);
rlm@1 65 if (m_PHuffmanDecoder.Symbol >= kNumDistanceSymbols)
rlm@1 66 return S_FALSE;
rlm@1 67 }
rlm@1 68 else
rlm@1 69 {
rlm@1 70 if (n > kNumDistanceSymbols)
rlm@1 71 return S_FALSE;
rlm@1 72 m_PHuffmanDecoder.Symbol = -1;
rlm@1 73 Byte lens[kNumDistanceSymbols];
rlm@1 74 int i = 0;
rlm@1 75 while (i < n)
rlm@1 76 {
rlm@1 77 int c = m_InBitStream.ReadBits(3);
rlm@1 78 if (c == 7)
rlm@1 79 while (ReadBits(1))
rlm@1 80 {
rlm@1 81 if (c > kMaxHuffmanLen)
rlm@1 82 return S_FALSE;
rlm@1 83 c++;
rlm@1 84 }
rlm@1 85 lens[i++] = (Byte)c;
rlm@1 86 }
rlm@1 87 while (i < kNumDistanceSymbols)
rlm@1 88 lens[i++] = 0;
rlm@1 89 m_PHuffmanDecoder.SetCodeLengths(lens);
rlm@1 90 }
rlm@1 91 return S_OK;
rlm@1 92 }
rlm@1 93
rlm@1 94 HRESULT CCoder::ReadCTable()
rlm@1 95 {
rlm@1 96 int n = ReadBits(kNumCBits);
rlm@1 97 if (n == 0)
rlm@1 98 {
rlm@1 99 m_CHuffmanDecoder.Symbol = ReadBits(kNumCBits);
rlm@1 100 if (m_CHuffmanDecoder.Symbol >= kNumCSymbols)
rlm@1 101 return S_FALSE;
rlm@1 102 }
rlm@1 103 else
rlm@1 104 {
rlm@1 105 if (n > kNumCSymbols)
rlm@1 106 return S_FALSE;
rlm@1 107 m_CHuffmanDecoder.Symbol = -1;
rlm@1 108 Byte lens[kNumCSymbols];
rlm@1 109 int i = 0;
rlm@1 110 while (i < n)
rlm@1 111 {
rlm@1 112 int c = m_LevelHuffman.Decode(&m_InBitStream);
rlm@1 113 if (c < kNumSpecLevelSymbols)
rlm@1 114 {
rlm@1 115 if (c == 0)
rlm@1 116 c = 1;
rlm@1 117 else if (c == 1)
rlm@1 118 c = ReadBits(4) + 3;
rlm@1 119 else
rlm@1 120 c = ReadBits(kNumCBits) + 20;
rlm@1 121 while (--c >= 0)
rlm@1 122 {
rlm@1 123 if (i > kNumCSymbols)
rlm@1 124 return S_FALSE;
rlm@1 125 lens[i++] = 0;
rlm@1 126 }
rlm@1 127 }
rlm@1 128 else
rlm@1 129 lens[i++] = (Byte)(c - 2);
rlm@1 130 }
rlm@1 131 while (i < kNumCSymbols)
rlm@1 132 lens[i++] = 0;
rlm@1 133 m_CHuffmanDecoder.SetCodeLengths(lens);
rlm@1 134 }
rlm@1 135 return S_OK;
rlm@1 136 }
rlm@1 137
rlm@1 138 STDMETHODIMP CCoder::CodeReal(ISequentialInStream *inStream,
rlm@1 139 ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize,
rlm@1 140 ICompressProgressInfo *progress)
rlm@1 141 {
rlm@1 142 if (outSize == NULL)
rlm@1 143 return E_INVALIDARG;
rlm@1 144
rlm@1 145 if (!m_OutWindowStream.Create(kHistorySize))
rlm@1 146 return E_OUTOFMEMORY;
rlm@1 147 if (!m_InBitStream.Create(1 << 20))
rlm@1 148 return E_OUTOFMEMORY;
rlm@1 149
rlm@1 150 UInt64 pos = 0;
rlm@1 151 m_OutWindowStream.SetStream(outStream);
rlm@1 152 m_OutWindowStream.Init(false);
rlm@1 153 m_InBitStream.SetStream(inStream);
rlm@1 154 m_InBitStream.Init();
rlm@1 155
rlm@1 156 CCoderReleaser coderReleaser(this);
rlm@1 157
rlm@1 158 int pbit;
rlm@1 159 if (m_NumDictBits <= 13)
rlm@1 160 pbit = 4;
rlm@1 161 else
rlm@1 162 pbit = 5;
rlm@1 163
rlm@1 164 UInt32 blockSize = 0;
rlm@1 165
rlm@1 166 while(pos < *outSize)
rlm@1 167 {
rlm@1 168 // for (i = 0; i < dictSize; i++) dtext[i] = 0x20;
rlm@1 169
rlm@1 170 if (blockSize == 0)
rlm@1 171 {
rlm@1 172 if (progress != NULL)
rlm@1 173 {
rlm@1 174 UInt64 packSize = m_InBitStream.GetProcessedSize();
rlm@1 175 RINOK(progress->SetRatioInfo(&packSize, &pos));
rlm@1 176 }
rlm@1 177 blockSize = ReadBits(kBlockSizeBits);
rlm@1 178 ReadLevelTable();
rlm@1 179 ReadCTable();
rlm@1 180 RINOK(ReadPTable(pbit));
rlm@1 181 }
rlm@1 182 blockSize--;
rlm@1 183 UInt32 c = m_CHuffmanDecoder.Decode(&m_InBitStream);
rlm@1 184 if (c < 256)
rlm@1 185 {
rlm@1 186 m_OutWindowStream.PutByte((Byte)c);
rlm@1 187 pos++;
rlm@1 188 }
rlm@1 189 else if (c >= kNumCSymbols)
rlm@1 190 return S_FALSE;
rlm@1 191 else
rlm@1 192 {
rlm@1 193 // offset = (interface->method == LARC_METHOD_NUM) ? 0x100 - 2 : 0x100 - 3;
rlm@1 194 UInt32 len = c - 256 + kMinMatch;
rlm@1 195 UInt32 distance = m_PHuffmanDecoder.Decode(&m_InBitStream);
rlm@1 196 if (distance != 0)
rlm@1 197 distance = (1 << (distance - 1)) + ReadBits(distance - 1);
rlm@1 198 if (distance >= pos)
rlm@1 199 return S_FALSE;
rlm@1 200 if (pos + len > *outSize)
rlm@1 201 len = (UInt32)(*outSize - pos);
rlm@1 202 pos += len;
rlm@1 203 m_OutWindowStream.CopyBlock(distance, len);
rlm@1 204 }
rlm@1 205 }
rlm@1 206 coderReleaser.NeedFlush = false;
rlm@1 207 return m_OutWindowStream.Flush();
rlm@1 208 }
rlm@1 209
rlm@1 210 STDMETHODIMP CCoder::Code(ISequentialInStream *inStream,
rlm@1 211 ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
rlm@1 212 ICompressProgressInfo *progress)
rlm@1 213 {
rlm@1 214 try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
rlm@1 215 catch(const CInBufferException &e) { return e.ErrorCode; }
rlm@1 216 catch(const CLzOutWindowException &e) { return e.ErrorCode; }
rlm@1 217 catch(...) { return S_FALSE; }
rlm@1 218 }
rlm@1 219
rlm@1 220 }}}