Merge pull request #4011 from fritsch/vdpau-settings
[vuplus_xbmc] / lib / UnrarXLib / arcread.cpp
1 #include "rar.hpp"
2
3 int Archive::SearchBlock(int BlockType)
4 {
5   int Size,Count=0;
6   while ((Size=ReadHeader())!=0 &&
7          (BlockType==ENDARC_HEAD || GetHeaderType()!=ENDARC_HEAD))
8   {
9     if ((++Count & 127)==0)
10       Wait();
11     if (GetHeaderType()==BlockType)
12       return(Size);
13     SeekToNext();
14   }
15   return(0);
16 }
17
18
19 int Archive::SearchSubBlock(const char *Type)
20 {
21   int Size;
22   while ((Size=ReadHeader())!=0 && GetHeaderType()!=ENDARC_HEAD)
23   {
24     if (GetHeaderType()==NEWSUB_HEAD && SubHead.CmpName(Type))
25       return(Size);
26     SeekToNext();
27   }
28   return(0);
29 }
30
31
32 int Archive::ReadHeader()
33 {
34   CurBlockPos=Tell();
35
36 #ifndef SFX_MODULE
37   if (OldFormat)
38     return(ReadOldHeader());
39 #endif
40
41   RawRead Raw(this);
42
43   bool Decrypt=Encrypted && CurBlockPos>=SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD;
44
45   if (Decrypt)
46   {
47 #if defined(SHELL_EXT) || defined(NOCRYPT)
48     return(0);
49 #else
50     if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE)
51       return(0);
52     if (*Cmd->Password==0)
53 #ifdef RARDLL
54       if (Cmd->Callback==NULL ||
55           Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LONG)Cmd->Password,sizeof(Cmd->Password))==-1)
56       {
57         Close();
58         ErrHandler.Exit(USER_BREAK);
59       }
60
61 #else
62       if (!GetPassword(PASSWORD_ARCHIVE,FileName,Cmd->Password,sizeof(Cmd->Password)))
63       {
64         Close();
65         ErrHandler.Exit(USER_BREAK);
66       }
67 #endif
68     HeadersCrypt.SetCryptKeys(Cmd->Password,HeadersSalt,false);
69     Raw.SetCrypt(&HeadersCrypt);
70 #endif
71   }
72
73   Raw.Read(SIZEOF_SHORTBLOCKHEAD);
74   if (Raw.Size()==0)
75   {
76     Int64 ArcSize=FileLength();
77     if (CurBlockPos>ArcSize || NextBlockPos>ArcSize)
78     {
79   #ifndef SHELL_EXT
80       Log(FileName,St(MLogUnexpEOF));
81   #endif
82       ErrHandler.SetErrorCode(WARNING);
83     }
84     return(0);
85   }
86
87   Raw.Get(ShortBlock.HeadCRC);
88   byte HeadType;
89   Raw.Get(HeadType);
90   ShortBlock.HeadType=(HEADER_TYPE)HeadType;
91   Raw.Get(ShortBlock.Flags);
92   Raw.Get(ShortBlock.HeadSize);
93   if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
94   {
95 #ifndef SHELL_EXT
96     Log(FileName,St(MLogFileHead),"???");
97 #endif
98     BrokenFileHeader=true;
99     ErrHandler.SetErrorCode(CRC_ERROR);
100     return(0);
101   }
102
103   if (ShortBlock.HeadType==COMM_HEAD)
104     Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
105   else
106     if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0)
107       Raw.Read(SIZEOF_NEWMHD-SIZEOF_SHORTBLOCKHEAD);
108     else
109       Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
110
111   NextBlockPos=CurBlockPos+ShortBlock.HeadSize;
112
113   switch(ShortBlock.HeadType)
114   {
115     case MAIN_HEAD:
116       *(BaseBlock *)&NewMhd=ShortBlock;
117       Raw.Get(NewMhd.HighPosAV);
118       Raw.Get(NewMhd.PosAV);
119       break;
120     case ENDARC_HEAD:
121       *(BaseBlock *)&EndArcHead=ShortBlock;
122       if (EndArcHead.Flags & EARC_DATACRC)
123         Raw.Get(EndArcHead.ArcDataCRC);
124     if (EndArcHead.Flags & EARC_VOLNUMBER)
125         Raw.Get(EndArcHead.VolNumber);
126       break;
127     case FILE_HEAD:
128     case NEWSUB_HEAD:
129       {
130         FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead;
131         *(BaseBlock *)hd=ShortBlock;
132         Raw.Get(hd->PackSize);
133         Raw.Get(hd->UnpSize);
134         Raw.Get(hd->HostOS);
135         Raw.Get(hd->FileCRC);
136         Raw.Get(hd->FileTime);
137         Raw.Get(hd->UnpVer);
138         Raw.Get(hd->Method);
139         Raw.Get(hd->NameSize);
140         Raw.Get(hd->FileAttr);
141         if (hd->Flags & LHD_LARGE)
142         {
143           Raw.Get(hd->HighPackSize);
144           Raw.Get(hd->HighUnpSize);
145         }
146         else 
147     {
148           hd->HighPackSize=hd->HighUnpSize=0;
149           if (hd->UnpSize==0xffffffff)
150           {
151             hd->UnpSize=int64to32(INT64MAX);
152             hd->HighUnpSize=int64to32(INT64MAX>>32);
153           }
154         }
155         hd->FullPackSize=int32to64(hd->HighPackSize,hd->PackSize);
156         hd->FullUnpSize=int32to64(hd->HighUnpSize,hd->UnpSize);
157
158         char FileName[NM*4];
159         int NameSize=Min(hd->NameSize,sizeof(FileName)-1);
160         Raw.Get((byte *)FileName,NameSize);
161         FileName[NameSize]=0;
162
163         strncpy(hd->FileName,FileName,sizeof(hd->FileName));
164         hd->FileName[sizeof(hd->FileName)-1]=0;
165
166         if (hd->HeadType==NEWSUB_HEAD)
167         {
168           int DataSize=hd->HeadSize-hd->NameSize-SIZEOF_NEWLHD;
169           if (hd->Flags & LHD_SALT)
170             DataSize-=SALT_SIZE;
171           if (DataSize>0)
172           {
173             hd->SubData.Alloc(DataSize);
174             Raw.Get(&hd->SubData[0],DataSize);
175             if (hd->CmpName(SUBHEAD_TYPE_RR))
176             {
177               byte *D=&hd->SubData[8];
178               RecoverySectors=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24);
179             }
180           }
181         }
182         else
183           if (hd->HeadType==FILE_HEAD)
184           {
185             if (hd->Flags & LHD_UNICODE)
186             {
187               EncodeFileName NameCoder;
188               int Length=strlen(FileName)+1;
189               NameCoder.Decode(FileName,(byte *)FileName+Length,
190                                hd->NameSize-Length,hd->FileNameW,
191                                sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0]));
192               if (*hd->FileNameW==0)
193                 hd->Flags &= ~LHD_UNICODE;
194             }
195             else
196               *hd->FileNameW=0;
197 #ifndef SFX_MODULE
198             ConvertNameCase(hd->FileName);
199             ConvertNameCase(hd->FileNameW);
200 #endif
201             ConvertUnknownHeader();
202           }
203         if (hd->Flags & LHD_SALT)
204           Raw.Get(hd->Salt,SALT_SIZE);
205         hd->mtime.SetDos(hd->FileTime);
206         hd->ctime.Reset();
207         hd->atime.Reset();
208         hd->arctime.Reset();
209         if (hd->Flags & LHD_EXTTIME)
210         {
211           ushort Flags;
212           Raw.Get(Flags);
213           RarTime *tbl[4];
214           tbl[0]=&NewLhd.mtime;
215           tbl[1]=&NewLhd.ctime;
216           tbl[2]=&NewLhd.atime;
217           tbl[3]=&NewLhd.arctime;
218           for (int I=0;I<4;I++)
219           {
220             RarTime *CurTime=tbl[I];
221             uint rmode=Flags>>(3-I)*4;
222             if ((rmode & 8)==0)
223               continue;
224             if (I!=0)
225             {
226               uint DosTime;
227               Raw.Get(DosTime);
228               CurTime->SetDos(DosTime);
229             }
230             RarLocalTime rlt;
231             CurTime->GetLocal(&rlt);
232             if (rmode & 4)
233               rlt.Second++;
234             rlt.Reminder=0;
235             int count=rmode&3;
236             for (int J=0;J<count;J++)
237             {
238               byte CurByte;
239               Raw.Get(CurByte);
240               rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
241             }
242             CurTime->SetLocal(&rlt);
243           }
244         }
245         NextBlockPos+=hd->FullPackSize;
246         bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0;
247         HeaderCRC = ~Raw.GetCRC(CRCProcessedOnly) & 0xffff;
248         if (hd->HeadCRC!=HeaderCRC)
249         {
250           if (hd->HeadType==NEWSUB_HEAD)
251             strcat(hd->FileName,"- ???");
252           BrokenFileHeader=true;
253           ErrHandler.SetErrorCode(WARNING);
254 #ifndef SHELL_EXT
255           Log(Archive::FileName,St(MLogFileHead),IntNameToExt(hd->FileName));
256           Alarm();
257 #endif
258         }
259       }
260       break;
261 #ifndef SFX_MODULE
262     case COMM_HEAD:
263       *(BaseBlock *)&CommHead=ShortBlock;
264       Raw.Get(CommHead.UnpSize);
265       Raw.Get(CommHead.UnpVer);
266       Raw.Get(CommHead.Method);
267       Raw.Get(CommHead.CommCRC);
268       break;
269     case SIGN_HEAD:
270       *(BaseBlock *)&SignHead=ShortBlock;
271       Raw.Get(SignHead.CreationTime);
272       Raw.Get(SignHead.ArcNameSize);
273       Raw.Get(SignHead.UserNameSize);
274       break;
275     case AV_HEAD:
276       *(BaseBlock *)&AVHead=ShortBlock;
277       Raw.Get(AVHead.UnpVer);
278       Raw.Get(AVHead.Method);
279       Raw.Get(AVHead.AVVer);
280       Raw.Get(AVHead.AVInfoCRC);
281       break;
282     case PROTECT_HEAD:
283       *(BaseBlock *)&ProtectHead=ShortBlock;
284       Raw.Get(ProtectHead.DataSize);
285       Raw.Get(ProtectHead.Version);
286       Raw.Get(ProtectHead.RecSectors);
287       Raw.Get(ProtectHead.TotalBlocks);
288       Raw.Get(ProtectHead.Mark,8);
289       NextBlockPos+=ProtectHead.DataSize;
290       RecoverySectors=ProtectHead.RecSectors;
291       break;
292     case SUB_HEAD:
293       *(BaseBlock *)&SubBlockHead=ShortBlock;
294       Raw.Get(SubBlockHead.DataSize);
295       NextBlockPos+=SubBlockHead.DataSize;
296       Raw.Get(SubBlockHead.SubType);
297       Raw.Get(SubBlockHead.Level);
298       switch(SubBlockHead.SubType)
299       {
300         case UO_HEAD:
301           *(SubBlockHeader *)&UOHead=SubBlockHead;
302           Raw.Get(UOHead.OwnerNameSize);
303           Raw.Get(UOHead.GroupNameSize);
304           if (UOHead.OwnerNameSize>NM-1)
305             UOHead.OwnerNameSize=NM-1;
306           if (UOHead.GroupNameSize>NM-1)
307             UOHead.GroupNameSize=NM-1;
308           Raw.Get((byte *)UOHead.OwnerName,UOHead.OwnerNameSize);
309           Raw.Get((byte *)UOHead.GroupName,UOHead.GroupNameSize);
310           UOHead.OwnerName[UOHead.OwnerNameSize]=0;
311           UOHead.GroupName[UOHead.GroupNameSize]=0;
312           break;
313         case MAC_HEAD:
314           *(SubBlockHeader *)&MACHead=SubBlockHead;
315           Raw.Get(MACHead.fileType);
316           Raw.Get(MACHead.fileCreator);
317           break;
318         case EA_HEAD:
319         case BEEA_HEAD:
320         case NTACL_HEAD:
321           *(SubBlockHeader *)&EAHead=SubBlockHead;
322           Raw.Get(EAHead.UnpSize);
323           Raw.Get(EAHead.UnpVer);
324           Raw.Get(EAHead.Method);
325           Raw.Get(EAHead.EACRC);
326           break;
327         case STREAM_HEAD:
328           *(SubBlockHeader *)&StreamHead=SubBlockHead;
329           Raw.Get(StreamHead.UnpSize);
330           Raw.Get(StreamHead.UnpVer);
331           Raw.Get(StreamHead.Method);
332           Raw.Get(StreamHead.StreamCRC);
333           Raw.Get(StreamHead.StreamNameSize);
334           if (StreamHead.StreamNameSize>NM-1)
335             StreamHead.StreamNameSize=NM-1;
336           Raw.Get((byte *)StreamHead.StreamName,StreamHead.StreamNameSize);
337           StreamHead.StreamName[StreamHead.StreamNameSize]=0;
338           break;
339       }
340       break;
341 #endif
342     default:
343       if (ShortBlock.Flags & LONG_BLOCK)
344       {
345         uint DataSize;
346         Raw.Get(DataSize);
347         NextBlockPos+=DataSize;
348       }
349       break;
350   }
351   HeaderCRC=~Raw.GetCRC(false)&0xffff;
352   CurHeaderType=ShortBlock.HeadType;
353   if (Decrypt)
354   {
355     NextBlockPos+=Raw.PaddedSize()+SALT_SIZE;
356
357     if (ShortBlock.HeadCRC!=HeaderCRC)
358     {
359       bool Recovered=false;
360       if (ShortBlock.HeadType==ENDARC_HEAD && (EndArcHead.Flags & EARC_REVSPACE)!=0)
361       {
362         SaveFilePos SavePos(*this);
363         Int64 Length=Tell();
364         Seek(Length-7,SEEK_SET);
365         Recovered=true;
366         for (int J=0;J<7;J++)
367           if (GetByte()!=0)
368             Recovered=false;
369       }
370       if (!Recovered)
371       {
372 #ifndef SILENT
373         Log(FileName,St(MEncrBadCRC),FileName);
374 #endif
375         Close();
376
377         BrokenFileHeader=true;
378         ErrHandler.SetErrorCode(CRC_ERROR);
379         return(0);
380 //        ErrHandler.Exit(CRC_ERROR);
381       }
382     }
383   }
384
385   if (NextBlockPos<=CurBlockPos)
386   {
387 #ifndef SHELL_EXT
388     Log(FileName,St(MLogFileHead),"???");
389 #endif
390     BrokenFileHeader=true;
391     ErrHandler.SetErrorCode(CRC_ERROR);
392     return(0);
393   }
394   return(Raw.Size());
395 }
396
397
398 #ifndef SFX_MODULE
399 int Archive::ReadOldHeader()
400 {
401   RawRead Raw(this);
402   if (CurBlockPos<=SFXSize)
403   {
404     Raw.Read(SIZEOF_OLDMHD);
405     Raw.Get(OldMhd.Mark,4);
406     Raw.Get(OldMhd.HeadSize);
407     Raw.Get(OldMhd.Flags);
408     NextBlockPos=CurBlockPos+OldMhd.HeadSize;
409     CurHeaderType=MAIN_HEAD;
410   }
411   else
412   {
413     OldFileHeader OldLhd;
414     Raw.Read(SIZEOF_OLDLHD);
415     NewLhd.HeadType=FILE_HEAD;
416     Raw.Get(NewLhd.PackSize);
417     Raw.Get(NewLhd.UnpSize);
418     Raw.Get(OldLhd.FileCRC);
419     Raw.Get(NewLhd.HeadSize);
420     Raw.Get(NewLhd.FileTime);
421     Raw.Get(OldLhd.FileAttr);
422     Raw.Get(OldLhd.Flags);
423     Raw.Get(OldLhd.UnpVer);
424     Raw.Get(OldLhd.NameSize);
425     Raw.Get(OldLhd.Method);
426
427     NewLhd.Flags=OldLhd.Flags|LONG_BLOCK;
428     NewLhd.UnpVer=(OldLhd.UnpVer==2) ? 13 : 10;
429     NewLhd.Method=OldLhd.Method+0x30;
430     NewLhd.NameSize=OldLhd.NameSize;
431     NewLhd.FileAttr=OldLhd.FileAttr;
432     NewLhd.FileCRC=OldLhd.FileCRC;
433     NewLhd.FullPackSize=NewLhd.PackSize;
434     NewLhd.FullUnpSize=NewLhd.UnpSize;
435
436     NewLhd.mtime.SetDos(NewLhd.FileTime);
437     NewLhd.ctime.Reset();
438     NewLhd.atime.Reset();
439     NewLhd.arctime.Reset();
440
441     Raw.Read(OldLhd.NameSize);
442     Raw.Get((byte *)NewLhd.FileName,OldLhd.NameSize);
443     NewLhd.FileName[OldLhd.NameSize]=0;
444     ConvertNameCase(NewLhd.FileName);
445     *NewLhd.FileNameW=0;
446
447     if (Raw.Size()!=0)
448       NextBlockPos=CurBlockPos+NewLhd.HeadSize+NewLhd.PackSize;
449     CurHeaderType=FILE_HEAD;
450   }
451   return(NextBlockPos>CurBlockPos ? Raw.Size():0);
452 }
453 #endif
454
455
456 void Archive::ConvertNameCase(char *Name)
457 {
458   if (Cmd->ConvertNames==NAMES_UPPERCASE)
459   {
460     IntToExt(Name,Name);
461     strupper(Name);
462     ExtToInt(Name,Name);
463   }
464   if (Cmd->ConvertNames==NAMES_LOWERCASE)
465   {
466     IntToExt(Name,Name);
467     strlower(Name);
468     ExtToInt(Name,Name);
469   }
470 }
471
472
473 #ifndef SFX_MODULE
474 void Archive::ConvertNameCase(wchar *Name)
475 {
476   if (Cmd->ConvertNames==NAMES_UPPERCASE)
477     strupperw(Name);
478   if (Cmd->ConvertNames==NAMES_LOWERCASE)
479     strlowerw(Name);
480 }
481 #endif
482
483
484 bool Archive::IsArcDir()
485 {
486   return((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY);
487 }
488
489
490 bool Archive::IsArcLabel()
491 {
492   return(NewLhd.HostOS<=HOST_WIN32 && (NewLhd.FileAttr & 8));
493 }
494
495
496 void Archive::ConvertAttributes()
497 {
498 #if defined(_WIN_32) || defined(_EMX)
499   switch(NewLhd.HostOS)
500   {
501     case HOST_MSDOS:
502     case HOST_OS2:
503     case HOST_WIN32:
504       break;
505     case HOST_UNIX:
506     case HOST_BEOS:
507       if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
508         NewLhd.FileAttr=0x10;
509       else
510         NewLhd.FileAttr=0x20;
511       break;
512     default:
513       if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
514         NewLhd.FileAttr=0x10;
515       else
516         NewLhd.FileAttr=0x20;
517       break;
518   }
519 #endif
520 #ifdef _UNIX
521   static mode_t mask = (mode_t) -1;
522
523   if (mask == (mode_t) -1)
524   {
525     mask = umask(022);
526     umask(mask);
527   }
528   switch(NewLhd.HostOS)
529   {
530     case HOST_MSDOS:
531     case HOST_OS2:
532     case HOST_WIN32:
533       if (NewLhd.FileAttr & 0x10)
534         NewLhd.FileAttr=0x41ff & ~mask;
535       else
536         if (NewLhd.FileAttr & 1)
537           NewLhd.FileAttr=0x8124 & ~mask;
538         else
539           NewLhd.FileAttr=0x81b6 & ~mask;
540       break;
541     case HOST_UNIX:
542     case HOST_BEOS:
543       break;
544     default:
545       if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
546         NewLhd.FileAttr=0x41ff & ~mask;
547       else
548         NewLhd.FileAttr=0x81b6 & ~mask;
549       break;
550   }
551 #endif
552 }
553
554
555 void Archive::ConvertUnknownHeader()
556 {
557   if (NewLhd.UnpVer<20 && (NewLhd.FileAttr & 0x10))
558     NewLhd.Flags|=LHD_DIRECTORY;
559   if (NewLhd.HostOS>=HOST_MAX)
560   {
561     if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
562       NewLhd.FileAttr=0x10;
563     else
564       NewLhd.FileAttr=0x20;
565   }
566   for (char *s=NewLhd.FileName;*s!=0;s=charnext(s))
567   {
568     if (*s=='/' || *s=='\\')
569       *s=CPATHDIVIDER;
570 #if defined(_APPLE) && !defined(UNICODE_SUPPORTED)
571     if ((byte)*s<32 || (byte)*s>127)
572       *s='_';
573 #endif
574   }
575   for (wchar *s=NewLhd.FileNameW;*s!=0;s++)
576     if (*s=='/' || *s=='\\')
577       *s=CPATHDIVIDER;
578 }
579
580 #ifndef SHELL_EXT
581 bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
582 {
583   if (HeaderCRC!=SubHead.HeadCRC)
584   {
585 #ifndef SHELL_EXT
586     Log(FileName,St(MSubHeadCorrupt));
587 #endif
588     ErrHandler.SetErrorCode(CRC_ERROR);
589     return(false);
590   }
591   if (SubHead.Method<0x30 || SubHead.Method>0x35 || SubHead.UnpVer>PACK_VER)
592   {
593 #ifndef SHELL_EXT
594     Log(FileName,St(MSubHeadUnknown));
595 #endif
596     return(false);
597   }
598
599   if (SubHead.PackSize==0 && (SubHead.Flags & LHD_SPLIT_AFTER)==0)
600     return(true);
601
602   SubDataIO.Init();
603   Unpack Unpack(&SubDataIO);
604   Unpack.Init();
605
606   if (DestFile==NULL)
607   {
608     UnpData->Alloc(SubHead.UnpSize);
609     SubDataIO.SetUnpackToMemory(&(*UnpData)[0],SubHead.UnpSize);
610   }
611   if (SubHead.Flags & LHD_PASSWORD)
612   {
613     if (*Cmd->Password)
614       SubDataIO.SetEncryption(SubHead.UnpVer,Cmd->Password,
615              (SubHead.Flags & LHD_SALT) ? SubHead.Salt:NULL,false);
616     else
617       return(false);
618   }
619   SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
620   SubDataIO.EnableShowProgress(false);
621   SubDataIO.SetFiles(this,DestFile);
622   SubDataIO.UnpVolume=(SubHead.Flags & LHD_SPLIT_AFTER);
623   SubDataIO.SetSubHeader(&SubHead,NULL);
624   Unpack.SetDestSize(SubHead.UnpSize);
625   if (SubHead.Method==0x30)
626     CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize);
627   else
628     Unpack.DoUnpack(SubHead.UnpVer,false);
629
630   if (SubHead.FileCRC!=~SubDataIO.UnpFileCRC)
631   {
632 #ifndef SHELL_EXT
633     Log(FileName,St(MSubHeadDataCRC),SubHead.FileName);
634 #endif
635     ErrHandler.SetErrorCode(CRC_ERROR);
636     if (UnpData!=NULL)
637       UnpData->Reset();
638     return(false);
639   }
640   return(true);
641 }
642 #endif