Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Compress / ArjDecoder2.cpp
1 // ArjDecoder2.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "ArjDecoder2.h"\r
6 \r
7 namespace NCompress{\r
8 namespace NArj {\r
9 namespace NDecoder2 {\r
10 \r
11 static const UInt32 kHistorySize = 26624;\r
12 static const UInt32 kMatchMinLen = 3;\r
13 \r
14 HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,\r
15     const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo * /* progress */)\r
16 {\r
17   if (outSize == NULL)\r
18     return E_INVALIDARG;\r
19 \r
20   if (!m_OutWindowStream.Create(kHistorySize))\r
21     return E_OUTOFMEMORY;\r
22   if (!m_InBitStream.Create(1 << 20))\r
23     return E_OUTOFMEMORY;\r
24 \r
25   UInt64 pos = 0;\r
26   m_OutWindowStream.SetStream(outStream);\r
27   m_OutWindowStream.Init(false);\r
28   m_InBitStream.SetStream(inStream);\r
29   m_InBitStream.Init();\r
30   CCoderReleaser coderReleaser(this);\r
31 \r
32   while(pos < *outSize)\r
33   {\r
34     const UInt32 kStartWidth = 0;\r
35     const UInt32 kStopWidth = 7;\r
36     UInt32 power = 1 << kStartWidth;\r
37     UInt32 width;\r
38     UInt32 len = 0;\r
39     for (width = kStartWidth; width < kStopWidth; width++)\r
40     {\r
41       if (m_InBitStream.ReadBits(1) == 0)\r
42         break;\r
43       len += power;\r
44       power <<= 1;\r
45     }\r
46     if (width != 0)\r
47       len += m_InBitStream.ReadBits(width);\r
48     if (len == 0)\r
49     {\r
50       m_OutWindowStream.PutByte((Byte)m_InBitStream.ReadBits(8));\r
51       pos++;\r
52       continue;\r
53     }\r
54     else\r
55     {\r
56       len = len - 1 + kMatchMinLen;\r
57       const UInt32 kStartWidth = 9;\r
58       const UInt32 kStopWidth = 13;\r
59       UInt32 power = 1 << kStartWidth;\r
60       UInt32 width;\r
61       UInt32 distance = 0;\r
62       for (width = kStartWidth; width < kStopWidth; width++)\r
63       {\r
64         if (m_InBitStream.ReadBits(1) == 0)\r
65           break;\r
66         distance += power;\r
67         power <<= 1;\r
68       }\r
69       if (width != 0)\r
70         distance += m_InBitStream.ReadBits(width);\r
71       if (distance >= pos)\r
72         return S_FALSE;\r
73       m_OutWindowStream.CopyBlock(distance, len);\r
74         pos += len;\r
75     }\r
76   }\r
77   coderReleaser.NeedFlush = false;\r
78   return m_OutWindowStream.Flush();\r
79 }\r
80 \r
81 STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,\r
82     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)\r
83 {\r
84   try { return CodeReal(inStream, outStream, inSize, outSize, progress);}\r
85   catch(const CInBufferException &e) { return e.ErrorCode; }\r
86   catch(const CLzOutWindowException &e) { return e.ErrorCode; }\r
87   catch(...) { return S_FALSE; }\r
88 }\r
89 \r
90 }}}\r