Merge pull request #4852 from FernetMenta/aefixes
[vuplus_xbmc] / lib / UnrarXLib / rar.cpp
1 #include "rar.hpp"
2 #include "UnrarX.hpp"
3 #include "guilib/GUIWindowManager.h"
4 #include "dialogs/GUIDialogProgress.h"
5 #include "filesystem/File.h"
6
7 #include "smallfn.cpp"
8
9 using namespace std;
10
11 #ifdef _DJGPP
12 extern "C" char **__crt0_glob_function (char *arg) { return 0; }
13 extern "C" void   __crt0_load_environment_file (char *progname) { }
14 #endif
15
16 #if !defined(GUI) && !defined(RARDLL) && !defined(TARGET_POSIX) && !defined(_XBMC)
17 int main(int argc, char *argv[])
18 {
19 #ifdef _UNIX
20   setlocale(LC_ALL,"");
21 #endif
22 #ifndef SFX_MODULE
23   setbuf(stdout,NULL);
24
25   #ifdef _EMX
26     EnumConfigPaths(argv[0],-1);
27   #endif
28 #endif
29
30   ErrHandler.SetSignalHandlers(true);
31
32   RARInitData();
33
34 #ifdef SFX_MODULE
35   char ModuleName[NM];
36 #ifdef _WIN_32
37   GetModuleFileName(NULL,ModuleName,sizeof(ModuleName));
38 #else
39   strcpy(ModuleName,argv[0]);
40 #endif
41 #endif
42
43 #ifdef _WIN_32
44   SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
45
46
47 #endif
48
49 #ifdef ALLOW_EXCEPTIONS
50   try 
51 #endif
52   {
53   
54     CommandData Cmd;
55 #ifdef SFX_MODULE
56     strcpy(Cmd.Command,"X");
57     char *Switch=NULL;
58 #ifdef _SFX_RTL_
59     char *CmdLine=GetCommandLine();
60     if (CmdLine!=NULL && *CmdLine=='\"')
61       CmdLine=strchr(CmdLine+1,'\"');
62     if (CmdLine!=NULL && (CmdLine=strpbrk(CmdLine," /"))!=NULL)
63     {
64       while (isspace(*CmdLine))
65         CmdLine++;
66       Switch=CmdLine;
67     }
68 #else
69     Switch=argc>1 ? argv[1]:NULL;
70 #endif
71     if (Switch!=NULL && Cmd.IsSwitch(Switch[0]))
72     {
73       int UpperCmd=toupper(Switch[1]);
74       switch(UpperCmd)
75       {
76         case 'T':
77         case 'V':
78           Cmd.Command[0]=UpperCmd;
79           break;
80         case '?':
81           Cmd.OutHelp();
82           break;
83       }
84     }
85     Cmd.AddArcName(ModuleName,NULL);
86 #else
87     if (Cmd.IsConfigEnabled(argc,argv))
88     {
89       Cmd.ReadConfig(argc,argv);
90       Cmd.ParseEnvVar();
91     }
92     for (int I=1;I<argc;I++)
93       Cmd.ParseArg(argv[I],NULL);
94 #endif
95     Cmd.ParseDone();
96
97
98     InitConsoleOptions(Cmd.MsgStream,Cmd.Sound);
99     InitSystemOptions(Cmd.SleepTime);
100     InitLogOptions(Cmd.LogName);
101     ErrHandler.SetSilent(Cmd.AllYes || Cmd.MsgStream==MSG_NULL);
102     ErrHandler.SetShutdown(Cmd.Shutdown);
103
104     Cmd.OutTitle();
105     Cmd.ProcessCommand();
106   }
107 #ifdef ALLOW_EXCEPTIONS
108   catch (int ErrCode)
109   {
110     ErrHandler.SetErrorCode(ErrCode);
111   }
112 #ifdef ENABLE_BAD_ALLOC
113   catch (bad_alloc)
114   {
115     ErrHandler.SetErrorCode(MEMORY_ERROR);
116   }
117 #endif
118   catch (...)
119   {
120     ErrHandler.SetErrorCode(FATAL_ERROR);
121   }
122 #endif
123   File::RemoveCreated();
124 #if defined(SFX_MODULE) && defined(_DJGPP)
125   _chmod(ModuleName,1,0x20);
126 #endif
127   return(ErrHandler.GetErrorCode());
128 }
129 #endif
130
131
132 #if defined(TARGET_POSIX) || defined(_XBMC)
133 /*-------------------------------------------------------------------------*\
134                                XBOX interface
135 \*-------------------------------------------------------------------------*/
136
137 /*-------------------------------------------------------------------------*\
138   Extract a RAR file
139   rarfile      - Name of the RAR file to uncompress
140   targetPath    - The path to which we want to uncompress
141   fileToExtract - The file inside the archive we want to uncompress,
142           or NULL for all files.
143   libpassword   - Password (for encrypted archives)
144 \*-------------------------------------------------------------------------*/
145 int urarlib_get(char *rarfile, char *targetPath, char *fileToExtract, char *libpassword, int64_t* iOffset, bool bShowProgress)
146 {
147   InitCRC();
148   int bRes = 1;
149
150   // Set the arguments for the extract command
151   auto_ptr<CommandData> pCmd (new CommandData);
152
153   if( pCmd.get() )
154   {
155     strcpy(pCmd->Command, "X");
156     pCmd->AddArcName(rarfile,NULL);
157     strncpy(pCmd->ExtrPath, targetPath, sizeof(pCmd->Command) - 2);
158     pCmd->ExtrPath[sizeof(pCmd->Command) - 2] = '\0';
159     AddEndSlash(pCmd->ExtrPath);
160     pCmd->ParseArg((char*)"-va",NULL);
161     if (fileToExtract)
162     {
163       if (*fileToExtract)
164       {
165         pCmd->FileArgs->AddString(fileToExtract);
166         // Uncomment this if you want to extract a single file without the full path
167         strcpy(pCmd->Command, "E");
168       }
169     }
170     else
171     {
172       pCmd->FileArgs->AddString(MASKALL);
173     }
174
175     // Set password for encrypted archives
176     if (libpassword)
177       if (strlen(libpassword)!=0)
178       {
179         strncpy(pCmd->Password, libpassword, sizeof(pCmd->Password) - 1);
180         pCmd->Password[sizeof(pCmd->Password) - 1] = '\0';
181       }
182
183     // Opent the archive    
184     auto_ptr<Archive> pArc( new Archive(pCmd.get()) );
185     
186     if( pArc.get() )
187     {
188       if (!pArc->WOpen(rarfile,NULL))
189         return 0;
190
191       if (pArc->IsOpened() && pArc->IsArchive(true))
192       {
193         auto_ptr<CmdExtract> pExtract( new CmdExtract );
194         
195         if( pExtract.get() )
196         {
197           pExtract->GetDataIO().SetCurrentCommand(*(pCmd->Command));
198           struct FindData FD;
199           if (FindFile::FastFind(rarfile,NULL,&FD))
200             pExtract->GetDataIO().TotalArcSize+=FD.Size;
201           pExtract->ExtractArchiveInit(pCmd.get(),*pArc);
202
203           if (bShowProgress)
204           {
205             pExtract->GetDataIO().m_pDlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
206             if (pExtract->GetDataIO().m_pDlgProgress)
207             {
208               pExtract->GetDataIO().m_pDlgProgress->SetHeading(fileToExtract);
209               pExtract->GetDataIO().m_pDlgProgress->SetCanCancel(false);
210               pExtract->GetDataIO().m_pDlgProgress->StartModal();
211             }
212           }
213
214           int64_t iOff=0;
215           bool bSeeked = false;
216           while (1)
217           {
218             iOff = pArc->Tell();
219             int Size=pArc->ReadHeader();
220             int Type=pArc->GetHeaderType();
221           
222             if (Type == ENDARC_HEAD)
223               break;
224
225             if (Type != FILE_HEAD)
226             {
227               pArc->SeekToNext();
228               continue;
229             }
230             
231             bool Repeat=false;           
232             if (!pExtract->ExtractCurrentFile(pCmd.get(),*pArc,Size,Repeat))
233             {
234                bRes = FALSE;
235                 break;
236             }
237             
238             if (pExtract->GetDataIO().bQuit) 
239             {
240               if (pExtract->GetDataIO().m_pDlgProgress)
241                 pExtract->GetDataIO().m_pDlgProgress->Close();
242               bRes = 2;
243               break;
244             }
245
246             if (fileToExtract)
247             {
248               if (*fileToExtract)
249               {
250                 bool EqualNames=false;
251                 int MatchNumber=pCmd->IsProcessFile(pArc->NewLhd,&EqualNames);
252                 bool ExactMatch=MatchNumber!=0;
253                 if (ExactMatch)
254                 {
255                   if (iOffset)
256                     *iOffset = iOff;
257                   break;
258                 }
259               }
260             }
261             if (iOffset && !bSeeked && !pArc->Solid)
262             {
263               if (*iOffset > -1)
264               {
265                 bSeeked = true;
266                 pArc->Seek(*iOffset,SEEK_SET);
267               }
268             }
269           }
270
271           pExtract->GetDataIO().ProcessedArcSize+=FD.Size;         
272           if (pExtract->GetDataIO().m_pDlgProgress)
273             pExtract->GetDataIO().m_pDlgProgress->ShowProgressBar(false);
274         }
275         if (bShowProgress)
276           if (pExtract->GetDataIO().m_pDlgProgress)
277             pExtract->GetDataIO().m_pDlgProgress->Close();
278       }
279     }
280   }
281
282   File::RemoveCreated();
283   return bRes;
284 }
285
286 /*-------------------------------------------------------------------------*\
287   List the files in a RAR file
288   rarfile    - Name of the RAR file to uncompress
289   list      - Output. A list of file data of the files in the archive.
290                 The list should be freed with urarlib_freelist().
291   libpassword - Password (for encrypted archives)
292 \*-------------------------------------------------------------------------*/
293 int urarlib_list(char *rarfile, ArchiveList_struct **ppList, char *libpassword, bool stopattwo)
294 {
295   if (!ppList)
296     return 0;
297   uint FileCount = 0;
298   InitCRC();
299
300   // Set the arguments for the extract command
301   auto_ptr<CommandData> pCmd( new CommandData );
302
303   {
304     strcpy(pCmd->Command, "L");
305     pCmd->AddArcName(rarfile, NULL);
306     pCmd->FileArgs->AddString(MASKALL);
307     pCmd->ParseArg((char*)"-va",NULL);
308
309     // Set password for encrypted archives
310     if (libpassword)
311     {
312       strncpy(pCmd->Password, libpassword, sizeof(pCmd->Password) - 1);
313       pCmd->Password[sizeof(pCmd->Password) - 1] = '\0';
314     }
315
316     // Opent the archive
317     auto_ptr<Archive> pArc( new Archive(pCmd.get()) );
318     if ( pArc.get() )
319     {
320       if (!pArc->WOpen(rarfile,NULL))
321         return 0;
322
323       FileCount=0;
324       *ppList = NULL;
325       ArchiveList_struct *pPrev = NULL;
326       int iArchive=0;
327       while (1)
328       {
329         if (pArc->IsOpened() && pArc->IsArchive(true))
330         {
331           int64_t iOffset = pArc->NextBlockPos;
332           while(pArc->ReadHeader()>0)
333           {
334             if (pArc->GetHeaderType() == FILE_HEAD)
335             {
336               if (pPrev)
337                 if (stricmp(pArc->NewLhd.FileName,pPrev->item.Name)==0)
338                 {
339                   iOffset = pArc->NextBlockPos;
340                   pArc->SeekToNext();
341                   continue;
342                 }
343
344               IntToExt(pArc->NewLhd.FileName,pArc->NewLhd.FileName);
345               ArchiveList_struct *pCurr = (ArchiveList_struct *)malloc(sizeof(ArchiveList_struct));
346               if (!pCurr)
347                 break;
348               if (pPrev)
349                 pPrev->next = pCurr;
350               if (!*ppList)
351                 *ppList = pCurr;
352               pCurr->item.NameSize = strlen(pArc->NewLhd.FileName);
353               // sanity check - if it fails the archive is likely corrupt
354               if (pCurr->item.NameSize > NM)
355               {
356                 File::RemoveCreated();
357                 return 0;
358               }
359
360               pCurr->item.Name = (char *)malloc(pCurr->item.NameSize + 1);
361               strcpy(pCurr->item.Name, pArc->NewLhd.FileName);
362               pCurr->item.NameW = (wchar *)malloc((pCurr->item.NameSize + 1)*sizeof(wchar));
363               wcscpy(pCurr->item.NameW, pArc->NewLhd.FileNameW);
364               pCurr->item.PackSize = pArc->NewLhd.PackSize;
365               pCurr->item.UnpSize = int32to64(pArc->NewLhd.HighUnpSize,pArc->NewLhd.UnpSize);
366               pCurr->item.HostOS = pArc->NewLhd.HostOS;
367               pCurr->item.FileCRC = pArc->NewLhd.FileCRC;
368               pCurr->item.FileTime = pArc->NewLhd.FileTime;
369               pCurr->item.UnpVer = pArc->NewLhd.UnpVer;
370               pCurr->item.Method = pArc->NewLhd.Method;
371               pCurr->item.FileAttr = pArc->NewLhd.FileAttr;
372               pCurr->item.iOffset = iOffset;
373               pCurr->next = NULL;
374               pPrev = pCurr;
375               FileCount++;
376               if (stopattwo && FileCount > 1)
377                 break;
378             }
379             iOffset = pArc->NextBlockPos;
380             if (iOffset > pArc->FileLength())
381             {
382               File::RemoveCreated();
383               return 0;
384             }
385             pArc->SeekToNext();
386           }
387           if (pCmd->VolSize!=0 && ((pArc->NewLhd.Flags & LHD_SPLIT_AFTER) || (pArc->GetHeaderType()==ENDARC_HEAD && (pArc->EndArcHead.Flags & EARC_NEXT_VOLUME)!=0)))
388           {
389             if (FileCount == 1 && iArchive==0)
390             {
391               char NextName[NM];
392               char LastName[NM];
393               strcpy(NextName,pArc->FileName);
394               while (XFILE::CFile::Exists(NextName))
395               {
396                 strcpy(LastName,NextName);
397                 NextVolumeName(NextName,(pArc->NewMhd.Flags & MHD_NEWNUMBERING)==0 || pArc->OldFormat);
398               }
399                Archive arc;
400               if (arc.WOpen(LastName,NULL))
401               {
402                 bool bBreak=false;
403                 while(arc.ReadHeader()>0)
404                 {
405                   if (arc.GetHeaderType() == FILE_HEAD)
406                     if (stricmp(arc.NewLhd.FileName,pPrev->item.Name)==0)
407                     {
408                       bBreak=true;
409                       break;  
410                     }
411 //                  iOffset = pArc->Tell();
412                   arc.SeekToNext();
413                 }
414                 if (bBreak)
415                 {
416                   break;
417                 }
418               }
419             }
420             if (MergeArchive(*pArc,NULL,false,*pCmd->Command))
421             {
422               iArchive++;
423               pArc->Seek(0,SEEK_SET); 
424             }
425             else
426               break;
427           }
428           else
429             break;
430         }
431         else
432           break;
433       }
434     }
435   }
436
437   File::RemoveCreated();
438   return FileCount;
439 }
440
441 /*-------------------------------------------------------------------------*\
442   Free the file list returned by urarlib_list()
443   list - The output from urarlib_list()
444 \*-------------------------------------------------------------------------*/
445 void urarlib_freelist(ArchiveList_struct *list)
446 {
447   ArchiveList_struct *p;
448   while (list)
449   {
450     p = list->next;
451     free(list->item.Name);
452     free(list->item.NameW);
453     free(list);
454     list = p;
455   }
456 }
457
458
459 #endif