"Fossies" - the Fresh Open Source Software Archive 
Member "unrar/qopen.cpp" (4 May 2022, 6905 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "qopen.cpp" see the
Fossies "Dox" file reference documentation.
1 #include "rar.hpp"
2
3 QuickOpen::QuickOpen()
4 {
5 Buf=NULL;
6 Init(NULL,false);
7 }
8
9
10 QuickOpen::~QuickOpen()
11 {
12 Close();
13 delete[] Buf;
14 }
15
16
17 void QuickOpen::Init(Archive *Arc,bool WriteMode)
18 {
19 if (Arc!=NULL) // Unless called from constructor.
20 Close();
21
22 QuickOpen::Arc=Arc;
23 QuickOpen::WriteMode=WriteMode;
24
25 ListStart=NULL;
26 ListEnd=NULL;
27
28 if (Buf==NULL)
29 Buf=new byte[MaxBufSize];
30
31 CurBufSize=0; // Current size of buffered data in write mode.
32
33 Loaded=false;
34 }
35
36
37 void QuickOpen::Close()
38 {
39 QuickOpenItem *Item=ListStart;
40 while (Item!=NULL)
41 {
42 QuickOpenItem *Next=Item->Next;
43 delete[] Item->Header;
44 delete Item;
45 Item=Next;
46 }
47 }
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 void QuickOpen::Load(uint64 BlockPos)
63 {
64 if (!Loaded)
65 {
66 // If loading for the first time, perform additional intialization.
67 SeekPos=Arc->Tell();
68 UnsyncSeekPos=false;
69
70 int64 SavePos=SeekPos;
71 Arc->Seek(BlockPos,SEEK_SET);
72
73 // If BlockPos points to original main header, we'll have the infinite
74 // recursion, because ReadHeader() for main header will attempt to load
75 // QOpen and call QuickOpen::Load again. If BlockPos points to long chain
76 // of other main headers, we'll have multiple recursive calls of this
77 // function wasting resources. So we prohibit QOpen temporarily to
78 // prevent this. ReadHeader() calls QOpen.Init and sets MainHead Locator
79 // and QOpenOffset fields, so we cannot use them to prohibit QOpen.
80 Arc->SetProhibitQOpen(true);
81 size_t ReadSize=Arc->ReadHeader();
82 Arc->SetProhibitQOpen(false);
83
84 if (ReadSize==0 || Arc->GetHeaderType()!=HEAD_SERVICE ||
85 !Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN))
86 {
87 Arc->Seek(SavePos,SEEK_SET);
88 return;
89 }
90 QOHeaderPos=Arc->CurBlockPos;
91 RawDataStart=Arc->Tell();
92 RawDataSize=Arc->SubHead.UnpSize;
93 Arc->Seek(SavePos,SEEK_SET);
94
95 Loaded=true; // Set only after all file processing calls like Tell, Seek, ReadHeader.
96 }
97
98 if (Arc->SubHead.Encrypted)
99 {
100 RAROptions *Cmd=Arc->GetRAROptions();
101 #ifndef RAR_NOCRYPT
102 if (Cmd->Password.IsSet())
103 Crypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,Arc->SubHead.Salt,
104 Arc->SubHead.InitV,Arc->SubHead.Lg2Count,
105 Arc->SubHead.HashKey,Arc->SubHead.PswCheck);
106 else
107 #endif
108 {
109 Loaded=false;
110 return;
111 }
112 }
113
114 RawDataPos=0;
115 ReadBufSize=0;
116 ReadBufPos=0;
117 LastReadHeader.Reset();
118 LastReadHeaderPos=0;
119
120 ReadBuffer();
121 }
122
123
124 bool QuickOpen::Read(void *Data,size_t Size,size_t &Result)
125 {
126 if (!Loaded)
127 return false;
128 // Find next suitable cached block.
129 while (LastReadHeaderPos+LastReadHeader.Size()<=SeekPos)
130 if (!ReadNext())
131 break;
132 if (!Loaded)
133 {
134 // If something wrong happened, let's set the correct file pointer
135 // and stop further quick open processing.
136 if (UnsyncSeekPos)
137 Arc->File::Seek(SeekPos,SEEK_SET);
138 return false;
139 }
140
141 if (SeekPos>=LastReadHeaderPos && SeekPos+Size<=LastReadHeaderPos+LastReadHeader.Size())
142 {
143 memcpy(Data,LastReadHeader+size_t(SeekPos-LastReadHeaderPos),Size);
144 Result=Size;
145 SeekPos+=Size;
146 UnsyncSeekPos=true;
147 }
148 else
149 {
150 if (UnsyncSeekPos)
151 {
152 Arc->File::Seek(SeekPos,SEEK_SET);
153 UnsyncSeekPos=false;
154 }
155 int ReadSize=Arc->File::Read(Data,Size);
156 if (ReadSize<0)
157 {
158 Loaded=false;
159 return false;
160 }
161 Result=ReadSize;
162 SeekPos+=ReadSize;
163 }
164
165 return true;
166 }
167
168
169 bool QuickOpen::Seek(int64 Offset,int Method)
170 {
171 if (!Loaded)
172 return false;
173
174 // Normally we process an archive sequentially from beginning to end,
175 // so we read quick open data sequentially. But some operations like
176 // archive updating involve several passes. So if we detect that file
177 // pointer is moved back, we reload quick open data from beginning.
178 if (Method==SEEK_SET && (uint64)Offset<SeekPos && (uint64)Offset<LastReadHeaderPos)
179 Load(QOHeaderPos);
180
181 if (Method==SEEK_SET)
182 SeekPos=Offset;
183 if (Method==SEEK_CUR)
184 SeekPos+=Offset;
185 UnsyncSeekPos=true;
186
187 if (Method==SEEK_END)
188 {
189 Arc->File::Seek(Offset,SEEK_END);
190 SeekPos=Arc->File::Tell();
191 UnsyncSeekPos=false;
192 }
193 return true;
194 }
195
196
197 bool QuickOpen::Tell(int64 *Pos)
198 {
199 if (!Loaded)
200 return false;
201 *Pos=SeekPos;
202 return true;
203 }
204
205
206 uint QuickOpen::ReadBuffer()
207 {
208 int64 SavePos=Arc->Tell();
209 Arc->File::Seek(RawDataStart+RawDataPos,SEEK_SET);
210 size_t SizeToRead=(size_t)Min(RawDataSize-RawDataPos,MaxBufSize-ReadBufSize);
211 if (Arc->SubHead.Encrypted)
212 SizeToRead &= ~CRYPT_BLOCK_MASK;
213 int ReadSize=0;
214 if (SizeToRead!=0)
215 {
216 ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
217 if (ReadSize<=0)
218 ReadSize=0;
219 else
220 {
221 #ifndef RAR_NOCRYPT
222 if (Arc->SubHead.Encrypted)
223 Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK);
224 #endif
225 RawDataPos+=ReadSize;
226 ReadBufSize+=ReadSize;
227 }
228 }
229 Arc->Seek(SavePos,SEEK_SET);
230 return ReadSize;
231 }
232
233
234 // Fill RawRead object from buffer.
235 bool QuickOpen::ReadRaw(RawRead &Raw)
236 {
237 if (MaxBufSize-ReadBufPos<0x100) // We are close to end of buffer.
238 {
239 // Ensure that we have enough data to read CRC and header size.
240 size_t DataLeft=ReadBufSize-ReadBufPos;
241 memcpy(Buf,Buf+ReadBufPos,DataLeft);
242 ReadBufPos=0;
243 ReadBufSize=DataLeft;
244 ReadBuffer();
245 }
246 const size_t FirstReadSize=7;
247 if (ReadBufPos+FirstReadSize>ReadBufSize)
248 return false;
249 Raw.Read(Buf+ReadBufPos,FirstReadSize);
250 ReadBufPos+=FirstReadSize;
251
252 uint SavedCRC=Raw.Get4();
253 uint SizeBytes=Raw.GetVSize(4);
254 uint64 BlockSize=Raw.GetV();
255 int SizeToRead=int(BlockSize);
256 SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
257 if (SizeToRead<0 || SizeBytes==0 || BlockSize==0)
258 {
259 Loaded=false; // Invalid data.
260 return false;
261 }
262
263 // If rest of block data crosses Buf boundary, read it in loop.
264 while (SizeToRead>0)
265 {
266 size_t DataLeft=ReadBufSize-ReadBufPos;
267 size_t CurSizeToRead=Min(DataLeft,(size_t)SizeToRead);
268 Raw.Read(Buf+ReadBufPos,CurSizeToRead);
269 ReadBufPos+=CurSizeToRead;
270 SizeToRead-=int(CurSizeToRead);
271 if (SizeToRead>0) // We read the entire buffer and still need more data.
272 {
273 ReadBufPos=0;
274 ReadBufSize=0;
275 if (ReadBuffer()==0)
276 return false;
277 }
278 }
279
280 return SavedCRC==Raw.GetCRC50();
281 }
282
283
284 // Read next cached header.
285 bool QuickOpen::ReadNext()
286 {
287 RawRead Raw(NULL);
288 if (!ReadRaw(Raw)) // Read internal quick open header preceding stored block.
289 return false;
290 uint Flags=(uint)Raw.GetV();
291 uint64 Offset=Raw.GetV();
292 size_t HeaderSize=(size_t)Raw.GetV();
293 if (HeaderSize>MAX_HEADER_SIZE_RAR5)
294 return false;
295 LastReadHeader.Alloc(HeaderSize);
296 Raw.GetB(&LastReadHeader[0],HeaderSize);
297 // Calculate the absolute position as offset from quick open service header.
298 LastReadHeaderPos=QOHeaderPos-Offset;
299 return true;
300 }