rlm@1
|
1 // Archive/LzhIn.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 #include "Common/StringConvert.h"
|
rlm@1
|
6 #include "Common/Buffer.h"
|
rlm@1
|
7
|
rlm@1
|
8 #include "../../Common/StreamUtils.h"
|
rlm@1
|
9
|
rlm@1
|
10 #include "LzhIn.h"
|
rlm@1
|
11
|
rlm@1
|
12 namespace NArchive {
|
rlm@1
|
13 namespace NLzh {
|
rlm@1
|
14
|
rlm@1
|
15 HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
|
rlm@1
|
16 {
|
rlm@1
|
17 size_t realProcessedSize = size;
|
rlm@1
|
18 RINOK(ReadStream(m_Stream, data, &realProcessedSize));
|
rlm@1
|
19 processedSize = (UInt32)realProcessedSize;
|
rlm@1
|
20 m_Position += processedSize;
|
rlm@1
|
21 return S_OK;
|
rlm@1
|
22 }
|
rlm@1
|
23
|
rlm@1
|
24 HRESULT CInArchive::CheckReadBytes(void *data, UInt32 size)
|
rlm@1
|
25 {
|
rlm@1
|
26 UInt32 processedSize;
|
rlm@1
|
27 RINOK(ReadBytes(data, size, processedSize));
|
rlm@1
|
28 return (processedSize == size) ? S_OK: S_FALSE;
|
rlm@1
|
29 }
|
rlm@1
|
30
|
rlm@1
|
31 HRESULT CInArchive::Open(IInStream *inStream)
|
rlm@1
|
32 {
|
rlm@1
|
33 RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
|
rlm@1
|
34 m_Stream = inStream;
|
rlm@1
|
35 return S_OK;
|
rlm@1
|
36 }
|
rlm@1
|
37
|
rlm@1
|
38 static const Byte *ReadUInt32(const Byte *p, UInt32 &v)
|
rlm@1
|
39 {
|
rlm@1
|
40 v = 0;
|
rlm@1
|
41 for (int i = 0; i < 4; i++)
|
rlm@1
|
42 v |= ((UInt32)(*p++) << (i * 8));
|
rlm@1
|
43 return p;
|
rlm@1
|
44 }
|
rlm@1
|
45
|
rlm@1
|
46 static const Byte *ReadUInt16(const Byte *p, UInt16 &v)
|
rlm@1
|
47 {
|
rlm@1
|
48 v = 0;
|
rlm@1
|
49 for (int i = 0; i < 2; i++)
|
rlm@1
|
50 v |= ((UInt16)(*p++) << (i * 8));
|
rlm@1
|
51 return p;
|
rlm@1
|
52 }
|
rlm@1
|
53
|
rlm@1
|
54 static const Byte *ReadString(const Byte *p, size_t size, AString &s)
|
rlm@1
|
55 {
|
rlm@1
|
56 s.Empty();
|
rlm@1
|
57 for (size_t i = 0; i < size; i++)
|
rlm@1
|
58 {
|
rlm@1
|
59 char c = p[i];
|
rlm@1
|
60 if (c == 0)
|
rlm@1
|
61 break;
|
rlm@1
|
62 s += c;
|
rlm@1
|
63 }
|
rlm@1
|
64 return p + size;
|
rlm@1
|
65 }
|
rlm@1
|
66
|
rlm@1
|
67 static Byte CalcSum(const Byte *data, size_t size)
|
rlm@1
|
68 {
|
rlm@1
|
69 Byte sum = 0;
|
rlm@1
|
70 for (size_t i = 0; i < size; i++)
|
rlm@1
|
71 sum = (Byte)(sum + data[i]);
|
rlm@1
|
72 return sum;
|
rlm@1
|
73 }
|
rlm@1
|
74
|
rlm@1
|
75 HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
|
rlm@1
|
76 {
|
rlm@1
|
77 filled = false;
|
rlm@1
|
78
|
rlm@1
|
79 UInt32 processedSize;
|
rlm@1
|
80 Byte startHeader[2];
|
rlm@1
|
81 RINOK(ReadBytes(startHeader, 2, processedSize))
|
rlm@1
|
82 if (processedSize == 0)
|
rlm@1
|
83 return S_OK;
|
rlm@1
|
84 if (processedSize == 1)
|
rlm@1
|
85 return (startHeader[0] == 0) ? S_OK: S_FALSE;
|
rlm@1
|
86 if (startHeader[0] == 0 && startHeader[1] == 0)
|
rlm@1
|
87 return S_OK;
|
rlm@1
|
88
|
rlm@1
|
89 Byte header[256];
|
rlm@1
|
90 const UInt32 kBasicPartSize = 22;
|
rlm@1
|
91 RINOK(ReadBytes(header, kBasicPartSize, processedSize));
|
rlm@1
|
92 if (processedSize != kBasicPartSize)
|
rlm@1
|
93 return (startHeader[0] == 0) ? S_OK: S_FALSE;
|
rlm@1
|
94
|
rlm@1
|
95 const Byte *p = header;
|
rlm@1
|
96 memmove(item.Method, p, kMethodIdSize);
|
rlm@1
|
97 if (!item.IsValidMethod())
|
rlm@1
|
98 return S_OK;
|
rlm@1
|
99 p += kMethodIdSize;
|
rlm@1
|
100 p = ReadUInt32(p, item.PackSize);
|
rlm@1
|
101 p = ReadUInt32(p, item.Size);
|
rlm@1
|
102 p = ReadUInt32(p, item.ModifiedTime);
|
rlm@1
|
103 item.Attributes = *p++;
|
rlm@1
|
104 item.Level = *p++;
|
rlm@1
|
105 if (item.Level > 2)
|
rlm@1
|
106 return S_FALSE;
|
rlm@1
|
107 UInt32 headerSize;
|
rlm@1
|
108 if (item.Level < 2)
|
rlm@1
|
109 {
|
rlm@1
|
110 headerSize = startHeader[0];
|
rlm@1
|
111 if (headerSize < kBasicPartSize)
|
rlm@1
|
112 return S_FALSE;
|
rlm@1
|
113 UInt32 remain = headerSize - kBasicPartSize;
|
rlm@1
|
114 RINOK(CheckReadBytes(header + kBasicPartSize, remain));
|
rlm@1
|
115 if (startHeader[1] != CalcSum(header, headerSize))
|
rlm@1
|
116 return S_FALSE;
|
rlm@1
|
117 size_t nameLength = *p++;
|
rlm@1
|
118 if ((p - header) + nameLength + 2 > headerSize)
|
rlm@1
|
119 return S_FALSE;
|
rlm@1
|
120 p = ReadString(p, nameLength, item.Name);
|
rlm@1
|
121 }
|
rlm@1
|
122 else
|
rlm@1
|
123 headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8);
|
rlm@1
|
124 p = ReadUInt16(p, item.CRC);
|
rlm@1
|
125 if (item.Level != 0)
|
rlm@1
|
126 {
|
rlm@1
|
127 if (item.Level == 2)
|
rlm@1
|
128 {
|
rlm@1
|
129 RINOK(CheckReadBytes(header + kBasicPartSize, 2));
|
rlm@1
|
130 }
|
rlm@1
|
131 if ((size_t)(p - header) + 3 > headerSize)
|
rlm@1
|
132 return S_FALSE;
|
rlm@1
|
133 item.OsId = *p++;
|
rlm@1
|
134 UInt16 nextSize;
|
rlm@1
|
135 p = ReadUInt16(p, nextSize);
|
rlm@1
|
136 while (nextSize != 0)
|
rlm@1
|
137 {
|
rlm@1
|
138 if (nextSize < 3)
|
rlm@1
|
139 return S_FALSE;
|
rlm@1
|
140 if (item.Level == 1)
|
rlm@1
|
141 {
|
rlm@1
|
142 if (item.PackSize < nextSize)
|
rlm@1
|
143 return S_FALSE;
|
rlm@1
|
144 item.PackSize -= nextSize;
|
rlm@1
|
145 }
|
rlm@1
|
146 CExtension ext;
|
rlm@1
|
147 RINOK(CheckReadBytes(&ext.Type, 1))
|
rlm@1
|
148 nextSize -= 3;
|
rlm@1
|
149 ext.Data.SetCapacity(nextSize);
|
rlm@1
|
150 RINOK(CheckReadBytes((Byte *)ext.Data, nextSize))
|
rlm@1
|
151 item.Extensions.Add(ext);
|
rlm@1
|
152 Byte hdr2[2];
|
rlm@1
|
153 RINOK(CheckReadBytes(hdr2, 2));
|
rlm@1
|
154 ReadUInt16(hdr2, nextSize);
|
rlm@1
|
155 }
|
rlm@1
|
156 }
|
rlm@1
|
157 item.DataPosition = m_Position;
|
rlm@1
|
158 filled = true;
|
rlm@1
|
159 return S_OK;
|
rlm@1
|
160 }
|
rlm@1
|
161
|
rlm@1
|
162 HRESULT CInArchive::Skeep(UInt64 numBytes)
|
rlm@1
|
163 {
|
rlm@1
|
164 UInt64 newPostion;
|
rlm@1
|
165 RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
|
rlm@1
|
166 m_Position += numBytes;
|
rlm@1
|
167 if (m_Position != newPostion)
|
rlm@1
|
168 return E_FAIL;
|
rlm@1
|
169 return S_OK;
|
rlm@1
|
170 }
|
rlm@1
|
171
|
rlm@1
|
172 }}
|