1
0

zipread.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #include <precomp.h>
  2. #define REAL_STDIO
  3. #include "zipread.h"
  4. #include <zlib/unzip.h>
  5. #include <bfc/parse/pathparse.h>
  6. #include <api/skin/api_skin.h>
  7. #define UNZIPBUFSIZE 65536
  8. int ZipRead::open(const char *filename, int mode) {
  9. unzFile f=NULL;
  10. int success=0;
  11. if (WASABI_API_SKIN == NULL) return 0;
  12. PathParser pp1(WASABI_API_SKIN->getSkinsPath());
  13. PathParser pp2(filename);
  14. int v;
  15. for (v=0;v<pp1.getNumStrings();v++)
  16. if (!STRCASEEQLSAFE(pp1.enumString(v), pp2.enumString(v))) return 0;
  17. String walName = pp2.enumString(v);
  18. String file;
  19. for (v=v+1;v<pp2.getNumStrings();v++) {
  20. if (!file.isempty()) file.cat(DIRCHARSTR);
  21. file += pp2.enumString(v);
  22. }
  23. // is there a zip file?
  24. String zipName;
  25. Std::fileInfoStruct zipFi;
  26. if(!Std::getFileInfos(zipName=StringPrintf("%s%s.wal",WASABI_API_SKIN->getSkinsPath(),walName.getValue()),&zipFi) &&
  27. !Std::getFileInfos(zipName=StringPrintf("%s%s.wsz",WASABI_API_SKIN->getSkinsPath(),walName.getValue()),&zipFi) &&
  28. !Std::getFileInfos(zipName=StringPrintf("%s%s.zip",WASABI_API_SKIN->getSkinsPath(),walName.getValue()),&zipFi))
  29. return 0; // zip not found
  30. if(zipTmpDir.isempty()) {
  31. char tmpPath[WA_MAX_PATH];
  32. Std::getTempPath(sizeof(tmpPath)-1,tmpPath);
  33. zipTmpDir=StringPrintf("%s_wa3sktmp",tmpPath);
  34. Std::createDirectory(zipTmpDir);
  35. }
  36. // check in cached opened zip dirs
  37. int badcrc=0;
  38. for(int i=0;i<openedZipHandles.getNumItems();i++) {
  39. if(!STRICMP(openedZipHandles[i].name->getValue(), walName)) {
  40. if(!MEMCMP(&openedZipHandles[i].checksum,&zipFi,sizeof(zipFi))) {
  41. // try to find it in the dezipped temp dir
  42. handle=openInTempDir(walName,file);
  43. if(handle) return 1;
  44. else return 0;
  45. } else {
  46. // bad checksum
  47. badcrc=1;
  48. break;
  49. }
  50. }
  51. }
  52. // is the dezipped dir is here?
  53. if(!badcrc) {
  54. StringPrintf tmpf("%s%s%s%s_wa3chksum",zipTmpDir.getValue(),DIRCHARSTR,walName.getValue(),DIRCHARSTR);
  55. FILE *fh=fopen(tmpf,"rb");
  56. if(fh) {
  57. Std::fileInfoStruct tmpFi={0,};
  58. fread(&tmpFi,1,sizeof(tmpFi),fh);
  59. fclose(fh);
  60. if(!MEMCMP(&tmpFi,&zipFi,sizeof(tmpFi))) {
  61. // checksum correct
  62. openedZipEntry ze={new String(walName), new String(zipName)};
  63. ze.checksum=tmpFi;
  64. openedZipHandles.addItem(ze);
  65. handle=openInTempDir(walName,file);
  66. if(handle) return 1;
  67. else return 0;
  68. }
  69. }
  70. }
  71. // not found, so try to find it in a zip file
  72. f = unzOpen(zipName);
  73. if(!f) return 0;
  74. StringPrintf zDir("%s%s%s",zipTmpDir.getValue(),DIRCHARSTR,walName.getValue());
  75. Std::removeDirectory(zDir,1);
  76. // unpack the zip in temp folder
  77. String dirmask;
  78. unzGoToFirstFile(f);
  79. Std::createDirectory(zDir);
  80. do {
  81. char filename[MAX_PATH];
  82. unzGetCurrentFileInfo(f,NULL,filename,sizeof(filename),NULL,0,NULL,0);
  83. if (unzOpenCurrentFile(f) == UNZ_OK) {
  84. int l;
  85. dirmask.printf("%s%s%s",zDir.getValue(),DIRCHARSTR,filename);
  86. if (Std::isDirChar(dirmask.lastChar())) {
  87. // create dir
  88. Std::createDirectory(dirmask);
  89. } else {
  90. // create file
  91. FILE *fp = fopen(dirmask,"wb");
  92. if(!fp) {
  93. String dir=dirmask;
  94. char *p=(char *)Std::filename(dir);
  95. if(p) {
  96. *p=0;
  97. Std::createDirectory(dir);
  98. fp = fopen(dirmask,"wb");
  99. }
  100. }
  101. if (fp) {
  102. do {
  103. MemBlock<char> buf(UNZIPBUFSIZE);
  104. l=unzReadCurrentFile(f,buf.getMemory(),buf.getSizeInBytes());
  105. if (l > 0) fwrite(buf.getMemory(),1,l,fp);
  106. } while (l > 0);
  107. fclose(fp);
  108. success=1;
  109. }
  110. }
  111. if (unzCloseCurrentFile(f) == UNZ_CRCERROR) success=0;
  112. }
  113. } while (unzGoToNextFile(f) == UNZ_OK);
  114. unzClose(f);
  115. // write the checksum file
  116. Std::fileInfoStruct fi;
  117. Std::getFileInfos(zipName, &fi);
  118. FILE *fh=fopen(StringPrintf("%s%s_wa3chksum",zDir.getValue(),DIRCHARSTR),"wt");
  119. fwrite(&fi,1,sizeof(fi),fh);
  120. fclose(fh);
  121. openedZipEntry ze={new String(walName), new String(zipName)};
  122. ze.checksum=fi;
  123. openedZipHandles.addItem(ze);
  124. // try to find it (again) in the dezipped temp dir
  125. handle=openInTempDir(walName,file);
  126. if(handle) return 1;
  127. return 0;
  128. }
  129. FILE *ZipRead::openInTempDir(const char *walName, const char *file) {
  130. StringPrintf tmpf("%s%s%s%s%s",zipTmpDir.getValue(),DIRCHARSTR,walName,DIRCHARSTR,file);
  131. FILE *fh=fopen(tmpf,"rb");
  132. if(fh) return fh;
  133. // okay maybe the file isn't in the root dir of the zip file
  134. fh=fopen(StringPrintf("%s%s%s%s%s%s%s",zipTmpDir.getValue(),DIRCHARSTR,walName,DIRCHARSTR,walName,DIRCHARSTR,file),"rb");
  135. if(fh) return fh;
  136. // definitely not here
  137. return 0;
  138. }
  139. void ZipRead::close() {
  140. fclose(handle);
  141. }
  142. int ZipRead::read(char *buffer, int size) {
  143. return fread(buffer,1,size,handle);
  144. }
  145. int ZipRead::getPos() {
  146. return ftell(handle);
  147. }
  148. int ZipRead::getLength() {
  149. int pos=ftell(handle);
  150. fseek(handle,0,SEEK_END);
  151. int length=ftell(handle);
  152. fseek(handle,pos,SEEK_SET);
  153. return length;
  154. }
  155. using namespace wasabi;
  156. TList<ZipRead::openedZipEntry> ZipRead::openedZipHandles;;