Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

Pod.cpp

Go to the documentation of this file.
00001 /*
00002  * Pod.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003-2005 Chris Wallace
00007  *
00008  * Fly! Legacy is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  * Fly! Legacy is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  *   along with Fly! Legacy; if not, write to the Free Software
00020  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00028 #ifdef _MSC_VER
00029 #pragma warning (disable:4189)    // Local variable initialized but not used
00030 #pragma warning (disable:4710)    // Function not inlined
00031 #endif
00032 
00033 #include <stdarg.h>
00034 #include <string.h>
00035 #include "../Include/Pod.h"
00036 #include "../Include/Utility.h"
00037 #include "../Include/Globals.h"
00038 #include "../Include/Endian.h"
00039 
00040 using namespace std;
00041 
00042 
00043 //
00044 // Local function to convert string to upper-case
00045 //
00046 static void strupper (char *s)
00047 {
00048   for (unsigned int i=0; i<strlen(s); i++) s[i] = toupper(s[i]);
00049 }
00050 
00051 //
00052 // Local functions for extracting typical data types from stdio FILE*
00053 //
00054 static unsigned int freadBigUnsignedInt (FILE* f)
00055 {
00056   unsigned int rc;
00057   fread ((char *)&rc, sizeof(unsigned int), 1, f);
00058   return BigEndian (rc);
00059 }
00060 
00061 static unsigned int freadLittleUnsignedInt (FILE* f)
00062 {
00063   unsigned int rc;
00064   fread ((char *)&rc, sizeof(unsigned int), 1, f);
00065   return LittleEndian (rc);
00066 }
00067 
00073 static void plog (PFS *pPfs, const char* fmt, ...)
00074 {
00075   if (pPfs->log != NULL) {
00076     va_list argp;
00077     va_start(argp, fmt);
00078     pPfs->log->Write (fmt, argp);
00079     va_end(argp);
00080   }  
00081 }
00082 
00084 //
00085 // Standard C pod filesystem implementation
00086 //
00087 
00088 //
00089 // Example:
00090 //
00091 // PFS pfs;
00092 // pinit (&pfs, "C:\\Fly! II", false);
00093 // paddpodfolder ("Aircraft");
00094 // paddpodfolder ("System");
00095 // padddiskfolder ("World");
00096 // PFSFILE* f = popen ("World\\Flyhawk.svh");
00097 //...
00098 //
00099 
00109 void pinit (PFS* pPfs, const char* root, bool searchPodFilesFirst)
00110 {
00111   strcpy (pPfs->root, root);
00112   pPfs->searchPodFilesFirst = searchPodFilesFirst;
00113 
00114   // Get INI setting and open log if necessary
00115   pPfs->log = NULL;
00116   int i = 0;
00117   GetIniVar ("Logs", "logPodFilesystem", &i);
00118   if (i != 0) {
00119     pPfs->log = new CLogFile ("Logs\\PodFilesystem.log", "w");
00120   }
00121 
00122 #ifdef POD_PERFORMANCE_METRICS
00123   // Initialize performance metrics
00124   pPfs->popenSuccess = pPfs->popenFailure = 0;
00125   pPfs->popenSuccessTotalTime.QuadPart = 0;
00126   pPfs->popenFailureTotalTime.QuadPart = 0;
00127 #endif
00128 
00129   plog (pPfs, "Initialization complete");
00130 }
00131 
00137 void pshutdown (PFS* pPfs)
00138 {
00139   plog (pPfs, "Shutting down...");
00140 
00141   // Deallocate all entries in the pod list
00142   map<string,PFSPOD*>::iterator iPod;
00143   for (iPod=pPfs->podList.begin(); iPod!=pPfs->podList.end(); iPod++) {
00144     PFSPOD *pPod = iPod->second;
00145     if (pPod->file != NULL) fclose (pPod->file);
00146     delete pPod;
00147   }
00148   
00149   // Delete all entries in the pod file list
00150   multimap<string,PFSPODFILE*>::iterator i;
00151   for (i=pPfs->podFileList.begin(); i!=pPfs->podFileList.end(); i++) {
00152     PFSPODFILE *pf = i->second;
00153     delete pf;
00154   }
00155 
00156   plog (pPfs, "Shutdown complete");
00157   
00158   // Close log file
00159   if (pPfs->log != NULL) delete pPfs->log;
00160 }
00161 
00162 static bool paddpodfile (PFS *pPfs, PFSPODFILE *p)
00163 {
00164   bool rc = true;
00165 
00166   // Create pairing of filename with PFSPODFILE*
00167   pair<string,PFSPODFILE*>  pr;
00168   pr.first = p->name;
00169   pr.second = p;
00170   pPfs->podFileList.insert(pr);
00171 
00172   return rc;
00173 }
00174 
00175 static void padddiskfile (PFS *pPfs, string filename)
00176 {
00177   pPfs->diskFileList.insert(filename);
00178 }
00179     
00185 static void pmountepd (PFS *pPfs, PFSPOD* pPod)
00186 {
00187   // Local copy of the POD's FILE* for convenience
00188   FILE* f = pPod->file;
00189 
00190   // Read EPD header
00191   char volume[EPD_VOLUME_LENGTH+1];
00192   fread (volume, 1, EPD_VOLUME_LENGTH, f);
00193   unsigned int nEntries = freadLittleUnsignedInt (f);
00194 
00195   // Skip version number
00196   freadLittleUnsignedInt (f);
00197   
00198   pPod->checksum = freadLittleUnsignedInt (f);
00199 
00200   // Read EPD directory and add PFSPODFILE structs to the POD file list
00201   for (unsigned int i=0; i<nEntries; i++) {
00202     // Instantiate new PFSPODFILE struct
00203     PFSPODFILE* pFile = new PFSPODFILE;
00204 
00205     // Populate struct with EPD directory entry fields
00206     pFile->pod = pPod;
00207     fread (pFile->name, 1, EPD_FILENAME_LENGTH, f);
00208     pFile->size = freadBigUnsignedInt (f);
00209     pFile->offset = freadBigUnsignedInt (f);
00210     pFile->timestamp = freadBigUnsignedInt (f);
00211     pFile->checksum = freadBigUnsignedInt (f);
00212 
00213     // EPD files do not support mount priority, so use default of 1000
00214     pFile->priority = 1000;
00215 
00216     if (!paddpodfile (pPfs, pFile)) {
00217       // Pod file was rejected; delete it
00218       delete pFile;
00219     }
00220   }
00221 }
00222 
00223 static void pmountpod2 (PFS *pPfs, PFSPOD* pPod)
00224 {
00225   int i, j;
00226   
00227   // Local copy of the POD's FILE* for convenience
00228   FILE* f = pPod->file;
00229 
00230   // Read POD2 header
00231   pPod->checksum = freadLittleUnsignedInt (f);
00232   char volume[POD_VOLUME_LENGTH+1];
00233   fread (volume, POD_VOLUME_LENGTH, 1, f);
00234   unsigned int nEntries = freadLittleUnsignedInt (f);
00235   pPod->nAuditEntries = freadLittleUnsignedInt (f);
00236   pPod->revision = 0;
00237   pPod->priority = 1000;
00238 
00239   // Calculate starting offset of filename string table
00240   unsigned int offsetStringTable = (POD_VOLUME_LENGTH
00241     + (4 * sizeof(unsigned int))
00242     + (nEntries * 20));
00243 
00246   
00247   // Read POD2 directory, and add PFSPODFILE structs to POD file list
00248   for (i=0; i<(int)nEntries; i++) {
00249     // Instantiate new PFSPODFILE struct
00250     PFSPODFILE* pFile = new PFSPODFILE;
00251 
00252     pFile->pod = pPod;
00253     unsigned int offsetFilename = freadLittleUnsignedInt (f);
00254     pFile->size = freadLittleUnsignedInt (f);
00255     pFile->offset = freadLittleUnsignedInt (f);
00256     pFile->timestamp = freadLittleUnsignedInt (f);
00257     pFile->checksum = freadLittleUnsignedInt (f);
00258 
00259     // Mount priority is not supported by the POD2 format, use default of 1000
00260     pFile->priority = 1000;
00261 
00262     // Reposition file pointer to location in string table of the filename,
00263     //   read the filename then reposition back to the next directory entry
00264     long pos = ftell (f);
00265     fseek (f, offsetStringTable + offsetFilename, SEEK_SET);
00266     char c;
00267     for (j=0; j<POD_FILENAME_LENGTH; j++) {
00268       fread (&c, 1, 1, f);
00269       if (c == '\0') break;
00270       pFile->name[j] = c;
00271     }
00272     pFile->name[j] = '\0';
00273     fseek (f, pos, SEEK_SET);
00274 
00275     if (!paddpodfile (pPfs, pFile)) {
00276       // Pod file was rejected; delete it
00277       delete pFile;
00278     }
00279   }
00280 }
00281 
00282 static void pmountpod3 (PFS *pPfs, PFSPOD* pPod)
00283 {
00284   int i, j;
00285   
00286   // Local copy of the POD's FILE* for convenience
00287   FILE* f = pPod->file;
00288 
00289   pPod->checksum = freadLittleUnsignedInt (f);
00290   char volume[POD_VOLUME_LENGTH+1];
00291   fread (volume, POD_VOLUME_LENGTH, 1, f);
00292   unsigned int nEntries = freadLittleUnsignedInt (f);
00293   pPod->nAuditEntries = freadLittleUnsignedInt (f);
00294   pPod->revision = freadLittleUnsignedInt (f);
00295   pPod->priority = freadLittleUnsignedInt (f);
00296   char author[POD_AUTHOR_LENGTH+1];
00297   fread (author, POD_AUTHOR_LENGTH, 1, f);
00298   char copyright[POD_COPYRIGHT_LENGTH+1];
00299   fread (copyright, POD_COPYRIGHT_LENGTH, 1, f);
00300   unsigned int offsetDirectory = freadLittleUnsignedInt (f);
00301 
00302   // The following POD3 header fields are ignored:
00303   //    checksum
00304   //    string table size
00305   //    dependency
00306   //    unknown4
00307   //    unknown5
00308   
00309   // Calculate starting offset of filename string table
00310   unsigned int offsetStringTable = offsetDirectory + (nEntries * 20);
00311 
00312   // Reposition file pointer to start of POD directory
00313   fseek (f, offsetDirectory, SEEK_SET);
00314 
00315   for (i=0; i<(int)nEntries; i++) {
00316     // Instantiate new PFSPODFILE struct
00317     PFSPODFILE* pFile = new PFSPODFILE;
00318 
00319     pFile->pod = pPod;
00320     unsigned int offsetFilename = freadLittleUnsignedInt (f);
00321     pFile->size = freadLittleUnsignedInt (f);
00322     pFile->offset = freadLittleUnsignedInt (f);
00323     pFile->priority = pPod->priority;
00324     pFile->timestamp = freadLittleUnsignedInt (f);
00325     pFile->checksum  = freadLittleUnsignedInt (f);
00326 
00327     // Reposition file pointer to location in string table of the filename,
00328     //   read the filename then reposition back to the next directory entry
00329     long pos = ftell (f);
00330     fseek (f, offsetStringTable + offsetFilename, SEEK_SET);
00331     strcpy (pFile->name, "");
00332     char c;
00333     for (j=0; j<POD_FILENAME_LENGTH; j++) {
00334       fread (&c, 1, 1, f);
00335       if (c == '\0') break;
00336       pFile->name[j] = c;
00337     }
00338     pFile->name[j] = '\0';
00339     fseek (f, pos, SEEK_SET);
00340 
00341     if (!paddpodfile (pPfs, pFile)) {
00342       // Pod file was rejected; delete it
00343       delete pFile;
00344     }
00345   }
00346 }
00347 
00348 static PFSPOD* pmount (PFS *pPfs, const char* podname)
00349 {
00350   PFSPOD* pPod = new PFSPOD;
00351   strcpy (pPod->name, podname);
00352   pPod->file = NULL;
00353   pPod->format = PodFormatUnknown;
00354   pPod->refs = 0;
00355 
00356   FILE* f = fopen (podname, "rb");
00357   if (f != NULL) {
00358     pPod->file = f;
00359     
00360     // Read POD type signature
00361     unsigned int signature = freadBigUnsignedInt (f);
00362 
00363     // Set pod format based on signature
00364     switch (signature) {
00365     case PodSignatureEpd:
00366       pPod->format = PodFormatEpd;
00367       pmountepd (pPfs, pPod);
00368       break;
00369 
00370     case PodSignaturePod2:
00371       pPod->format = PodFormatPod2;
00372       pmountpod2 (pPfs, pPod);
00373       break;
00374 
00375     case PodSignaturePod3:
00376       pPod->format = PodFormatPod3;
00377       pmountpod3 (pPfs, pPod);
00378       break;
00379 
00380     default:
00381       pPod->format = PodFormatUnknown;
00382     }
00383   } else {
00384     WARNINGLOG ("pmount : Could not open POD file %s", podname);
00385   }
00386 
00387   return pPod;
00388 }
00389 
00390 void paddpod (PFS *pPfs, const char* filename)
00391 {
00392   plog (pPfs, "Adding POD: %s", filename);
00393 
00394   // Create full POD folder by concatenating root folder with sub-folder name
00395   char podname[PATH_MAX];
00396   strcpy (podname, pPfs->root);
00397   strcat (podname, "\\");
00398   strcat (podname, filename);
00399 
00400   PFSPOD *pPod = pmount (pPfs, podname);
00401   pPfs->podList[filename] = pPod;
00402 }
00403 
00404 void premovepod (PFS *pPfs, const char* filename)
00405 {
00406   plog (pPfs, "Removing POD: %s", filename);
00407 
00408   // Find the entry in the pod list
00409   map<string,PFSPOD*>::iterator iter = pPfs->podList.find(filename);
00410   if (iter != pPfs->podList.end()) {
00411     PFSPOD *pPod = iter->second;
00412     pPfs->podList.erase(filename);
00413     
00414     // Close the associated disk file if it is open
00415     if (pPod->file) {
00416       fclose (pPod->file);
00417     }
00418     
00419     delete pPod;
00420   }
00421 }
00422 
00423 //
00424 // All POD files (with .POD or .EPD extension) in the specified folder are added
00425 //   to the POD filesystem.
00426 //
00427 void paddpodfolder (PFS* pPfs, const char* folder)
00428 {
00429   plog (pPfs, "Adding pod folder: %s", folder);
00430 
00431   // Create full POD folder by concatenating root folder with sub-folder name
00432   char path[PATH_MAX];
00433   strcpy (path, pPfs->root);
00434   strcat (path, "\\");
00435   strcat (path, folder);
00436 
00437   // Iterate over all files in this folder.  Sub-folders are not processed recursively
00438   ulDir* dirp = ulOpenDir (path);
00439   if (dirp != NULL) {
00440     ulDirEnt* dp;
00441     while ( (dp = ulReadDir(dirp)) != NULL )
00442     {
00443       if (dp->d_isdir) {
00444         // This is a sub-folder, ignore it
00445         continue;
00446       } else {
00447         // Check the file extension
00448         char *c = strrchr (dp->d_name, '.');
00449         if ((stricmp (c, ".EPD") == 0) || (stricmp(c, ".POD") == 0)) {
00450           // This is a POD file, create a new PFSPOD instance and add
00451           //   it to the POD list for the filesystem
00452           char podfilename[PATH_MAX];
00453           strcpy (podfilename, path);
00454           strcat (podfilename, "\\");
00455           strcat (podfilename, dp->d_name);
00456 
00458 
00459           PFSPOD *pPod = pmount (pPfs, podfilename);
00460           pPfs->podList[podfilename] = pPod;
00461 
00462           // Update podFileList
00463 //          map<string,PFSPODFILE*>::iterator i;
00464 //          for (i=pPod->fileList.begin(); i!=pPod->fileList.end(); i++) {
00465 //            pPfs->podFileList[i->second->name] = pPod;
00466 //          }
00467         }
00468       }
00469     }
00470     ulCloseDir(dirp);
00471   }
00472 }
00473 
00474 //
00475 // This function adds all non-POD files in the specified folder to the referenced
00476 //   pod filesystem.  Sub-folders are recursively added as well.
00477 //
00478 void padddiskfolder (PFS *pPfs, const char* folder)
00479 {
00480   plog (pPfs, "Adding disk folder: %s", folder);
00481 
00482   // Create full folder name by concatenating root folder with sub-folder name
00483   char path[1024];
00484   strcpy (path, pPfs->root);
00485   strcat (path, "\\");
00486   strcat (path, folder);
00487 
00488   // Iterate over all files in this folder.
00489   ulDir* dirp = ulOpenDir (path);
00490   if (dirp != NULL) {
00491     ulDirEnt* dp;
00492     while ( (dp = ulReadDir(dirp)) != NULL )
00493     {
00494       if (dp->d_isdir) {
00495         // This is a sub-folder, recursively add it
00496         if ((strcmp (dp->d_name, ".") != 0) && (strcmp (dp->d_name, "..") != 0)) {
00497           char subfolder[1024];
00498           strcpy (subfolder, folder);
00499           strcat (subfolder, "\\");
00500           strcat (subfolder, dp->d_name);
00501           padddiskfolder (pPfs, subfolder);
00502         }
00503       } else {
00504         // This is a file, check the extension
00505         char *c = strrchr (dp->d_name, '.');
00506         if ((stricmp (c, ".EPD") == 0) || (stricmp(c, ".POD") == 0)) {
00507           // This is a POD file, ignore it
00508           continue;
00509         } else {
00510           // This is not a POD file, add it to the set of disk files
00511           char filename[1024];
00512           strcpy (filename, folder);
00513           strcat (filename, "\\");
00514           strcat (filename, dp->d_name);
00515           strupper (filename);
00516           
00517           padddiskfile (pPfs, filename);
00518         }
00519       }
00520     }
00521     ulCloseDir(dirp);
00522   }
00523 }
00524 
00525 static PODFILE* findinpod (PFS* pPfs, const char* filename)
00526 {
00527   PODFILE* p = NULL;
00528 
00529   // POD filenames are case-insensitive, and are stored in POD files as all upper case
00530   char f[PATH_MAX];
00531   strcpy (f, filename);
00532   strupper (f);
00533 
00534   PFSPODFILE *pf = NULL;
00535   multimap<string,PFSPODFILE*>::iterator i = pPfs->podFileList.lower_bound(f);
00536   if (i != pPfs->podFileList.end()) {
00537     // There is at least one file with this name in the list of pod files
00538     // Find the highest-priority instance and return it
00539     unsigned long priority = 9999;
00540     while (i != pPfs->podFileList.upper_bound(f)) {
00541       if (i->second->priority < priority) {
00542         char debug[PATH_MAX + 100];
00543         sprintf (debug, "Override %s pri %d with pri %d in %s",
00544                 filename, priority, i->second->priority, i->second->pod->name);
00545         plog (pPfs, debug);
00546         pf = i->second;
00547         priority = pf->priority;
00548       }
00549       i++;
00550     }
00551   }
00552   
00553   if (pf != NULL) {
00554     // Instantiate new PODFILE struct
00555     p = new PODFILE;
00556     
00557     // Link this PODFILE struct to the underlying POD
00558     strcpy (p->filename, filename);
00559     p->source = PODFILE_SOURCE_POD;
00560     p->pPod = pf->pod;
00561     p->pFile = pf->pod->file;
00562     p->offset = pf->offset;
00563     p->pos = pf->offset;
00564     p->size = pf->size;
00565     
00566     // Increment reference counter of containing POD
00567     pf->pod->refs++;
00568   }
00569 
00570   return p;
00571 }
00572 
00573 static PODFILE* findondisk (PFS* pPfs, const char* filename)
00574 {
00575   PODFILE* p = NULL;
00576 
00577   set<string>::iterator i = pPfs->diskFileList.find(filename);
00578   if (i != pPfs->diskFileList.end()) {
00579     // Found it
00580     p = new PODFILE;
00581 
00582     char fullpath[1024];
00583     strcpy (fullpath, pPfs->root);
00584     strcat (fullpath, "\\");
00585     strcat (fullpath, filename);
00586 
00587     // Open the disk file
00588     strcpy (p->filename, filename);
00589     p->pFile = fopen (fullpath, "rb");
00590     p->source = PODFILE_SOURCE_DISK;
00591     p->offset = 0;
00592     p->pos = 0;
00593     fseek (p->pFile, 0, SEEK_END);
00594     p->size = ftell (p->pFile);
00595     rewind (p->pFile);
00596   }
00597 
00598   return p;
00599 }
00600 
00601 
00602 //
00603 // Search all mounted pod files for the given filename
00604 //
00605 // Returns: true if the file exists in a pod, false otherwise
00606 //
00607 static bool existsinpod (PFS *pPfs, const char* filename)
00608 {
00609 //  int i, j;
00610   bool rc = false;
00611   
00612   // Search pod file list for filename
00613   multimap<string,PFSPODFILE*>::iterator i = pPfs->podFileList.find(filename);
00614   rc = (i != pPfs->podFileList.end());
00615   
00616   return rc;
00617 }
00618 
00619 //
00620 // Search the disk file list for the given filename
00621 //
00622 // Returns: true if the file exists on disk, false otherwise
00623 //
00624 static bool existsondisk (PFS *pPfs, const char* filename)
00625 {
00626   bool rc = false;
00627 
00628   // Search for existence of the filename in the disk file list set
00629   set<string>::iterator i = pPfs->diskFileList.find(filename);
00630   rc = (i != pPfs->diskFileList.end());
00631 
00632   return rc;
00633 }
00634 
00635 bool pexists (PFS* pPfs, const char* filename)
00636 {
00637   bool rc = false;
00638 
00639   if (pPfs->searchPodFilesFirst) {
00640     // Search for filename in all mounted PODs.
00641     rc = existsinpod (pPfs, filename);
00642     if (!rc) {
00643       // Not found in a POD, search disk files
00644       rc = existsondisk (pPfs, filename);
00645     }
00646   } else {
00647     // Search for filename in disk files
00648     rc = existsondisk (pPfs, filename);
00649     if (!rc) {
00650       // Not found on disk, search all mounted PODs
00651       rc = existsinpod (pPfs, filename);
00652     }
00653   }
00654 
00655   return rc;
00656 }
00657 
00658 
00659 PODFILE* popen (PFS* pPfs, const char* fname)
00660 {
00661   PODFILE *p = NULL;
00662 
00663 #ifdef POD_PERFORMANCE_METRICS
00664   // Get timestamp
00665   LARGE_INTEGER start, stop, delta;
00666   QueryPerformanceCounter (&start);
00667 #endif
00668 
00669   // Convert filename to uppercase
00670   char filename[PATH_MAX];
00671   strcpy (filename, fname);
00672   strupper (filename);
00673 
00674   if (pPfs->searchPodFilesFirst) {
00675     // Search for filename in all mounted PODs.
00676     p = findinpod (pPfs, filename);
00677     if (p == NULL) {
00678       // Not found in a POD, search disk files
00679       p = findondisk (pPfs, filename);
00680     }
00681   } else {
00682     // Search for filename in disk files
00683     p = findondisk (pPfs, filename);
00684     if (p == NULL) {
00685       // Not found on disk, search all mounted PODs
00686       p = findinpod (pPfs, filename);
00687     }
00688   }
00689 
00690 #ifdef POD_PERFORMANCE_METRICS
00691   // Get final timestamp and update performance metrics (logging time should not
00692   //   be included in measurements
00693   delta.QuadPart = 0;
00694   QueryPerformanceCounter (&stop);
00695   if (stop.QuadPart < start.QuadPart) {
00696 #ifdef HAVE_MAXLONGLONG
00697       delta.QuadPart = stop.QuadPart + (MAXLONGLONG - start.QuadPart);
00698 #else
00699       gtfo ("popen : Performance counter wraparound\n");
00700 #endif // HAVE_MAXLONGLONG
00701   } else {
00702     delta.QuadPart = stop.QuadPart - start.QuadPart;
00703   }
00704 
00705   // Record measured interval against either success or failure metric
00706   if (p == NULL) {
00707     // popen failure
00708     pPfs->popenFailure++;
00709     pPfs->popenFailureTotalTime.QuadPart += delta.QuadPart;
00710   } else {
00711     // popen success
00712     pPfs->popenSuccess++;
00713     pPfs->popenSuccessTotalTime.QuadPart += delta.QuadPart;
00714   }
00715 #endif
00716 
00717   // Generate log if file not found
00718   if (p == NULL) {
00719     plog (pPfs, "popen() : Failed to open %s", filename);
00720   }
00721 
00722   return p;
00723 }
00724 
00725 size_t pread (void* buffer, size_t size, size_t count, PODFILE* f)
00726 {
00727   size_t rc = 0;
00728   if (f) {
00729     switch (f->source) {
00730     case PODFILE_SOURCE_POD:
00731       // Reads to different files within the same POD may be interspersed,
00732       //   so the read pointer must be reset to the next expected byte for
00733       //   this pod file.
00734       fseek (f->pFile, f->pos, SEEK_SET);
00735       rc = fread (buffer, size, count, f->pFile);
00736       f->pos = ftell (f->pFile);
00737       break;
00738 
00739     case PODFILE_SOURCE_DISK:
00740       rc = fread (buffer, size, count, f->pFile);
00741       break;
00742     }
00743   }
00744 
00745   return rc;
00746 }
00747 
00748 int peof (PODFILE* f)
00749 {
00750   int rc = true;
00751   if (f) {
00752 
00753     switch (f->source) {
00754     case PODFILE_SOURCE_POD:
00755       if (f->pos < (f->offset + f->size)) {
00756         rc = false;
00757       }
00758       break;
00759 
00760     case PODFILE_SOURCE_DISK:
00761       rc = feof (f->pFile);
00762       break;
00763     }
00764   }
00765   return rc;
00766 }
00767 
00768 int perror (PODFILE* f)
00769 {
00770   int rc = 0;
00771   if (f) {
00772     switch (f->source) {
00773     case PODFILE_SOURCE_POD:
00774       rc = ferror (f->pFile);
00775       break;
00776 
00777     case PODFILE_SOURCE_DISK:
00778       rc = ferror (f->pFile);
00779       break;
00780     }
00781   }
00782   return rc;
00783 }
00784 
00785 int pgetc (PODFILE* f)
00786 {
00787   int rc = 0;
00788   if (f) {
00789     switch (f->source) {
00790     case PODFILE_SOURCE_POD:
00791       // Reads to different files within the same POD may be interspersed,
00792       //   so the read pointer must be reset to the next expected byte for
00793       //   this pod file.
00794       fseek (f->pFile, f->pos, SEEK_SET);
00795       rc = fgetc (f->pFile);
00796       f->pos = ftell (f->pFile);
00797       break;
00798 
00799     case PODFILE_SOURCE_DISK:
00800       rc = fgetc (f->pFile);
00801       break;
00802     }
00803   }
00804 
00805   return rc;
00806 }
00807 
00808 char* pgets (char* s, int n, PODFILE* f)
00809 {
00810   char* rc = NULL;
00811   if (f) {
00812     switch (f->source) {
00813     case PODFILE_SOURCE_POD:
00814       // Reads to different files within the same POD may be interspersed,
00815       //   so the read pointer must be reset to the next expected byte for
00816       //   this pod file.
00817       fseek (f->pFile, f->pos, SEEK_SET);
00818       rc = fgets (s, n, f->pFile);
00819       f->pos = ftell (f->pFile);
00820       break;
00821 
00822     case PODFILE_SOURCE_DISK:
00823       rc = fgets (s, n, f->pFile);
00824       break;
00825     }
00826   }
00827 
00828   return rc;
00829 }
00830 
00831 int pseek (PODFILE* f, long offset, int origin)
00832 {
00833   int rc = 0;
00834   if (f) {
00835     rc = fseek (f->pFile, f->offset + offset, origin);
00836     // Adjust position
00837     f->pos = ftell (f->pFile);
00838   }
00839 
00840   return rc;
00841 }
00842 
00843 long ptell (PODFILE* f)
00844 {
00845   long rc = -1;
00846   if (f) rc = f->pos - f->offset;
00847   return rc;
00848 }
00849 
00850 void prewind (PODFILE* f)
00851 {
00852   if (f) {
00853     switch (f->source) {
00854     case PODFILE_SOURCE_POD:
00855       // Reset the position pointer to the starting offset for this file
00856       //   within the POD
00857       f->pos = f->offset;
00858       fseek (f->pFile, f->pos, SEEK_SET);
00859       break;
00860 
00861     case PODFILE_SOURCE_DISK:
00862       rewind (f->pFile);
00863       break;
00864     }
00865   }
00866 }
00867 
00868 void pclose (PODFILE* f)
00869 {
00870   if (f != NULL) {
00871     switch (f->source) {
00872     case PODFILE_SOURCE_POD:
00873       {
00874         PFSPOD *pPod = f->pPod;
00875         if (pPod != NULL) {
00876           // Decrement pod reference count
00877           if (pPod->refs == 0) {
00878             // Ref count is already zero; generate warning
00879             WARNINGLOG ("pclose : Pod reference count underflow");
00880           } else {
00881             pPod->refs--;
00882           }
00883         }
00884       }
00885       break;
00886 
00887     case PODFILE_SOURCE_DISK:
00888       fclose (f->pFile);
00889       break;
00890     }
00891   }
00892 
00893   delete f;
00894 }
00895 
00896 
00897 //
00898 // Dump the directory of a pod filesystem to disk
00899 //
00900 void pfsdump (PFS *pfs, FILE *f)
00901 {
00902   // Dump out root folders for the filesystem
00903   fprintf (f, "Pod Filesystem Root : %s\n", pfs->root);
00904   fprintf (f, "  Search pod files first : %c\n", pfs->searchPodFilesFirst ? 'Y' : 'N');
00905   fprintf (f, "\n");
00906 
00907   long nTotalFiles = 0;
00908 
00909   // Dump out list of disk files
00910   fprintf (f, "FILE contents:\n");
00911   set<string>::iterator idf;
00912   for (idf=pfs->diskFileList.begin(); idf!=pfs->diskFileList.end(); idf++) {
00913     fprintf (f, "  %-60s\n", idf->c_str());
00914     nTotalFiles++;
00915   }
00916   fprintf (f, "\n");
00917 
00918   // Dump out list of pod files
00919   fprintf (f, "POD contents:\n");
00920   multimap<string,PFSPODFILE*>::iterator ipf;
00921   for (ipf=pfs->podFileList.begin(); ipf!=pfs->podFileList.end(); ipf++) {
00922     PFSPODFILE *pf = ipf->second;
00923     fprintf (f, "  %-40s %d %-30s\n", pf->name, pf->priority, pf->pod->name);
00924     nTotalFiles++;
00925   }
00926   fprintf (f, "\n");
00927 
00928   // Dump out list of pods
00929   fprintf (f, "POD list:\n");
00930   map<string,PFSPOD*>::iterator ip;
00931   for (ip=pfs->podList.begin(); ip!=pfs->podList.end(); ip++) {
00932     PFSPOD *pod = ip->second;
00933     fprintf (f, "Filename  : %s\n", pod->name);
00934     fprintf (f, "Format    : 0x%08X\n", pod->format);
00935   }
00936   fprintf (f, "\n");
00937   
00938   // Total number of files
00939   fprintf (f, "Total files in POD Filesystem : %d\n\n", nTotalFiles);
00940 
00941 #ifdef POD_PERFORMANCE_METRICS
00942   // Calculate and display popen() statistics
00943   LARGE_INTEGER perf_freq;
00944   if (!QueryPerformanceFrequency (&perf_freq)) {
00945     gtfo ("CTimeManager : QueryPerformanceFrequency failed");
00946   }
00947   float freq = (float)perf_freq.QuadPart;
00948 
00949   float avgTicks = (float)pfs->popenSuccessTotalTime.QuadPart / (float)pfs->popenSuccess;
00950   float avg = (avgTicks / freq) * 1000.0f;
00951   fprintf (f, "Number of successful popen()  : %d\n", pfs->popenSuccess);
00952   fprintf (f, "Avg. ms per popen() success   : %f\n\n", avg);
00953 
00954   avgTicks = (float)pfs->popenFailureTotalTime.QuadPart / (float)pfs->popenFailure;
00955   avg = (avgTicks / freq) * 1000.0f;
00956   fprintf (f, "Number of failed popen()   : %d\n", pfs->popenFailure);
00957   fprintf (f, "Avg. ms per popen() failure: %f\n\n", avg);
00958 #endif
00959 
00960 /*
00961   // Dump out list of disk files
00962   fprintf (f, "FILE contents:\n");
00963   int nDiskFiles = pfs->fileList.getNumEntities();
00964   for (i=0; i<nDiskFiles; i++) {
00965     PFSDISKFILE *diskfile = (PFSDISKFILE *)pfs->fileList.getEntity (i);
00966     fprintf (f, "  %-60s\n", diskfile->filename);
00967   }
00968   nTotalFiles += nDiskFiles;
00969   fprintf (f, "\n");
00970 
00971   // Dump out list of pods
00972   fprintf (f, "POD list:\n");
00973   int nPods = pfs->podList.getNumEntities();
00974   for (i=0; i<nPods; i++) {
00975     PFSPOD *pod = (PFSPOD *)pfs->podList.getEntity (i);
00976     fprintf (f, "Filename  : %s\n", pod->name);
00977     fprintf (f, "Format    : 0x%08X\n", pod->format);
00978 
00979     int nFiles = pod->fileList.getNumEntities ();
00980     fprintf (f, "Num Files : %d\n", nFiles);
00981     for (j=0; j<nFiles; j++) {
00982       PFSPODFILE *podfile = (PFSPODFILE *) pod->fileList.getEntity (j);
00983       fprintf (f, "  %-60s O/S/P: 0x%08X / 0x%08X / %4d\n",
00984         podfile->name, podfile->offset, podfile->size, podfile->priority);
00985     }
00986     nTotalFiles += nFiles;
00987     fprintf (f, "\n");
00988   }
00989   fprintf (f, "\n");
00990 
00991   // Total number of files
00992   fprintf (f, "Total files in POD Filesystem : %d\n\n", nTotalFiles);
00993 */
00994 }
SourceForge.net Logo Documentation generated by doxygen