1 //  This file is part of par2cmdline (a PAR 2.0 compatible file verification and
2 //  repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
3 //
4 //  Copyright (c) 2003 Peter Brian Clements
5 //
6 //  par2cmdline is free software; you can redistribute it and/or modify
7 //  it under the terms of the GNU General Public License as published by
8 //  the Free Software Foundation; either version 2 of the License, or
9 //  (at your option) any later version.
10 //
11 //  par2cmdline is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
19 
20 #include "par2cmdline.h"
21 
22 #ifdef _MSC_VER
23 #ifdef _DEBUG
24 #undef THIS_FILE
25 static char THIS_FILE[]=__FILE__;
26 #define new DEBUG_NEW
27 #endif
28 #endif
29 
30 
31 #ifdef WIN32
32 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
33 
34 #define OffsetType __int64
35 #define MaxOffset 0x7fffffffffffffffI64
36 #define LengthType unsigned int
37 #define MaxLength 0xffffffffUL
38 
DiskFile(void)39 DiskFile::DiskFile(void)
40 {
41   filename;
42   filesize = 0;
43   offset = 0;
44 
45   hFile = INVALID_HANDLE_VALUE;
46 
47   exists = false;
48 }
49 
~DiskFile(void)50 DiskFile::~DiskFile(void)
51 {
52   if (hFile != INVALID_HANDLE_VALUE)
53     ::CloseHandle(hFile);
54 }
55 
56 // Create new file on disk and make sure that there is enough
57 // space on disk for it.
Create(string _filename,u64 _filesize)58 bool DiskFile::Create(string _filename, u64 _filesize)
59 {
60   assert(hFile == INVALID_HANDLE_VALUE);
61 
62   filename = _filename;
63   filesize = _filesize;
64 
65   // Create the file
66   hFile = ::CreateFileA(_filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
67   if (hFile == INVALID_HANDLE_VALUE)
68   {
69     DWORD error = ::GetLastError();
70 
71     cerr << "Could not create \"" << _filename << "\": " << ErrorMessage(error) << endl;
72 
73     return false;
74   }
75 
76   if (filesize > 0)
77   {
78     // Seek to the end of the file
79     LONG lowoffset = ((LONG*)&filesize)[0];
80     LONG highoffset = ((LONG*)&filesize)[1];
81 
82     if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, lowoffset, &highoffset, FILE_BEGIN))
83     {
84       DWORD error = ::GetLastError();
85 
86       cerr << "Could not set size of \"" << _filename << "\": " << ErrorMessage(error) << endl;
87 
88       ::CloseHandle(hFile);
89       hFile = INVALID_HANDLE_VALUE;
90       ::DeleteFile(_filename.c_str());
91 
92       return false;
93     }
94 
95     // Set the end of the file
96     if (!::SetEndOfFile(hFile))
97     {
98       DWORD error = ::GetLastError();
99 
100       cerr << "Could not set size of \"" << _filename << "\": " << ErrorMessage(error) << endl;
101 
102       ::CloseHandle(hFile);
103       hFile = INVALID_HANDLE_VALUE;
104       ::DeleteFile(_filename.c_str());
105 
106       return false;
107     }
108   }
109 
110   offset = filesize;
111 
112   exists = true;
113   return true;
114 }
115 
116 // Write some data to disk
117 
Write(u64 _offset,const void * buffer,size_t length)118 bool DiskFile::Write(u64 _offset, const void *buffer, size_t length)
119 {
120   assert(hFile != INVALID_HANDLE_VALUE);
121 
122   if (offset != _offset)
123   {
124     LONG lowoffset = ((LONG*)&_offset)[0];
125     LONG highoffset = ((LONG*)&_offset)[1];
126 
127     // Seek to the required offset
128     if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, lowoffset, &highoffset, FILE_BEGIN))
129     {
130       DWORD error = ::GetLastError();
131 
132       cerr << "Could not write " << (u64)length << " bytes to \"" << filename << "\" at offset " << _offset << ": " << ErrorMessage(error) << endl;
133 
134       return false;
135     }
136     offset = _offset;
137   }
138 
139   if (length > MaxLength)
140   {
141     cerr << "Could not write " << (u64)length << " bytes to \"" << filename << "\" at offset " << _offset << ": " << "Write too long" << endl;
142 
143     return false;
144   }
145 
146   DWORD write = (LengthType)length;
147   DWORD wrote;
148 
149   // Write the data
150   if (!::WriteFile(hFile, buffer, write, &wrote, NULL))
151   {
152     DWORD error = ::GetLastError();
153 
154     cerr << "Could not write " << (u64)length << " bytes to \"" << filename << "\" at offset " << _offset << ": " << ErrorMessage(error) << endl;
155 
156     return false;
157   }
158 
159   offset += length;
160 
161   if (filesize < offset)
162   {
163     filesize = offset;
164   }
165 
166   return true;
167 }
168 
169 // Open the file
170 
Open(string _filename,u64 _filesize)171 bool DiskFile::Open(string _filename, u64 _filesize)
172 {
173   assert(hFile == INVALID_HANDLE_VALUE);
174 
175   filename = _filename;
176   filesize = _filesize;
177 
178   hFile = ::CreateFileA(_filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
179   if (hFile == INVALID_HANDLE_VALUE)
180   {
181     DWORD error = ::GetLastError();
182 
183     switch (error)
184     {
185     case ERROR_FILE_NOT_FOUND:
186     case ERROR_PATH_NOT_FOUND:
187       break;
188     default:
189       cerr << "Could not open \"" << _filename << "\": " << ErrorMessage(error) << endl;
190     }
191 
192     return false;
193   }
194 
195   offset = 0;
196   exists = true;
197 
198   return true;
199 }
200 
201 // Read some data from disk
202 
Read(u64 _offset,void * buffer,size_t length)203 bool DiskFile::Read(u64 _offset, void *buffer, size_t length)
204 {
205   assert(hFile != INVALID_HANDLE_VALUE);
206 
207   if (offset != _offset)
208   {
209     LONG lowoffset = ((LONG*)&_offset)[0];
210     LONG highoffset = ((LONG*)&_offset)[1];
211 
212     // Seek to the required offset
213     if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, lowoffset, &highoffset, FILE_BEGIN))
214     {
215       DWORD error = ::GetLastError();
216 
217       cerr << "Could not read " << (u64)length << " bytes from \"" << filename << "\" at offset " << _offset << ": " << ErrorMessage(error) << endl;
218 
219       return false;
220     }
221     offset = _offset;
222   }
223 
224   if (length > MaxLength)
225   {
226     cerr << "Could not read " << (u64)length << " bytes from \"" << filename << "\" at offset " << _offset << ": " << "Read too long" << endl;
227 
228     return false;
229   }
230 
231   DWORD want = (LengthType)length;
232   DWORD got;
233 
234   // Read the data
235   if (!::ReadFile(hFile, buffer, want, &got, NULL))
236   {
237     DWORD error = ::GetLastError();
238 
239     cerr << "Could not read " << (u64)length << " bytes from \"" << filename << "\" at offset " << _offset << ": " << ErrorMessage(error) << endl;
240 
241     return false;
242   }
243 
244   offset += length;
245 
246   return true;
247 }
248 
Close(void)249 void DiskFile::Close(void)
250 {
251   if (hFile != INVALID_HANDLE_VALUE)
252   {
253     ::CloseHandle(hFile);
254     hFile = INVALID_HANDLE_VALUE;
255   }
256 }
257 
GetCanonicalPathname(string filename)258 string DiskFile::GetCanonicalPathname(string filename)
259 {
260   char fullname[MAX_PATH];
261   char *filepart;
262 
263   // Resolve a relative path to a full path
264   int length = ::GetFullPathName(filename.c_str(), sizeof(fullname), fullname, &filepart);
265   if (length <= 0 || sizeof(fullname) < length)
266     return filename;
267 
268   // Make sure the drive letter is upper case.
269   fullname[0] = toupper(fullname[0]);
270 
271   // Translate all /'s to \'s
272   char *current = strchr(fullname, '/');
273   while (current)
274   {
275     *current++ = '\\';
276     current  = strchr(current, '/');
277   }
278 
279   // Copy the root directory to the output string
280   string longname(fullname, 3);
281 
282   // Start processing at the first path component
283   current = &fullname[3];
284   char *limit = &fullname[length];
285 
286   // Process until we reach the end of the full name
287   while (current < limit)
288   {
289     char *tail;
290 
291     // Find the next \, or the end of the string
292     (tail = strchr(current, '\\')) || (tail = limit);
293     *tail = 0;
294 
295     // Create a wildcard to search for the path
296     string wild = longname + current;
297     WIN32_FIND_DATA finddata;
298     HANDLE hFind = ::FindFirstFile(wild.c_str(), &finddata);
299     if (hFind == INVALID_HANDLE_VALUE)
300     {
301       // If the component was not found then just copy the rest of the path to the
302       // output buffer verbatim.
303       longname += current;
304       break;
305     }
306     ::FindClose(hFind);
307 
308     // Copy the component found to the output
309     longname += finddata.cFileName;
310 
311     current = tail + 1;
312 
313     // If we have not reached the end of the name, add a "\"
314     if (current < limit)
315       longname += '\\';
316   }
317 
318   return longname;
319 }
320 
FindFiles(string path,string wildcard)321 list<string>* DiskFile::FindFiles(string path, string wildcard)
322 {
323   list<string> *matches = new list<string>;
324 
325   wildcard = path + wildcard;
326   WIN32_FIND_DATA fd;
327   HANDLE h = ::FindFirstFile(wildcard.c_str(), &fd);
328   if (h != INVALID_HANDLE_VALUE)
329   {
330     do
331     {
332       if (0 == (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
333       {
334         matches->push_back(path + fd.cFileName);
335       }
336     } while (::FindNextFile(h, &fd));
337     ::FindClose(h);
338   }
339 
340   return matches;
341 }
342 
343 
344 
345 
346 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
347 #else // !WIN32
348 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
349 
350 #ifdef HAVE_FSEEKO
351 # define OffsetType off_t
352 # define MaxOffset ((off_t)0x7fffffffffffffffULL)
353 # define fseek fseeko
354 #else
355 # if _FILE_OFFSET_BITS == 64
356 #  define OffsetType unsigned long long
357 #  define MaxOffset 0x7fffffffffffffffULL
358 # else
359 #  define OffsetType long
360 #  define MaxOffset 0x7fffffffUL
361 # endif
362 #endif
363 
364 #define LengthType unsigned int
365 #define MaxLength 0xffffffffUL
366 
DiskFile(void)367 DiskFile::DiskFile(void)
368 {
369   //filename;
370   filesize = 0;
371   offset = 0;
372 
373   file = 0;
374 
375   exists = false;
376 }
377 
~DiskFile(void)378 DiskFile::~DiskFile(void)
379 {
380   if (file != 0)
381     fclose(file);
382 }
383 
384 // Create new file on disk and make sure that there is enough
385 // space on disk for it.
Create(string _filename,u64 _filesize)386 bool DiskFile::Create(string _filename, u64 _filesize)
387 {
388   assert(file == 0);
389 
390   filename = _filename;
391   filesize = _filesize;
392 
393   file = fopen(_filename.c_str(), "wb");
394   if (file == 0)
395   {
396     cerr << "Could not create: " << _filename << endl;
397 
398     return false;
399   }
400 
401   if (_filesize > (u64)MaxOffset)
402   {
403     cerr << "Requested file size for " << _filename << " is too large." << endl;
404     return false;
405   }
406 
407   if (_filesize > 0)
408   {
409     if (fseek(file, (OffsetType)_filesize-1, SEEK_SET))
410     {
411       fclose(file);
412       file = 0;
413       ::remove(filename.c_str());
414 
415       cerr << "Could not set end of file: " << _filename << endl;
416       return false;
417     }
418 
419     if (1 != fwrite(&_filesize, 1, 1, file))
420     {
421       fclose(file);
422       file = 0;
423       ::remove(filename.c_str());
424 
425       cerr << "Could not set end of file: " << _filename << endl;
426       return false;
427     }
428   }
429 
430   offset = filesize;
431 
432   exists = true;
433   return true;
434 }
435 
436 // Write some data to disk
437 
Write(u64 _offset,const void * buffer,size_t length)438 bool DiskFile::Write(u64 _offset, const void *buffer, size_t length)
439 {
440   assert(file != 0);
441 
442   if (offset != _offset)
443   {
444     if (_offset > (u64)MaxOffset)
445     {
446       cerr << "Could not write " << (u64)length << " bytes to " << filename << " at offset " << _offset << endl;
447       return false;
448     }
449 
450 
451     if (fseek(file, (OffsetType)_offset, SEEK_SET))
452     {
453       cerr << "Could not write " << (u64)length << " bytes to " << filename << " at offset " << _offset << endl;
454       return false;
455     }
456     offset = _offset;
457   }
458 
459   if (length > MaxLength)
460   {
461     cerr << "Could not write " << (u64)length << " bytes to " << filename << " at offset " << _offset << endl;
462     return false;
463   }
464 
465   if (1 != fwrite(buffer, (LengthType)length, 1, file))
466   {
467     cerr << "Could not write " << (u64)length << " bytes to " << filename << " at offset " << _offset << endl;
468     return false;
469   }
470 
471   offset += length;
472 
473   if (filesize < offset)
474   {
475     filesize = offset;
476   }
477 
478   return true;
479 }
480 
481 // Open the file
482 
Open(string _filename,u64 _filesize)483 bool DiskFile::Open(string _filename, u64 _filesize)
484 {
485   assert(file == 0);
486 
487   filename = _filename;
488   filesize = _filesize;
489 
490   if (_filesize > (u64)MaxOffset)
491   {
492     cerr << "File size for " << _filename << " is too large." << endl;
493     return false;
494   }
495 
496   file = fopen(filename.c_str(), "rb");
497   if (file == 0)
498   {
499     return false;
500   }
501 
502   offset = 0;
503   exists = true;
504 
505   return true;
506 }
507 
508 // Read some data from disk
509 
Read(u64 _offset,void * buffer,size_t length)510 bool DiskFile::Read(u64 _offset, void *buffer, size_t length)
511 {
512   assert(file != 0);
513 
514   if (offset != _offset)
515   {
516     if (_offset > (u64)MaxOffset)
517     {
518       cerr << "Could not read " << (u64)length << " bytes from " << filename << " at offset " << _offset << endl;
519       return false;
520     }
521 
522 
523     if (fseek(file, (OffsetType)_offset, SEEK_SET))
524     {
525       cerr << "Could not read " << (u64)length << " bytes from " << filename << " at offset " << _offset << endl;
526       return false;
527     }
528     offset = _offset;
529   }
530 
531   if (length > MaxLength)
532   {
533     cerr << "Could not read " << (u64)length << " bytes from " << filename << " at offset " << _offset << endl;
534     return false;
535   }
536 
537   if (1 != fread(buffer, (LengthType)length, 1, file))
538   {
539     cerr << "Could not read " << (u64)length << " bytes from " << filename << " at offset " << _offset << endl;
540     return false;
541   }
542 
543   offset += length;
544 
545   return true;
546 }
547 
Close(void)548 void DiskFile::Close(void)
549 {
550   if (file != 0)
551   {
552     fclose(file);
553     file = 0;
554   }
555 }
556 
557 // Attempt to get the full pathname of the file
GetCanonicalPathname(string filename)558 string DiskFile::GetCanonicalPathname(string filename)
559 {
560   // Is the supplied path already an absolute one
561   if (filename.size() == 0 || filename[0] == '/')
562     return filename;
563 
564   // Get the current directory
565   char curdir[1000];
566   if (0 == getcwd(curdir, sizeof(curdir)))
567   {
568     return filename;
569   }
570 
571 
572   // Allocate a work buffer and copy the resulting full path into it.
573   char *work = new char[strlen(curdir) + filename.size() + 2];
574   strcpy(work, curdir);
575   if (work[strlen(work)-1] != '/')
576     strcat(work, "/");
577   strcat(work, filename.c_str());
578 
579   char *in = work;
580   char *out = work;
581 
582   while (*in)
583   {
584     if (*in == '/')
585     {
586       if (in[1] == '.' && in[2] == '/')
587       {
588         // skip the input past /./
589         in += 2;
590       }
591       else if (in[1] == '.' && in[2] == '.' && in[3] == '/')
592       {
593         // backtrack the output if /../ was found on the input
594         in += 3;
595         if (out > work)
596         {
597           do
598           {
599             out--;
600           } while (out > work && *out != '/');
601         }
602       }
603       else
604       {
605         *out++ = *in++;
606       }
607     }
608     else
609     {
610       *out++ = *in++;
611     }
612   }
613   *out = 0;
614 
615   string result = work;
616   delete [] work;
617 
618   return result;
619 }
620 
FindFiles(string path,string wildcard)621 list<string>* DiskFile::FindFiles(string path, string wildcard)
622 {
623   list<string> *matches = new list<string>;
624 
625   string::size_type where;
626 
627   if ((where = wildcard.find_first_of('*')) != string::npos ||
628       (where = wildcard.find_first_of('?')) != string::npos)
629   {
630     string front = wildcard.substr(0, where);
631     bool multiple = wildcard[where] == '*';
632     string back = wildcard.substr(where+1);
633 
634     DIR *dirp = opendir(path.c_str());
635     if (dirp != 0)
636     {
637       struct dirent *d;
638       while ((d = readdir(dirp)) != 0)
639       {
640         string name = d->d_name;
641 
642         if (name == "." || name == "..")
643           continue;
644 
645         if (multiple)
646         {
647           if (name.size() >= wildcard.size() &&
648               name.substr(0, where) == front &&
649               name.substr(name.size()-back.size()) == back)
650           {
651             matches->push_back(path + name);
652           }
653         }
654         else
655         {
656           if (name.size() == wildcard.size())
657           {
658             string::const_iterator pw = wildcard.begin();
659             string::const_iterator pn = name.begin();
660             while (pw != wildcard.end())
661             {
662               if (*pw != '?' && *pw != *pn)
663                 break;
664               ++pw;
665               ++pn;
666             }
667 
668             if (pw == wildcard.end())
669             {
670               matches->push_back(path + name);
671             }
672           }
673         }
674 
675       }
676       closedir(dirp);
677     }
678   }
679   else
680   {
681     struct stat st;
682     string fn = path + wildcard;
683     if (stat(fn.c_str(), &st) == 0)
684     {
685       matches->push_back(path + wildcard);
686     }
687   }
688 
689   return matches;
690 }
691 
692 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
693 #endif
694 
695 
696 
697 
698 
699 
700 
701 
702 
703 
704 
705 
706 
707 
708 
709 
710 
711 
712 
713 
714 
715 
716 
Open(void)717 bool DiskFile::Open(void)
718 {
719   string _filename = filename;
720 
721   return Open(_filename);
722 }
723 
Open(string _filename)724 bool DiskFile::Open(string _filename)
725 {
726   return Open(_filename, GetFileSize(_filename));
727 }
728 
729 
730 
731 
732 
733 
734 
735 
736 
737 // Delete the file
738 
Delete(void)739 bool DiskFile::Delete(void)
740 {
741 #ifdef WIN32
742   assert(hFile == INVALID_HANDLE_VALUE);
743 #else
744   assert(file == 0);
745 #endif
746 
747   if (filename.size() > 0 && 0 == unlink(filename.c_str()))
748   {
749     return true;
750   }
751   else
752   {
753     cerr << "Cannot delete " << filename << endl;
754 
755     return false;
756   }
757 }
758 
759 
760 
761 
762 
763 
764 
765 
766 
767 //string DiskFile::GetPathFromFilename(string filename)
768 //{
769 //  string::size_type where;
770 //
771 //  if (string::npos != (where = filename.find_last_of('/')) ||
772 //      string::npos != (where = filename.find_last_of('\\')))
773 //  {
774 //    return filename.substr(0, where+1);
775 //  }
776 //  else
777 //  {
778 //    return "." PATHSEP;
779 //  }
780 //}
781 
SplitFilename(string filename,string & path,string & name)782 void DiskFile::SplitFilename(string filename, string &path, string &name)
783 {
784   string::size_type where;
785 
786   if (string::npos != (where = filename.find_last_of('/')) ||
787       string::npos != (where = filename.find_last_of('\\')))
788   {
789     path = filename.substr(0, where+1);
790     name = filename.substr(where+1);
791   }
792   else
793   {
794     path = "." PATHSEP;
795     name = filename;
796   }
797 }
798 
FileExists(string filename)799 bool DiskFile::FileExists(string filename)
800 {
801   struct stat st;
802   return ((0 == stat(filename.c_str(), &st)) && (0 != (st.st_mode & S_IFREG)));
803 }
804 
GetFileSize(string filename)805 u64 DiskFile::GetFileSize(string filename)
806 {
807   struct stat st;
808   if ((0 == stat(filename.c_str(), &st)) && (0 != (st.st_mode & S_IFREG)))
809   {
810     return st.st_size;
811   }
812   else
813   {
814     return 0;
815   }
816 }
817 
818 
819 
820 // Take a filename from a PAR2 file and replace any characters
821 // which would be illegal for a file on disk
TranslateFilename(string filename)822 string DiskFile::TranslateFilename(string filename)
823 {
824   string result;
825 
826   string::iterator p = filename.begin();
827   while (p != filename.end())
828   {
829     unsigned char ch = *p;
830 
831     bool ok = true;
832 #ifdef WIN32
833     if (ch < 32)
834     {
835       ok = false;
836     }
837     else
838     {
839       switch (ch)
840       {
841       case '"':
842       case '*':
843       case '/':
844       case ':':
845       case '<':
846       case '>':
847       case '?':
848       case '\\':
849       case '|':
850         ok = false;
851       }
852     }
853 #else
854     if (ch < 32)
855     {
856       ok = false;
857     }
858     else
859     {
860       switch (ch)
861       {
862       case '/':
863         ok = false;
864       }
865     }
866 #endif
867 
868 
869     if (ok)
870     {
871       result += ch;
872     }
873     else
874     {
875       // convert problem characters to hex
876       result += ((ch >> 4) < 10) ? (ch >> 4) + '0' : (ch >> 4) + 'A'-10;
877       result += ((ch & 0xf) < 10) ? (ch & 0xf) + '0' : (ch & 0xf) + 'A'-10;
878     }
879 
880     ++p;
881   }
882 
883   return result;
884 }
885 
Rename(void)886 bool DiskFile::Rename(void)
887 {
888   char newname[_MAX_PATH+1];
889   u32 index = 0;
890 
891   struct stat st;
892 
893   do
894   {
895     int length = snprintf(newname, _MAX_PATH, "%s.%d", filename.c_str(), ++index);
896     if (length < 0 || length >= _MAX_PATH)
897     {
898       cerr << filename << " cannot be renamed." << endl;
899       return false;
900     }
901     newname[length] = 0;
902   } while (stat(newname, &st) == 0);
903 
904   return Rename(newname);
905 }
906 
Rename(string _filename)907 bool DiskFile::Rename(string _filename)
908 {
909 #ifdef WIN32
910   assert(hFile == INVALID_HANDLE_VALUE);
911 #else
912   assert(file == 0);
913 #endif
914 
915   if (::rename(filename.c_str(), _filename.c_str()) == 0)
916   {
917     filename = _filename;
918 
919     return true;
920   }
921   else
922   {
923     cerr << filename << " cannot be renamed to " << _filename << endl;
924 
925     return false;
926   }
927 }
928 
929 #ifdef WIN32
ErrorMessage(DWORD error)930 string DiskFile::ErrorMessage(DWORD error)
931 {
932   string result;
933 
934   LPVOID lpMsgBuf;
935   if (::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
936                        NULL,
937                        error,
938                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
939                        (LPSTR)&lpMsgBuf,
940                        0,
941                        NULL))
942   {
943     result = (char*)lpMsgBuf;
944     LocalFree(lpMsgBuf);
945   }
946   else
947   {
948     char message[40];
949     _snprintf(message, sizeof(message), "Unknown error code (%d)", error);
950     result = message;
951   }
952 
953   return result;
954 }
955 #endif
956 
DiskFileMap(void)957 DiskFileMap::DiskFileMap(void)
958 {
959 }
960 
~DiskFileMap(void)961 DiskFileMap::~DiskFileMap(void)
962 {
963   map<string, DiskFile*>::iterator fi = diskfilemap.begin();
964   while (fi != diskfilemap.end())
965   {
966     delete (*fi).second;
967 
968     ++fi;
969   }
970 }
971 
Insert(DiskFile * diskfile)972 bool DiskFileMap::Insert(DiskFile *diskfile)
973 {
974   string filename = diskfile->FileName();
975   assert(filename.length() != 0);
976 
977   pair<map<string,DiskFile*>::const_iterator,bool> location = diskfilemap.insert(pair<string,DiskFile*>(filename, diskfile));
978 
979   return location.second;
980 }
981 
Remove(DiskFile * diskfile)982 void DiskFileMap::Remove(DiskFile *diskfile)
983 {
984   string filename = diskfile->FileName();
985   assert(filename.length() != 0);
986 
987   diskfilemap.erase(filename);
988 }
989 
Find(string filename) const990 DiskFile* DiskFileMap::Find(string filename) const
991 {
992   assert(filename.length() != 0);
993 
994   map<string, DiskFile*>::const_iterator f = diskfilemap.find(filename);
995 
996   return (f != diskfilemap.end()) ?  f->second : 0;
997 }
998