Merge pull request #4852 from FernetMenta/aefixes
[vuplus_xbmc] / lib / UnrarXLib / file.cpp
1 #include "rar.hpp"
2
3 // BE WARNED THIS FILE IS HEAVILY MODIFIED TO BE USED WITH XBMC
4
5 #include "filesystem/Directory.h"
6 #include "filesystem/File.h"
7 #include "Util.h"
8 #include "utils/URIUtils.h"
9
10 //static File *CreatedFiles[32];
11 static int RemoveCreatedActive=0;
12
13 File::File()
14   :  m_File(*(new XFILE::CFile()))
15
16 {
17 //  hFile=BAD_HANDLE;
18   *FileName=0;
19   *FileNameW=0;
20   NewFile=false;
21   LastWrite=false;
22   HandleType=FILE_HANDLENORMAL;
23   SkipClose=false;
24   IgnoreReadErrors=false;
25   ErrorType=FILE_SUCCESS;
26   OpenShared=false;
27   AllowDelete=true;
28   CloseCount=0;
29   AllowExceptions=true;
30 }
31
32
33 File::~File()
34 {
35   /*if (hFile!=BAD_HANDLE && !SkipClose)
36     if (NewFile)
37       Delete();
38     else
39       Close();*/
40   m_File.Close();
41   delete &m_File;
42 }
43
44
45 void File::operator = (File &SrcFile)
46 {
47   //hFile=SrcFile.hFile;
48   m_File = SrcFile.m_File;
49   strcpy(FileName,SrcFile.FileName);
50   NewFile=SrcFile.NewFile;
51   LastWrite=SrcFile.LastWrite;
52   HandleType=SrcFile.HandleType;
53   SrcFile.SkipClose=true;
54 }
55
56
57 bool File::Open(const char *Name,const wchar *NameW,bool OpenShared,bool Update)
58 {
59  // Below commented code was left behind on spiffs request for possible later usage
60  
61   /*ErrorType=FILE_SUCCESS;
62   FileHandle hNewFile;
63   if (File::OpenShared)
64     OpenShared=true;
65 #ifdef _WIN_32
66   uint Access=GENERIC_READ;
67   if (Update)
68     Access|=GENERIC_WRITE;
69   uint ShareMode=FILE_SHARE_READ;
70   if (OpenShared)
71     ShareMode|=FILE_SHARE_WRITE;
72 #ifndef _XBOX
73   if (WinNT() && NameW!=NULL && *NameW!=0)
74     hNewFile=CreateFileW(NameW,Access,ShareMode,NULL,OPEN_EXISTING,
75                          FILE_FLAG_SEQUENTIAL_SCAN,NULL);
76   else
77 #endif
78     hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,
79                         FILE_FLAG_SEQUENTIAL_SCAN,NULL);
80
81   if (hNewFile==BAD_HANDLE && GetLastError()==ERROR_FILE_NOT_FOUND)
82     ErrorType=FILE_NOTFOUND;
83 #else
84   int flags=Update ? O_RDWR:O_RDONLY;
85 #ifdef O_BINARY
86   flags|=O_BINARY;
87 #if defined(_AIX) && defined(_LARGE_FILE_API)
88   flags|=O_LARGEFILE;
89 #endif
90 #endif
91 #if defined(_EMX) && !defined(_DJGPP)
92   int sflags=OpenShared ? SH_DENYNO:SH_DENYWR;
93   int handle=sopen(Name,flags,sflags);
94 #else
95   int handle=open(Name,flags);
96 #ifdef LOCK_EX
97   if (!OpenShared && Update && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1)
98   {
99     close(handle);
100     return(false);
101   }
102 #endif
103 #endif
104   hNewFile=handle==-1 ? BAD_HANDLE:fdopen(handle,Update ? UPDATEBINARY:READBINARY);
105   if (hNewFile==BAD_HANDLE && errno==ENOENT)
106     ErrorType=FILE_NOTFOUND;
107 #endif
108   NewFile=false;
109   HandleType=FILE_HANDLENORMAL;
110   SkipClose=false;
111   bool success=hNewFile!=BAD_HANDLE;*/
112   char _name[NM];
113   if (NameW!=NULL)
114     WideToUtf(NameW, _name, sizeof(_name));
115   else
116     strcpy(_name, Name);
117   bool success;
118   if (Update)
119     success = m_File.OpenForWrite(_name);
120   else
121     success = m_File.Open(_name);
122   if (success)
123   {
124 //    hFile=hNewFile;
125     if (NameW!=NULL)
126       strcpyw(FileNameW,NameW);
127     else
128       *FileNameW=0;
129     if (Name!=NULL)
130       strcpy(FileName,Name);
131     else
132       WideToChar(NameW,FileName);
133     //AddFileToList(hFile);
134     AddFileToList();
135   }
136   return(success);
137 }
138
139
140 #if !defined(SHELL_EXT) && !defined(SFX_MODULE)
141 void File::TOpen(const char *Name,const wchar *NameW)
142 {
143   if (!WOpen(Name,NameW))
144     ErrHandler.Exit(OPEN_ERROR);
145 }
146 #endif
147
148
149 bool File::WOpen(const char *Name,const wchar *NameW)
150 {
151   if (Open(Name,NameW))
152     return(true);
153   ErrHandler.OpenErrorMsg(Name);
154   return(false);
155 }
156
157
158 bool File::Create(const char *Name,const wchar *NameW)
159 {
160 // Below commented code was left behind on spiffs request for possible later usage 
161 /*#ifdef _WIN_32
162 #ifndef _XBOX
163   if (WinNT() && NameW!=NULL && *NameW!=0)
164     hFile=CreateFileW(NameW,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,
165                       CREATE_ALWAYS,0,NULL);
166   else
167 #endif
168     hFile=CreateFile(Name,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,
169                      CREATE_ALWAYS,0,NULL);
170 #else
171   hFile=fopen(Name,CREATEBINARY);
172 #endif*/
173   char _name[NM];
174   if (NameW!=NULL)
175     WideToUtf(NameW, _name, sizeof(_name));
176   else
177     strcpy(_name, Name);
178   CStdString strPath = URIUtils::GetDirectory(_name);
179   CUtil::CreateDirectoryEx(strPath);
180   m_File.OpenForWrite(_name,true);
181   NewFile=true;
182   HandleType=FILE_HANDLENORMAL;
183   SkipClose=false;
184   if (NameW!=NULL)
185     strcpyw(FileNameW,NameW);
186   else
187     *FileNameW=0;
188   if (Name!=NULL)
189     strcpy(FileName,Name);
190   else
191     WideToChar(NameW,FileName);
192   //AddFileToList(hFile);
193   AddFileToList();
194   //return(hFile!=BAD_HANDLE);
195   return true;
196 }
197
198
199 //void File::AddFileToList(FileHandle hFile)
200 void File::AddFileToList()
201 {
202   //if (hFile!=BAD_HANDLE)
203     //for (int I=0;I<sizeof(CreatedFiles)/sizeof(CreatedFiles[0]);I++)
204     /*for (int I=0;I<32;I++)
205       if (CreatedFiles[I]==NULL)
206       {
207         CreatedFiles[I]=this;
208         break;
209       }*/
210 }
211
212
213 #if !defined(SHELL_EXT) && !defined(SFX_MODULE)
214 void File::TCreate(const char *Name,const wchar *NameW)
215 {
216   if (!WCreate(Name,NameW))
217     ErrHandler.Exit(FATAL_ERROR);
218 }
219 #endif
220
221
222 bool File::WCreate(const char *Name,const wchar *NameW)
223 {
224   if (Create(Name,NameW))
225     return(true);
226   ErrHandler.SetErrorCode(CREATE_ERROR);
227   ErrHandler.CreateErrorMsg(Name);
228   return(false);
229 }
230
231
232 bool File::Close()
233 {
234   bool success=true;
235   /*if (HandleType!=FILE_HANDLENORMAL)
236     HandleType=FILE_HANDLENORMAL;
237   else
238     if (hFile!=BAD_HANDLE)
239     {*/
240       if (!SkipClose)
241       {
242 #if defined(_WIN_32) || defined(TARGET_POSIX)
243         //success=CloseHandle(hFile) != FALSE;
244         m_File.Close();
245 #else
246         success=fclose(hFile)!=EOF;
247 #endif
248 /*        if (success || !RemoveCreatedActive)
249           //for (int I=0;I<sizeof(CreatedFiles)/sizeof(CreatedFiles[0]);I++)
250           for (int I=0;I<32;I++)
251             if (CreatedFiles[I]==this)
252             {
253               CreatedFiles[I]=NULL;
254               break;
255             }*/
256       }
257       //hFile=BAD_HANDLE;
258       if (!success && AllowExceptions)
259         ErrHandler.CloseError(FileName);
260     //}
261   CloseCount++;
262   return(success);
263   //return(true);
264 }
265   
266
267 void File::Flush()
268 {
269   m_File.Flush();
270 /*#ifdef _WIN_32
271   FlushFileBuffers(hFile);
272 #else
273   fflush(hFile);
274 #endif*/
275 }
276
277
278 bool File::Delete()
279 {
280   /*if (HandleType!=FILE_HANDLENORMAL || !AllowDelete)
281     return(false);
282   if (hFile!=BAD_HANDLE)
283     Close();
284   return(DelFile(FileName,FileNameW));*/
285   return m_File.Delete(FileName);
286 }
287
288
289 bool File::Rename(const char *NewName)
290 {
291   bool success=strcmp(FileName,NewName)==0;
292   if (!success)
293     success=rename(FileName,NewName)==0;
294   if (success)
295   {
296     strcpy(FileName,NewName);
297     *FileNameW=0;
298   }
299   return(success);
300 }
301
302
303 void File::Write(const void *Data,int Size)
304 {
305 // Below commented code was left behind on spiffs request for possible later usage
306   /*if (Size==0)
307     return;
308 //#ifndef _WIN_CE
309 #if !defined(_WIN_CE) && !defined(_XBOX)
310   if (HandleType!=FILE_HANDLENORMAL)
311     switch(HandleType)
312     {
313       case FILE_HANDLESTD:
314 #ifdef _WIN_32
315         hFile=GetStdHandle(STD_OUTPUT_HANDLE);
316 #else
317         hFile=stdout;
318 #endif
319         break;
320       case FILE_HANDLEERR:
321 #ifdef _WIN_32
322         hFile=GetStdHandle(STD_ERROR_HANDLE);
323 #else
324         hFile=stderr;
325 #endif
326         break;
327     }
328 #endif*/
329   while (1)
330   {
331     bool success = true;
332 #if defined(_WIN_32) || defined(TARGET_POSIX)
333     DWORD Written=0;
334     if (HandleType!=FILE_HANDLENORMAL)
335     {
336       const int MaxSize=0x4000;
337       for (int I=0;I<Size;I+=MaxSize)
338         //if (!(success=WriteFile(hFile,(byte *)Data+I,Min(Size-I,MaxSize),&Written,NULL) != FALSE))
339         m_File.Write((byte*)Data+I,Min(Size-I,MaxSize));
340         //  break;
341     }
342     else
343     {
344       //success=WriteFile(hFile,Data,Size,&Written,NULL) != FALSE;
345       m_File.Write(Data,Size);
346     }
347 #else
348     success=fwrite(Data,1,Size,hFile)==Size && !ferror(hFile);
349 #endif
350     if (!success && AllowExceptions && HandleType==FILE_HANDLENORMAL)
351     {
352 #if defined(_WIN_32) && !defined(SFX_MODULE) && !defined(RARDLL)
353       int ErrCode=GetLastError();
354       Int64 FilePos=Tell();
355       Int64 FreeSize=GetFreeDisk(FileName);
356       SetLastError(ErrCode);
357       if (FreeSize>Size && FilePos-Size<=0xffffffff && FilePos+Size>0xffffffff)
358         ErrHandler.WriteErrorFAT(FileName);
359 #endif
360       if (ErrHandler.AskRepeatWrite(FileName))
361       {
362 #if !defined(_WIN_32) && !defined(TARGET_POSIX)
363         clearerr(hFile);
364 #endif
365       if (Written<(unsigned int)Size && Written>0)
366           Seek(Tell()-Written,SEEK_SET);
367         continue;
368       }
369       ErrHandler.WriteError(NULL,FileName);
370     }
371     break;
372   }
373   LastWrite=true;
374 }
375
376
377 int File::Read(void *Data,int Size)
378 {
379   Int64 FilePos = 0;
380   if (IgnoreReadErrors)
381     FilePos=Tell();
382   int ReadSize;
383   while (true)
384   {
385     ReadSize=DirectRead(Data,Size);
386     if (ReadSize==-1)
387     {
388       ErrorType=FILE_READERROR;
389       if (AllowExceptions)
390       {
391         if (IgnoreReadErrors)
392         {
393           ReadSize=0;
394           for (int I=0;I<Size;I+=512)
395           {
396             Seek(FilePos+I,SEEK_SET);
397             int SizeToRead=Min(Size-I,512);
398             int ReadCode=DirectRead(Data,SizeToRead);
399             ReadSize+=(ReadCode==-1) ? 512:ReadCode;
400           }
401         }
402         else
403         {
404           if (HandleType==FILE_HANDLENORMAL && ErrHandler.AskRepeatRead(FileName))
405             continue;
406           ErrHandler.ReadError(FileName);
407         }
408       }
409     }
410     break;
411   }
412   
413   return(ReadSize);
414 }
415
416
417 int File::DirectRead(void *Data,int Size)
418 {
419   int Read = 0;
420   while (Size)
421   {
422     int nRead = m_File.Read(Data,Size);
423     if (nRead == 0)
424       break;
425     Read += nRead;
426     Data = (void*)(((char*)Data)+nRead);
427     Size -= nRead;
428   }
429   //if (Read == 0)
430    // return -1;
431
432   return Read;
433 #if 0
434   #ifdef _WIN_32
435   const int MaxDeviceRead=20000;
436 #endif
437 // Below commented code was left behind on spiffs request for possible later usage
438  
439 //#ifndef _WIN_CE
440 /*#if !defined(_WIN_CE) && !defined(_XBOX)
441   if (HandleType==FILE_HANDLESTD)
442   {
443 #ifdef _WIN_32
444     if (Size>MaxDeviceRead)
445       Size=MaxDeviceRead;
446     hFile=GetStdHandle(STD_INPUT_HANDLE);
447 #else
448     hFile=stdin;
449 #endif
450   }
451 #endif
452 #ifdef _WIN_32
453   DWORD Read;
454   //if (!ReadFile(hFile,Data,Size,&Read,NULL))
455   Read = m_File.Read(Data,Size);
456   if ((Read != Size) && (m_File.GetPosition() != m_File.GetLength()))
457   {
458     if (IsDevice() && Size>MaxDeviceRead)
459       return(DirectRead(Data,MaxDeviceRead));
460     if (HandleType==FILE_HANDLESTD && GetLastError()==ERROR_BROKEN_PIPE)
461       return(0);
462     return(-1);
463   }
464   return(Read);
465 #else
466   if (LastWrite)
467   {
468     fflush(hFile);
469     LastWrite=false;
470   }
471   clearerr(hFile);
472   int ReadSize=fread(Data,1,Size,hFile);
473   if (ferror(hFile))
474     return(-1);
475   return(ReadSize);
476 #endif*/
477 #endif
478 }
479
480
481 void File::Seek(Int64 Offset,int Method)
482 {
483   if (!RawSeek(Offset,Method) && AllowExceptions)
484     ErrHandler.SeekError(FileName);
485 }
486
487
488 bool File::RawSeek(Int64 Offset,int Method)
489 {
490   /*if (hFile==BAD_HANDLE)
491     return(true);*/
492   /*if (!is64plus(Offset) && Method!=SEEK_SET)
493   {
494     Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset;
495     Method=SEEK_SET;
496   }*/
497 #if defined(_WIN_32) || defined(TARGET_POSIX)
498   //LONG HighDist=int64to32(Offset>>32);
499   //if (SetFilePointer(hFile,int64to32(Offset),&HighDist,Method)==0xffffffff &&
500   if (Offset > FileLength())
501     return false;
502
503   if (m_File.Seek(Offset,Method) < 0)
504   {
505     return(false);
506   }
507 #else
508   LastWrite=false;
509 #ifdef _LARGEFILE_SOURCE
510   if (fseeko(hFile,Offset,Method)!=0)
511 #else
512   if (fseek(hFile,int64to32(Offset),Method)!=0)
513 #endif
514     return(false);
515 #endif
516   return(true);
517 }
518
519
520 Int64 File::Tell()
521 {
522 #if defined(_WIN_32) || defined(TARGET_POSIX)
523   //LONG HighDist=0;
524   //uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT);
525   //Int64 pos = m_File.GetPosition();
526   return m_File.GetPosition();
527   /*if (LowDist==0xffffffff && GetLastError()!=NO_ERROR)
528     if (AllowExceptions)
529       ErrHandler.SeekError(FileName);
530     else
531       return(-1);
532   return(int32to64(HighDist,LowDist));*/
533 #else
534 #ifdef _LARGEFILE_SOURCE
535   return(ftello(hFile));
536 #else
537   return(ftell(hFile));
538 #endif
539 #endif
540 }
541
542
543 void File::Prealloc(Int64 Size)
544 {
545 #ifdef _WIN_32
546   if (RawSeek(Size,SEEK_SET))
547   {
548     Truncate();
549     Seek(0,SEEK_SET);
550   }
551 #endif
552 }
553
554
555 byte File::GetByte()
556 {
557   byte Byte=0;
558   Read(&Byte,1);
559   return(Byte);
560 }
561
562
563 void File::PutByte(byte Byte)
564 {
565   Write(&Byte,1);
566 }
567
568
569 bool File::Truncate()
570 {
571 #ifdef _WIN_32
572   //return(SetEndOfFile(hFile) != FALSE);
573   return true;
574 #else
575   return(false);
576 #endif
577 }
578
579
580 void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
581 {
582 #ifdef _WIN_32
583 // Below commented code was left behind on spiffs request for possible later usage
584  
585   /*bool sm=ftm!=NULL && ftm->IsSet();
586   bool sc=ftc!=NULL && ftc->IsSet();
587   bool sa=fta!=NULL && fta->IsSet();
588   FILETIME fm,fc,fa;
589   if (sm)
590     ftm->GetWin32(&fm);
591   if (sc)
592     ftc->GetWin32(&fc);
593   if (sa)
594     fta->GetWin32(&fa);
595   //SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL);*/
596 #endif
597 }
598
599
600 void File::SetCloseFileTime(RarTime *ftm,RarTime *fta)
601 {
602 #if defined(_UNIX) || defined(_EMX)
603   SetCloseFileTimeByName(FileName,ftm,fta);
604 #endif
605 }
606
607
608 void File::SetCloseFileTimeByName(const char *Name,RarTime *ftm,RarTime *fta)
609 {
610 #if defined(_UNIX) || defined(_EMX)
611   bool setm=ftm!=NULL && ftm->IsSet();
612   bool seta=fta!=NULL && fta->IsSet();
613   if (setm || seta)
614   {
615     struct utimbuf ut;
616     if (setm)
617       ut.modtime=ftm->GetUnix();
618     else
619       ut.modtime=fta->GetUnix();
620     if (seta)
621       ut.actime=fta->GetUnix();
622     else
623       ut.actime=ut.modtime;
624     utime(Name,&ut);
625   }
626 #endif
627 }
628
629
630 void File::GetOpenFileTime(RarTime *ft)
631 {
632 #if defined(_WIN_32) || defined(TARGET_POSIX)
633 /*  FILETIME FileTime;
634   GetFileTime(hFile,NULL,NULL,&FileTime);
635   *ft=FileTime;*/
636 #endif
637 /*
638 #if defined(_UNIX) || defined(_EMX)
639   struct stat st;
640   fstat(fileno(hFile),&st);
641   *ft=st.st_mtime;
642 #endif
643 */
644 }
645
646
647 void File::SetOpenFileStat(RarTime *ftm,RarTime *ftc,RarTime *fta)
648 {
649 #ifdef _WIN_32
650   //SetOpenFileTime(ftm,ftc,fta);
651 #endif
652 }
653
654
655 void File::SetCloseFileStat(RarTime *ftm,RarTime *fta,uint FileAttr)
656 {
657 #ifdef _WIN_32
658   //SetFileAttr(FileName,FileNameW,FileAttr);
659 #endif
660 #ifdef _EMX
661   SetCloseFileTime(ftm,fta);
662   SetFileAttr(FileName,FileNameW,FileAttr);
663 #endif
664 #ifdef _UNIX
665   SetCloseFileTime(ftm,fta);
666   chmod(FileName,(mode_t)FileAttr);
667 #endif
668 }
669
670
671 Int64 File::FileLength()
672 {
673   return (m_File.GetLength());
674 }
675
676
677 void File::SetHandleType(FILE_HANDLETYPE Type)
678 {
679   HandleType=Type;
680 }
681
682
683 bool File::IsDevice()
684 {
685   /*if (hFile==BAD_HANDLE)
686     return(false);*/
687 #if defined(_XBOX) || defined(TARGET_POSIX) || defined(_XBMC)
688   return false;
689 //#ifdef _WIN_32
690 #elif defined(_WIN_32)
691   uint Type=GetFileType(hFile);
692   return(Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE);
693 #else
694   return(isatty(fileno(hFile)));
695 #endif
696 }
697
698
699 #ifndef SFX_MODULE
700 void File::fprintf(const char *fmt,...)
701 {
702   va_list argptr;
703   va_start(argptr,fmt);
704   safebuf char Msg[2*NM+1024],OutMsg[2*NM+1024];
705   vsprintf(Msg,fmt,argptr);
706 #ifdef _WIN_32
707   for (int Src=0,Dest=0;;Src++)
708   {
709     char CurChar=Msg[Src];
710     if (CurChar=='\n')
711       OutMsg[Dest++]='\r';
712     OutMsg[Dest++]=CurChar;
713     if (CurChar==0)
714       break;
715   }
716 #else
717   strcpy(OutMsg,Msg);
718 #endif
719   Write(OutMsg,strlen(OutMsg));
720   va_end(argptr);
721 }
722 #endif
723
724
725 bool File::RemoveCreated()
726 {
727   RemoveCreatedActive++;
728   bool RetCode=true;
729   //for (int I=0;I<sizeof(CreatedFiles)/sizeof(CreatedFiles[0]);I++)
730   /*for (int I=0;I<32;I++)
731     if (CreatedFiles[I]!=NULL)
732     {
733       CreatedFiles[I]->SetExceptions(false);
734       bool success;
735       if (CreatedFiles[I]->NewFile)
736         success=CreatedFiles[I]->Delete();
737       else
738         success=CreatedFiles[I]->Close();
739       if (success)
740         CreatedFiles[I]=NULL;
741       else
742         RetCode=false;
743     }
744   RemoveCreatedActive--;*/
745   return(RetCode);
746 }
747
748
749 #ifndef SFX_MODULE
750 long File::Copy(File &Dest,Int64 Length)
751 {
752   Array<char> Buffer(0x10000);
753   long CopySize=0;
754   bool CopyAll=(Length==INT64ERR);
755
756   while (CopyAll || Length>0)
757   {
758     Wait();
759     int SizeToRead=(!CopyAll && Length<Buffer.Size()) ? int64to32(Length):Buffer.Size();
760     int ReadSize=Read(&Buffer[0],SizeToRead);
761     if (ReadSize==0)
762       break;
763     Dest.Write(&Buffer[0],ReadSize);
764     CopySize+=ReadSize;
765     if (!CopyAll)
766       Length-=ReadSize;
767   }
768   return(CopySize);
769 }
770 #endif