Merge pull request #473 from Montellese/onplaybackspeedchanged
[vuplus_xbmc] / lib / UnrarXLib / extract.cpp
1 #include "rar.hpp"
2 #include "Util.h"
3 #ifdef _LINUX
4 #include "XSyncUtils.h"
5 #include "XEventUtils.h"
6 #endif
7
8 // a cautious wrapper around strncpy
9 char *strncpy_null_terminated(char *dest, const char *src, size_t n)
10 {
11   char *result = strncpy(dest, src, n);
12   if(n>0) {
13     dest[n-1] = '\0';
14   }
15   return result;
16 }
17
18 CmdExtract::CmdExtract()
19 {
20   TotalFileCount=0;
21   *Password=0;
22   Unp = NULL;
23 }
24
25
26 CmdExtract::~CmdExtract()
27 {
28   delete Unp;
29   memset(Password,0,sizeof(Password));
30 }
31
32
33 void CmdExtract::DoExtract(CommandData *Cmd)
34 {
35   if (!Unp)
36   {
37       Unp=new Unpack(&DataIO);
38       Unp->Init(NULL);
39   }
40   DataIO.SetCurrentCommand(*Cmd->Command);
41
42   struct FindData FD;
43   while (Cmd->GetArcName(ArcName,ArcNameW,sizeof(ArcName)))
44     if (FindFile::FastFind(ArcName,ArcNameW,&FD))
45       DataIO.TotalArcSize+=FD.Size;
46   Cmd->ArcNames->Rewind();
47   while (Cmd->GetArcName(ArcName,ArcNameW,sizeof(ArcName)))
48   {
49     while (ExtractArchive(Cmd)==EXTRACT_ARC_REPEAT)
50       ;
51     if (FindFile::FastFind(ArcName,ArcNameW,&FD))
52       DataIO.ProcessedArcSize+=FD.Size;
53   }
54
55   if (TotalFileCount==0 && *Cmd->Command!='I')
56   {
57     if (!PasswordCancelled)
58     {
59       mprintf(St(MExtrNoFiles));
60     }
61     ErrHandler.SetErrorCode(WARNING);
62   }
63 #ifndef GUI
64   else if (!Cmd->DisableDone)
65   {
66     if (*Cmd->Command=='I')
67     {
68       mprintf(St(MDone));
69     }
70     else
71     {
72       if (ErrHandler.GetErrorCount()==0)
73       {
74         mprintf(St(MExtrAllOk));
75       }
76       else
77       {
78         mprintf(St(MExtrTotalErr),ErrHandler.GetErrorCount());
79       }
80     }
81   }
82 #endif
83 }
84
85
86 void CmdExtract::ExtractArchiveInit(CommandData *Cmd,Archive &Arc)
87 {
88   if (!Unp)
89   {
90       Unp=new Unpack(&DataIO);
91       Unp->Init(NULL);
92   }
93
94   DataIO.UnpArcSize=Arc.FileLength();
95
96   FileCount=0;
97   MatchedArgs=0;
98 #ifndef SFX_MODULE
99   FirstFile=true;
100 #endif
101
102   if (*Cmd->Password!=0)
103     strncpy_null_terminated(Password,Cmd->Password, MAXPASSWORD);
104   PasswordAll=(*Cmd->Password!=0);
105
106   DataIO.UnpVolume=false;
107
108   PrevExtracted=false;
109   SignatureFound=false;
110   AllMatchesExact=true;
111   ReconstructDone=false;
112 }
113
114
115 EXTRACT_ARC_CODE CmdExtract::ExtractArchive(CommandData *Cmd)
116 {
117   Archive Arc(Cmd);
118   if (!Arc.WOpen(ArcName,ArcNameW))
119   {
120     ErrHandler.SetErrorCode(OPEN_ERROR);
121     return(EXTRACT_ARC_NEXT);
122   }
123
124   if (!Arc.IsArchive(true))
125   {
126 #ifndef GUI
127     mprintf(St(MNotRAR),ArcName);
128 #endif
129     if (CmpExt(ArcName,"rar"))
130       ErrHandler.SetErrorCode(WARNING);
131     return(EXTRACT_ARC_NEXT);
132   }
133
134   if (!Arc.IsOpened())
135     return(EXTRACT_ARC_NEXT);
136
137 #ifndef SFX_MODULE
138   if (Arc.Volume && Arc.NotFirstVolume)
139   {
140     char FirstVolName[NM];
141
142     VolNameToFirstName(ArcName,FirstVolName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING));
143     if (stricomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) &&
144         Cmd->ArcNames->Search(FirstVolName,NULL,false))
145       return(EXTRACT_ARC_NEXT);
146   }
147 #endif
148   ExtractArchiveInit(Cmd,Arc);
149
150   if (*Cmd->Command=='T' || *Cmd->Command=='I')
151     Cmd->Test=true;
152
153 #ifndef GUI
154   if (*Cmd->Command=='I')
155     Cmd->DisablePercentage=true;
156   else
157     if (Cmd->Test)
158     {
159       mprintf(St(MExtrTest),ArcName);
160     }
161     else
162     {
163       mprintf(St(MExtracting),ArcName);
164     }
165 #endif
166
167   Arc.ViewComment();
168
169   while (1)
170   {
171     int Size=Arc.ReadHeader();
172     bool Repeat=false;
173     if (!ExtractCurrentFile(Cmd,Arc,Size,Repeat))
174     {
175       if (Repeat)
176       {
177         return(EXTRACT_ARC_REPEAT);
178       }
179       else
180         break;
181     }
182   }
183   return(EXTRACT_ARC_NEXT);
184 }
185
186
187 bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize,bool &Repeat)
188 {
189   if (!Unp)
190   {
191     Unp=new Unpack(&DataIO);
192     Unp->Init(NULL);
193   }
194   char Command=*Cmd->Command;
195
196   if (HeaderSize<=0)
197   {
198     if (DataIO.UnpVolume)
199     {
200 //#ifdef NOVOLUME
201 //      return(false);
202 //#else
203       if (!MergeArchive(Arc,NULL,false,Command))
204       {
205         ErrHandler.SetErrorCode(WARNING);
206         return(false);
207       }
208       SignatureFound=false;
209 //#endif
210     }
211     else
212       return(false);
213   }
214   int HeadType=Arc.GetHeaderType();
215   if (HeadType!=FILE_HEAD)
216   {
217     if (HeadType==AV_HEAD || HeadType==SIGN_HEAD)
218       SignatureFound=true;
219 #if !defined(SFX_MODULE) && !defined(_WIN_CE)
220     if (HeadType==SUB_HEAD && PrevExtracted)
221       SetExtraInfo(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);    
222 #endif
223     if (HeadType==NEWSUB_HEAD)
224     {
225       if (Arc.SubHead.CmpName(SUBHEAD_TYPE_AV))
226         SignatureFound=true;
227 #if !defined(NOSUBBLOCKS) && !defined(_WIN_CE)
228       if (PrevExtracted)
229         SetExtraInfoNew(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
230 #endif
231     }
232     if (HeadType==ENDARC_HEAD)
233     {
234       if (Arc.EndArcHead.Flags & EARC_NEXT_VOLUME)
235       {
236 #ifndef NOVOLUME
237         if (!MergeArchive(Arc,NULL,false,Command))
238         {
239           ErrHandler.SetErrorCode(WARNING);
240           return(false);
241         }
242         SignatureFound=false;
243 #endif
244         Arc.Seek(Arc.CurBlockPos,SEEK_SET);
245         return(true);
246       }
247       else
248         return(false);
249     }
250     Arc.SeekToNext();
251     return(true);
252   }
253   PrevExtracted=false;
254
255   if (SignatureFound ||
256      (!Cmd->Recurse && MatchedArgs>=(int)Cmd->FileArgs->ItemsCount() && AllMatchesExact))
257     return(false);
258
259   char ArcFileName[NM];
260
261   IntToExt(Arc.NewLhd.FileName,Arc.NewLhd.FileName);
262   strncpy_null_terminated(ArcFileName,Arc.NewLhd.FileName, NM);
263
264   wchar ArcFileNameW[NM];
265   *ArcFileNameW=0;
266
267   int MatchType=MATCH_WILDSUBPATH;
268   
269   bool EqualNames=false;
270   int MatchNumber=Cmd->IsProcessFile(Arc.NewLhd,&EqualNames,MatchType);
271   bool ExactMatch=MatchNumber!=0;
272 #if !defined(SFX_MODULE) && !defined(_WIN_CE)
273   if (Cmd->ExclPath==EXCL_BASEPATH)
274   {
275     *Cmd->ArcPath=0;
276     if (ExactMatch)
277     {
278       Cmd->FileArgs->Rewind();
279       if (Cmd->FileArgs->GetString(Cmd->ArcPath,NULL,sizeof(Cmd->ArcPath),MatchNumber-1))
280         *PointToName(Cmd->ArcPath)=0;
281     }
282   }
283 #endif
284   if (ExactMatch && !EqualNames)
285     AllMatchesExact=false;
286
287 #ifdef UNICODE_SUPPORTED
288   bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled();
289 #else
290   bool WideName=false;
291 #endif
292
293 #ifdef _APPLE
294   if (WideName)
295   {
296     WideToUtf(Arc.NewLhd.FileNameW,ArcFileName,sizeof(ArcFileName));
297     WideName=false;
298   }
299 #endif
300
301   wchar *DestNameW=WideName ? DestFileNameW:NULL;
302
303 #ifdef UNICODE_SUPPORTED
304   if (WideName)
305   {
306     ConvertPath(Arc.NewLhd.FileNameW,ArcFileNameW);
307     char Name[NM];
308     WideToChar(ArcFileNameW,Name);
309     if (IsNameUsable(Name))
310       strncpy_null_terminated(ArcFileName,Name, NM);
311   }
312 #endif
313
314   ConvertPath(ArcFileName,ArcFileName);
315
316   if (Arc.IsArcLabel())
317     return(true);
318
319   if (Arc.NewLhd.Flags & LHD_VERSION)
320   {
321     if (Cmd->VersionControl!=1 && !EqualNames)
322     {
323       if (Cmd->VersionControl==0)
324         ExactMatch=false;
325       int Version=ParseVersionFileName(ArcFileName,ArcFileNameW,false);
326       if (Cmd->VersionControl-1==Version)
327         ParseVersionFileName(ArcFileName,ArcFileNameW,true);
328       else
329         ExactMatch=false;
330     }
331   }
332   else
333     if (!Arc.IsArcDir() && Cmd->VersionControl>1)
334       ExactMatch=false;
335
336   Arc.ConvertAttributes();
337
338 #ifndef SFX_MODULE
339   if ((Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/)) && FirstFile)
340   {
341     char CurVolName[NM];
342     strncpy_null_terminated(CurVolName,ArcName, NM);
343
344     VolNameToFirstName(ArcName,ArcName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING) != 0);
345     if (stricomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
346     {
347       *ArcNameW=0;
348       Repeat=true;
349       return(false);
350     }
351 #if !defined(RARDLL) && !defined(_WIN_CE)
352     if (!ReconstructDone)
353     {
354       ReconstructDone=true;
355
356       RecVolumes RecVol;
357       if (RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true))
358       {
359         Repeat=true;
360         return(false);
361       }
362     }
363 #endif
364     strncpy_null_terminated(ArcName,CurVolName, NM);
365   }
366 #endif
367
368   DataIO.UnpVolume=(Arc.NewLhd.Flags & LHD_SPLIT_AFTER);
369   DataIO.NextVolumeMissing=false;
370
371   Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET);
372
373   bool TestMode=false;
374   bool ExtrFile=false;
375   bool SkipSolid=false;
376
377 #ifndef SFX_MODULE
378   if (FirstFile && (ExactMatch || Arc.Solid) && (Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/))!=0)
379   {
380     if (ExactMatch)
381     {
382       Log(Arc.FileName,St(MUnpCannotMerge),(char*) ArcFileName);
383 #ifdef RARDLL
384       Cmd->DllError=ERAR_BAD_DATA;
385 #endif
386         ErrHandler.SetErrorCode(WARNING);
387     }
388     ExactMatch=false;
389   }
390
391   FirstFile=false;
392 #endif
393
394   if (ExactMatch || (SkipSolid=Arc.Solid)!=0)
395   {
396     if (Arc.NewLhd.Flags & LHD_PASSWORD)
397 #ifndef RARDLL
398       if (*Password==0)
399 #endif
400       {
401 #ifdef RARDLL
402         if (*Cmd->Password==0)
403           if (Cmd->Callback==NULL ||
404               Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LONG)Cmd->Password,sizeof(Cmd->Password))==-1)
405             return(false);
406         strncpy_null_terminated(Password,Cmd->Password, MAXPASSWORD);
407
408 #else
409         if (!GetPassword(PASSWORD_FILE,ArcFileName,Password,sizeof(Password)))
410         {
411                 PasswordCancelled=true;        
412           return(false);
413         }
414 #endif
415       }
416 #if !defined(GUI) && !defined(SILENT)
417       else
418         if (!PasswordAll && (!Arc.Solid || Arc.NewLhd.UnpVer>=20 && (Arc.NewLhd.Flags & LHD_SOLID)==0))
419         {
420           eprintf(St(MUseCurPsw),(char*) ArcFileName);
421           switch(Cmd->AllYes ? 1:Ask(St(MYesNoAll)))
422           {
423             case -1:
424               ErrHandler.Exit(USER_BREAK);
425             case 2:
426               if (!GetPassword(PASSWORD_FILE,ArcFileName,Password,sizeof(Password)))
427               {
428                 return(false);
429               }
430               break;
431             case 3:
432               PasswordAll=true;
433               break;
434           }
435         }
436 #endif
437
438 #ifndef SFX_MODULE
439     if (*Cmd->ExtrPath==0 && *Cmd->ExtrPathW!=0)
440       WideToChar(Cmd->ExtrPathW,DestFileName);
441     else
442 #endif
443       strncpy_null_terminated(DestFileName,Cmd->ExtrPath, NM);
444
445
446 #ifndef SFX_MODULE
447     if (Cmd->AppendArcNameToPath)
448     {
449       AddEndSlash(DestFileName);
450       strcat(DestFileName,PointToName(Arc.FileName));
451       SetExt(DestFileName,NULL);
452       AddEndSlash(DestFileName);
453     }
454 #endif
455
456     char *ExtrName=ArcFileName;
457
458     bool EmptyName=false;
459 #ifndef SFX_MODULE
460     int Length=strlen(Cmd->ArcPath);
461     if (Length>1 && IsPathDiv(Cmd->ArcPath[Length-1]) &&
462         strlen(ArcFileName)==((unsigned int)Length-1))
463       Length--;
464     if (Length>0 && strnicomp(Cmd->ArcPath,ArcFileName,Length)==0)
465     {
466       ExtrName+=Length;
467       while (*ExtrName==CPATHDIVIDER)
468         ExtrName++;
469       if (*ExtrName==0)
470         EmptyName=true;
471     }
472 #endif
473
474     bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':');
475     if (AbsPaths)
476       *DestFileName=0;
477
478     if (DestFileName[strlen(DestFileName)-1] != '\\' && DestFileName[strlen(DestFileName)-1] != '/')
479       strcat(DestFileName,"\\");
480       
481     if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
482     {
483       strcat(DestFileName,PointToName(ExtrName));
484     }
485     else
486       strcat(DestFileName,ExtrName);
487
488     if (AbsPaths && DestFileName[1]=='_' && IsPathDiv(DestFileName[2]))
489       DestFileName[1]=':';
490
491 #ifndef SFX_MODULE
492     if (!WideName && *Cmd->ExtrPathW!=0)
493     {
494       DestNameW=DestFileNameW;
495       WideName=true;
496       CharToWide(ArcFileName,ArcFileNameW);
497     }
498 #endif
499
500     if (WideName)
501     {
502       if (*Cmd->ExtrPathW!=0)
503         strcpyw(DestFileNameW,Cmd->ExtrPathW);
504       else
505         CharToWide(Cmd->ExtrPath,DestFileNameW);
506
507 #ifndef SFX_MODULE
508       if (Cmd->AppendArcNameToPath)
509       {
510         wchar FileNameW[NM];
511         if (*Arc.FileNameW!=0)
512           strcpyw(FileNameW,Arc.FileNameW);
513         else
514           CharToWide(Arc.FileName,FileNameW);
515         strcatw(DestFileNameW,PointToName(FileNameW));
516         SetExt(DestFileNameW,NULL);
517         AddEndSlash(DestFileNameW);
518       }
519 #endif
520       wchar *ExtrNameW=ArcFileNameW;
521 #ifndef SFX_MODULE
522       if (Length>0)
523       {
524         wchar ArcPathW[NM];
525         CharToWide(Cmd->ArcPath,ArcPathW);
526         Length=strlenw(ArcPathW);
527       }
528       ExtrNameW+=Length;
529       while (*ExtrNameW==CPATHDIVIDER)
530         ExtrNameW++;
531 #endif
532
533       if (AbsPaths)
534         *DestFileNameW=0;
535
536       if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
537         strcatw(DestFileNameW,PointToName(ExtrNameW));
538       else
539         strcatw(DestFileNameW,ExtrNameW);
540
541       if (AbsPaths && DestFileNameW[1]=='_' && IsPathDiv(DestFileNameW[2]))
542         DestFileNameW[1]=':';
543     }
544     else
545       *DestFileNameW=0;
546
547     ExtrFile=!SkipSolid && !EmptyName && (Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0/* && *ExtrName*/;
548     if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X'))
549     {
550       struct FindData FD;
551       if (FindFile::FastFind(DestFileName,DestNameW,&FD))
552       {
553         if (FD.mtime >= Arc.NewLhd.mtime)
554           ExtrFile=false;
555       }
556       else
557         if (Cmd->FreshFiles)
558           ExtrFile=false;
559     }
560
561 #ifdef RARDLL
562     if (*Cmd->DllDestName)
563     {
564       strncpy_null_terminated(DestFileName,Cmd->DllDestName,sizeof(DestFileName));
565       *DestFileNameW=0;
566       if (Cmd->DllOpMode!=RAR_EXTRACT)
567         ExtrFile=false;
568     }
569     if (*Cmd->DllDestNameW)
570     {
571       strncpyw(DestFileNameW,Cmd->DllDestNameW,sizeof(DestFileNameW)/sizeof(DestFileNameW[0]));
572       DestNameW=DestFileNameW;
573       if (Cmd->DllOpMode!=RAR_EXTRACT)
574         ExtrFile=false;
575     }
576 #endif
577
578 #ifdef SFX_MODULE
579     if (Arc.NewLhd.UnpVer!=UNP_VER && Arc.NewLhd.Method!=0x30)
580 #else
581     if (Arc.NewLhd.UnpVer<13 || Arc.NewLhd.UnpVer>UNP_VER)
582 #endif
583     {
584 #ifndef SILENT
585       Log(Arc.FileName,St(MUnknownMeth),(char*) ArcFileName);
586 #ifndef SFX_MODULE
587       Log(Arc.FileName,St(MVerRequired),Arc.NewLhd.UnpVer/10,Arc.NewLhd.UnpVer%10);
588 #endif
589 #endif
590       ExtrFile=false;
591       ErrHandler.SetErrorCode(WARNING);
592 #ifdef RARDLL
593       Cmd->DllError=ERAR_UNKNOWN_FORMAT;
594 #endif
595     }
596
597     File CurFile;
598
599     if (!IsLink(Arc.NewLhd.FileAttr))
600     {
601       if (Arc.IsArcDir())
602       {
603         if (!ExtrFile || Command=='P' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
604           return(true);
605         if (SkipSolid)
606         {
607 #ifndef GUI
608           mprintf(St(MExtrSkipFile),(char*) ArcFileName);
609 #endif
610           return(true);
611         }
612         TotalFileCount++;
613         if (Cmd->Test)
614         {
615 #ifndef GUI
616           mprintf(St(MExtrTestFile),(char*) ArcFileName);
617           mprintf(" %s",St(MOk));
618 #endif
619           return(true);
620         }
621         if (CUtil::CreateDirectoryEx(DestFileName))
622         {
623 #ifndef GUI
624           mprintf(St(MCreatDir),DestFileName);
625           mprintf(" %s",St(MOk));
626 #endif
627           PrevExtracted=true;
628           SetFileAttr(DestFileName,DestNameW,Arc.NewLhd.FileAttr);
629           PrevExtracted=true;
630         }
631         else
632         {
633           Log(Arc.FileName,St(MExtrErrMkDir),DestFileName);
634           ErrHandler.SysErrMsg();
635 #ifdef RARDLL
636           Cmd->DllError=ERAR_ECREATE;
637 #endif
638           ErrHandler.SetErrorCode(CREATE_ERROR);
639         }
640         if (PrevExtracted)
641           SetDirTime(DestFileName,
642             Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
643             Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
644             Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
645         return(true);
646       }
647       else
648       {
649         if (Cmd->Test && ExtrFile)
650           TestMode=true;
651 #if !defined(GUI) && !defined(SFX_MODULE)
652         if (Command=='P' && ExtrFile)
653           CurFile.SetHandleType(FILE_HANDLESTD);
654 #endif
655         if ((Command=='E' || Command=='X') && ExtrFile && !Cmd->Test)
656         {
657           bool UserReject;
658
659           if (GetDataIO().UnpackToMemorySize == -1) 
660           {
661             if (!FileCreate(Cmd,&CurFile,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.UnpSize,Arc.NewLhd.FileTime))
662             {
663               ExtrFile=false;
664               if (!UserReject)
665               {
666                 ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName);
667                 ErrHandler.SetErrorCode(CREATE_ERROR);
668 #ifdef RARDLL
669                 Cmd->DllError=ERAR_ECREATE;
670 #endif
671               }
672             }
673           }
674         }
675       }
676     }
677     if (!ExtrFile && Arc.Solid)
678     {
679       SkipSolid=true;
680       TestMode=true;
681       ExtrFile=true;
682     }
683     if (ExtrFile)
684     {
685       if (!SkipSolid)
686       {
687         if (!TestMode && Command!='P' && CurFile.IsDevice())
688         {
689           Log(Arc.FileName,St(MInvalidName),DestFileName);
690           ErrHandler.WriteError(Arc.FileName,DestFileName);
691         }
692         TotalFileCount++;
693       }
694       FileCount++;
695 #ifndef GUI
696       if (Command!='I')
697       {
698         if (SkipSolid)
699           mprintf(St(MExtrSkipFile),(char*) ArcFileName);
700         else
701         {
702           switch(Cmd->Test ? 'T':Command)
703           {
704             case 'T':
705               mprintf(St(MExtrTestFile),(char*) ArcFileName);
706               break;
707 #ifndef SFX_MODULE
708             case 'P':
709               mprintf(St(MExtrPrinting),(char*) ArcFileName);
710               break;
711 #endif
712             case 'X':
713             case 'E':
714               mprintf(St(MExtrFile),DestFileName);
715               break;
716           }
717         }
718       }
719       if (!Cmd->DisablePercentage)
720       {
721         mprintf("     ");
722       }
723 #endif
724       DataIO.CurUnpRead=0;
725       DataIO.CurUnpWrite=0;
726       DataIO.UnpFileCRC=Arc.OldFormat ? 0 : 0xffffffff;
727       DataIO.PackedCRC=0xffffffff;
728       DataIO.SetEncryption(
729         (Arc.NewLhd.Flags & LHD_PASSWORD) ? Arc.NewLhd.UnpVer:0,Password,
730         (Arc.NewLhd.Flags & LHD_SALT) ? Arc.NewLhd.Salt:NULL,false);
731       DataIO.SetPackedSizeToRead(Arc.NewLhd.FullPackSize);
732       DataIO.SetFiles(&Arc,&CurFile);
733       DataIO.SetTestMode(TestMode);
734       DataIO.SetSkipUnpCRC(SkipSolid);
735
736 #ifndef _WIN_CE
737       if (!TestMode && !Arc.BrokenFileHeader &&
738          (Arc.NewLhd.FullPackSize<<11)>Arc.NewLhd.FullUnpSize &&
739       (Arc.NewLhd.FullUnpSize<100000000 || Arc.FileLength()>Arc.NewLhd.FullPackSize))
740     CurFile.Prealloc(Arc.NewLhd.FullUnpSize);
741 #endif
742     CurFile.SetAllowDelete(!Cmd->KeepBroken);
743
744       bool LinkCreateMode=!Cmd->Test && !SkipSolid;
745       if (ExtractLink(DataIO,Arc,DestFileName,DataIO.UnpFileCRC,LinkCreateMode))
746         PrevExtracted=LinkCreateMode;
747       else if ((Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0)
748       {
749         if (Arc.NewLhd.Method==0x30)
750           UnstoreFile(DataIO,Arc.NewLhd.FullUnpSize);
751         else
752         {
753           Unp->SetDestSize(Arc.NewLhd.FullUnpSize);
754 #ifndef SFX_MODULE        
755           if (Arc.NewLhd.UnpVer<=15)
756             Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
757           else
758 #endif
759             Unp->DoUnpack(Arc.NewLhd.UnpVer,(Arc.NewLhd.Flags & LHD_SOLID));
760         }
761       }
762
763       if (DataIO.UnpackToMemorySize > -1)
764         if (DataIO.hQuit->WaitMSec(1))
765         {
766           return false;
767         }
768
769       if (Arc.IsOpened())
770       Arc.SeekToNext();
771
772     bool BrokenFile=false;
773 /*    if (!SkipSolid)
774     {
775       if (Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC) ||
776         !Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC^0xffffffff))
777       {
778 #ifndef GUI
779       if (Command!='P' && Command!='I')
780         mprintf("%s%s ",Cmd->DisablePercentage ? " ":"\b\b\b\b\b ",St(MOk));
781 #endif
782       }
783       else
784       {
785         char *BadArcName=(Arc.NewLhd.Flags & LHD_SPLIT_BEFORE) ? NULL:Arc.FileName;
786         if (Arc.NewLhd.Flags & LHD_PASSWORD)
787         {
788           Log(BadArcName,St(MEncrBadCRC),ArcFileName);
789         }
790         else
791         {
792           Log(BadArcName,St(MCRCFailed),ArcFileName);
793         }
794         BrokenFile=true;
795         ErrHandler.SetErrorCode(CRC_ERROR);
796 #ifdef RARDLL
797         Cmd->DllError=ERAR_BAD_DATA;
798 #endif
799         Alarm();
800       }
801     }*/
802 #ifndef GUI
803 //    else
804 //      mprintf("\b\b\b\b\b     ");
805 #endif
806
807     if (!TestMode && (Command=='X' || Command=='E') &&
808       !IsLink(Arc.NewLhd.FileAttr))
809     {
810 #if defined(_WIN_32) || defined(_EMX)
811       if (Cmd->ClearArc)
812         Arc.NewLhd.FileAttr&=~FA_ARCH;
813 #endif
814       if (!BrokenFile || Cmd->KeepBroken)
815       {
816         if (BrokenFile)
817           CurFile.Truncate();
818         CurFile.SetOpenFileStat(
819           Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
820           Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
821           Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
822         CurFile.Close();
823           CurFile.SetCloseFileStat(
824           Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
825           Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime,
826           Arc.NewLhd.FileAttr);
827           PrevExtracted=true;
828         }
829       }
830     }
831   }
832   if (ExactMatch)
833     MatchedArgs++;
834   if (DataIO.NextVolumeMissing || !Arc.IsOpened())
835     return(false);
836   if (!ExtrFile)
837   {
838     if (!Arc.Solid)
839       Arc.SeekToNext();
840     else if (!SkipSolid)
841       return(false);
842   }
843   return(true);
844 }
845
846
847 void CmdExtract::UnstoreFile(ComprDataIO &DataIO,Int64 DestUnpSize)
848 {
849   Array<byte> Buffer(0x40000);
850   if (DataIO.UnpackToMemorySize > -1)
851   {
852     while (1)
853     {
854       if (DataIO.hQuit->WaitMSec(1))
855       {
856         return;
857       }
858       int Code=DataIO.UnpRead(&Buffer[0],Buffer.Size());
859       if (DataIO.UnpackToMemorySize > -1 && !DataIO.NextVolumeMissing)
860       {
861         if (DataIO.hSeek->WaitMSec(1))
862           continue;
863       }
864       if (Code > 0)
865       {
866         Code=Code<DestUnpSize ? Code:int64to32(DestUnpSize);
867         DataIO.UnpWrite(&Buffer[0],Code);
868         if (DestUnpSize>=0)
869           DestUnpSize-=Code;
870       }
871       else 
872       {
873         if (DataIO.NextVolumeMissing)
874           DataIO.hSeekDone->Set();
875         else 
876           if (DataIO.hSeek->WaitMSec(1))
877            continue;
878         DataIO.hBufferFilled->Reset();
879         DataIO.hBufferEmpty->Set();
880         while (! DataIO.hBufferFilled->WaitMSec(1))
881           if (DataIO.hQuit->WaitMSec(1))
882             return;
883       }
884     }
885   }
886   else
887   {
888     while (1)
889     {
890       int Code=DataIO.UnpRead(&Buffer[0],Buffer.Size());
891       if (Code > 0)
892       {
893         Code=Code<DestUnpSize ? Code:int64to32(DestUnpSize);
894         DataIO.UnpWrite(&Buffer[0],Code);
895         if (DestUnpSize>=0)
896           DestUnpSize-=Code;
897       }
898       else if (Code == -1)
899       {
900         DataIO.NextVolumeMissing = true;
901         return;
902       }
903       else
904         return;
905     }
906   }
907 }