PackFile.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #include "PackFile.h"
  2. #include "FileService.h"
  3. #include "FilesTree.h"
  4. #include "DataFile.h"
  5. #include "Archivator.h"
  6. #include "..\..\common_h\data_swizzle.h"
  7. const char PackFile::id[8] = {'S','t','o','r','m','P','k','x'};
  8. const char PackFile::ver[4] = {'2','.','1','0'};
  9. PackFile::PackFile(const char * path, const char * _cppFileName, long _cppFileLine) : data(_FL_, 1)
  10. {
  11. const char * name = string::GetFileName(path);
  12. for(long i = 0; i < sizeof(fileName); i++, name++)
  13. {
  14. fileName[i] = *name;
  15. if(*name == 0) break;
  16. }
  17. fileName[sizeof(fileName) - 1] = 0;
  18. refCounter = 1;
  19. #ifndef STOP_DEBUG
  20. cppFileName = _cppFileName;
  21. cppFileLine = _cppFileLine;
  22. #endif
  23. }
  24. PackFile::~PackFile()
  25. {
  26. }
  27. //Загрузить файл в память
  28. bool PackFile::Load(IDataFile * df)
  29. {
  30. //Проверяем размер
  31. dword size = df->Size();
  32. if(size < sizeof(Header) + sizeof(Element) + 1)
  33. {
  34. labelErrorFile:
  35. #ifndef STOP_DEBUG
  36. api->Error("FileService error: can't read pack file \"%s\", invalidate file content (file: %s, line: %i -> LoadPak)", fileName, cppFileName, cppFileLine);
  37. #endif
  38. return false;
  39. }
  40. //Загружаем файл
  41. data.AddElements(size);
  42. if(df->Read(data.GetBuffer(), size) != size)
  43. {
  44. #ifndef STOP_DEBUG
  45. api->Error("FileService error: can't read pack file \"%s\", io error (file: %s, line: %i -> LoadPak)", fileName, cppFileName, cppFileLine);
  46. #endif
  47. return false;
  48. }
  49. const byte * infoAddress = data.GetBuffer();
  50. Header & header = *(Header *)infoAddress;
  51. //Проверяем идентификатор и версию
  52. Assert(ARRSIZE(header.id) == ARRSIZE(id));
  53. for(dword i = 0; i < ARRSIZE(header.id); i++)
  54. {
  55. if(header.id[i] != id[i])
  56. {
  57. goto labelErrorFile;
  58. }
  59. }
  60. Assert(ARRSIZE(header.version) == ARRSIZE(ver));
  61. for(dword i = 0; i < ARRSIZE(header.version); i++)
  62. {
  63. if(header.version[i] != ver[i])
  64. {
  65. goto labelErrorFile;
  66. }
  67. }
  68. //Глобальные параметры файла
  69. if(!__SwizzleDetect())
  70. {
  71. __RefDataSwizzler(header.filesCount);
  72. __RefDataSwizzler(header.entryMask);
  73. }
  74. if(sizeof(Header) + header.entryMask*sizeof(Element *) + header.filesCount*sizeof(Element) > size)
  75. {
  76. goto labelErrorFile;
  77. }
  78. if(!__SwizzleDetect())
  79. {
  80. for(dword i = 0; i <= header.entryMask; i++)
  81. {
  82. __RefDataSwizzler(header.entry[i]);
  83. }
  84. }
  85. Element * elements = (Element *)&data[sizeof(Header) + header.entryMask*sizeof(Element *)];
  86. if((byte *)(elements + header.filesCount) >= infoAddress + size)
  87. {
  88. goto labelErrorFile;
  89. }
  90. //Входная таблица
  91. for(dword i = 0; i <= header.entryMask; i++)
  92. {
  93. if(header.entry[i])
  94. {
  95. Element * ptr = (Element *)(infoAddress + ((byte *)header.entry[i] - (byte *)0));
  96. if(ptr < elements || ptr > elements + header.filesCount)
  97. {
  98. goto labelErrorFile;
  99. }
  100. header.entry[i] = ptr;
  101. }
  102. }
  103. //Таблица файловых дескрипторов
  104. if(!__SwizzleDetect())
  105. {
  106. for(dword i = 0; i < header.filesCount; i++)
  107. {
  108. __RefDataSwizzler(elements[i].name);
  109. __RefDataSwizzler(elements[i].hash);
  110. __RefDataSwizzler(elements[i].len);
  111. __RefDataSwizzler(elements[i].data);
  112. __RefDataSwizzler(elements[i].fileSize);
  113. __RefDataSwizzler(elements[i].packSize);
  114. __RefDataSwizzler(elements[i].next);
  115. }
  116. }
  117. for(dword i = 0; i < header.filesCount; i++)
  118. {
  119. Element & el = elements[i];
  120. el.name = (const char *)(infoAddress + ((byte *)el.name - (byte *)0));
  121. if((byte *)el.name < infoAddress || (byte *)el.name >= infoAddress + size)
  122. {
  123. goto labelErrorFile;
  124. }
  125. el.data = (const byte *)(infoAddress + ((byte *)el.data - (byte *)0));
  126. if((byte *)el.data < (byte *)(elements + header.filesCount) || (byte *)el.data >= infoAddress + size)
  127. {
  128. goto labelErrorFile;
  129. }
  130. if(el.next)
  131. {
  132. el.next = (Element *)(infoAddress + ((byte *)el.next - (byte *)0));
  133. if(el.next < elements || el.next > elements + header.filesCount)
  134. {
  135. goto labelErrorFile;
  136. }
  137. }
  138. }
  139. return true;
  140. }
  141. //Увеличить счётчик ссылок
  142. void PackFile::AddRefCount()
  143. {
  144. refCounter++;
  145. }
  146. //Удалить объект, закончив отражать путь
  147. void PackFile::ErrorRelease()
  148. {
  149. #ifndef STOP_DEBUG
  150. api->Error("FileService error: IPackFile file \"%s\" not release (file: %s, line %i)", fileName, cppFileName, cppFileLine);
  151. #endif
  152. delete this;
  153. }
  154. //Удалить объект
  155. void PackFile::Release()
  156. {
  157. SingleExClassThread(FileService::object)
  158. refCounter--;
  159. if(refCounter > 0) return;
  160. //Удаляем себя
  161. FileService::object->DeletePackFile(this);
  162. delete this;
  163. }
  164. //Получить количество файлов
  165. dword PackFile::Count() const
  166. {
  167. Header & hdr = (Header &)data[0];
  168. return hdr.filesCount;
  169. }
  170. //Получить путь до файла внутри пака
  171. const char * PackFile::LocalPath(dword index) const
  172. {
  173. Header & hdr = (Header &)data[0];
  174. Element * elements = (Element *)&data[sizeof(Header) + hdr.entryMask*sizeof(Element *)];
  175. Assert(index < hdr.filesCount);
  176. return elements[index].name;
  177. }
  178. //Получить полный путь до файла
  179. const char * PackFile::FullPath(dword index) const
  180. {
  181. return LocalPath(index);
  182. }
  183. //Получить размер пак-файла
  184. dword PackFile::Size() const
  185. {
  186. return data.GetDataSize();
  187. }
  188. //Добавить все имена файлов
  189. void PackFile::CollectFiles(array<const char *> & names)
  190. {
  191. Header & hdr = (Header &)data[0];
  192. Element * elements = (Element *)&data[sizeof(Header) + hdr.entryMask*sizeof(Element *)];
  193. names.Reserve(names.Size() + hdr.filesCount);
  194. for(dword i = 0; i < hdr.filesCount; i++)
  195. {
  196. names.Add(elements[i].name);
  197. }
  198. }
  199. #ifndef _XBOX
  200. //Сохранить файлы в паке
  201. bool PackFile::SaveToPack(const char * path, PackArchivator & compressor)
  202. {
  203. Assert(!__SwizzleDetect());
  204. dword filesCount = compressor.GetFilesCount();
  205. if(!filesCount)
  206. {
  207. return false;
  208. }
  209. Assert(compressor.GetDataSize() > 0);
  210. //Вычисляем требуемый размер хэша
  211. dword hashSize = (filesCount < 80) ? filesCount*2 : filesCount;
  212. //Находим маску
  213. dword hashMask = 0x80000000;
  214. while((hashMask & hashSize) == 0)
  215. {
  216. hashMask >>= 1;
  217. Assert(hashMask != 0);
  218. }
  219. hashSize = hashMask;
  220. if(hashSize < 4) hashSize = 4;
  221. if(hashSize > 1024) hashSize = 1024;
  222. hashMask = hashSize - 1;
  223. //Подготавливаем описывающую структуру
  224. dword namesSize = compressor.GetNamesSize();
  225. array<byte> info(_FL_);
  226. dword infoSize = sizeof(Header) + hashMask*sizeof(Element *) + sizeof(Element)*filesCount + namesSize;
  227. info.AddElements(infoSize);
  228. byte * infoAddress = info.GetBuffer();
  229. Assert(info.GetDataSize() == infoSize);
  230. memset(infoAddress, 0, infoSize);
  231. Header & hdr = (Header &)info[0];
  232. Element * elements = (Element *)&info[sizeof(Header) + hashMask*sizeof(Element *)];
  233. char * names = (char *)&elements[filesCount];
  234. Assert(ARRSIZE(hdr.id) == ARRSIZE(id));
  235. for(dword i = 0; i < ARRSIZE(hdr.id); i++) hdr.id[i] = id[i];
  236. Assert(ARRSIZE(hdr.version) == ARRSIZE(ver));
  237. for(dword i = 0; i < ARRSIZE(hdr.version); i++) hdr.version[i] = ver[i];
  238. hdr.filesCount = filesCount;
  239. hdr.entryMask = hashMask;
  240. for(dword i = 0; i < filesCount; i++)
  241. {
  242. Element & el = elements[i];
  243. //Имя
  244. el.name = names;
  245. const char * n = compressor.GetFileName(i, el.len, el.hash);
  246. el.next = null;
  247. memcpy(names, n, el.len + 1);
  248. names += el.len + 1;
  249. Element ** chEl = &hdr.entry[el.hash & hdr.entryMask];
  250. while(*chEl != null) chEl = &(*chEl)->next;
  251. *chEl = &el;
  252. //Данные
  253. el.data = (byte *)0 + infoSize + compressor.GetFileOffset(i);
  254. el.fileSize = compressor.GetFileSize(i);
  255. el.packSize = compressor.GetFileCompressedSize(i);
  256. }
  257. //Приводим в сохраняемый формат с порядком байт под xbox
  258. __RefDataSwizzler(hdr.filesCount);
  259. __RefDataSwizzler(hdr.entryMask);
  260. for(dword i = 0; i < hashSize; i++)
  261. {
  262. if(hdr.entry[i])
  263. {
  264. hdr.entry[i] = (Element *)((byte *)0 + ((byte *)hdr.entry[i] - infoAddress));
  265. }
  266. __RefDataSwizzler(hdr.entry[i]);
  267. }
  268. for(dword i = 0; i < filesCount; i++)
  269. {
  270. Element & el = elements[i];
  271. Assert(el.name);
  272. el.name = (const char *)((byte *)0 + ((byte *)el.name - infoAddress));
  273. __RefDataSwizzler(el.name);
  274. __RefDataSwizzler(el.hash);
  275. __RefDataSwizzler(el.len);
  276. __RefDataSwizzler(el.data);
  277. __RefDataSwizzler(el.fileSize);
  278. __RefDataSwizzler(el.packSize);
  279. if(el.next)
  280. {
  281. el.next = (Element *)((byte *)0 + ((byte *)el.next - infoAddress));
  282. }
  283. __RefDataSwizzler(el.next);
  284. }
  285. //Сохраняем файл
  286. IFile * file = FileService::object->OpenFile(path, file_create_always, _FL_);
  287. if(!file)
  288. {
  289. return false;
  290. }
  291. bool isError = (file->Write(infoAddress, infoSize) != infoSize);
  292. isError |= (file->Write(compressor.GetDataBuffer(), compressor.GetDataSize()) != compressor.GetDataSize());
  293. file->Release();
  294. if(isError)
  295. {
  296. FileService::object->Delete(path);
  297. return false;
  298. }
  299. return true;
  300. }
  301. #endif