Tool dedicated to isohacking for Xenosaga on Playstation 2
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

543 lines
20 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. using System;
  2. using System.IO;
  3. using System.Diagnostics;
  4. using System.Text;
  5. using Hack.Xenosaga.Common;
  6. using Hack.Tools.TraceLog;
  7. namespace Hack.Xenosaga.Process
  8. {
  9. class Unpack
  10. {
  11. public enum EnumSource { ISO_FILE, PACK_DIR, UNPACK_DIR };
  12. private static BinaryWriter _bw;
  13. private const string _listExtension = ".lst";
  14. private const string _copyright = "Hacked by BahaBulle (c)2016\0";
  15. private const int _sectorSize = 0x800;
  16. private const int _maxSizeFile = 0x40000000;
  17. private struct element
  18. {
  19. public bool isDirectory;
  20. public bool isCompressed;
  21. public byte level;
  22. public string name;
  23. public UInt32 sector;
  24. public UInt32 position;
  25. public UInt32 sizeIn;
  26. public UInt32 sizeOut;
  27. }
  28. #region Private methods
  29. private static int getIdFile(UInt32 position, int indexSize)
  30. {
  31. double d = (position - indexSize) / _maxSizeFile;
  32. return (int)Math.Floor(d) + 1;
  33. }
  34. private static bool readElement(BinaryReader br, ref element e)
  35. {
  36. byte size = br.ReadByte();
  37. if (size == 0)
  38. return false;
  39. if ((size & 0x80) != 0)
  40. {
  41. size -= 2;
  42. e.isDirectory = true;
  43. e.level = br.ReadByte();
  44. e.name = Encoding.ASCII.GetString(br.ReadBytes(size & 0x7F));
  45. }
  46. else
  47. {
  48. size--;
  49. e.isDirectory = false;
  50. e.level = 0;
  51. e.name = Encoding.ASCII.GetString(br.ReadBytes(size & 0x3F));
  52. e.sector = br.ReadUInt16() + (uint)br.ReadByte() * 0x10000;
  53. e.position = e.sector * _sectorSize;
  54. e.sizeIn = br.ReadUInt32();
  55. if ((size & 0x40) != 0)
  56. {
  57. e.sizeOut = br.ReadUInt16() + (uint)br.ReadByte() * 0x10000;
  58. e.isCompressed = true;
  59. }
  60. else
  61. {
  62. e.sizeOut = e.sizeIn;
  63. e.isCompressed = false;
  64. }
  65. }
  66. return true;
  67. }
  68. private static byte readIndex(string asIndexName, listPathElement path)
  69. {
  70. byte bIndexNbSector = 0;
  71. int num = 0;
  72. int level;
  73. using (BinaryReader brIndex = new BinaryReader(File.Open(asIndexName, FileMode.Open)))
  74. {
  75. pathElement current = new pathElement(true);
  76. bIndexNbSector = brIndex.ReadByte();
  77. element e = new element();
  78. while (readElement(brIndex, ref e))
  79. {
  80. level = e.level;
  81. while (e.level-- > 0)
  82. current = current.Parent;
  83. pathElement entry = new pathElement(e.isDirectory) { Name = e.name, Position = e.position, Sector = e.sector, SizeIn = e.sizeIn, SizeOut = e.sizeOut, Id = num++, Level = level, IsCompressed = e.isCompressed };
  84. current.addEntry(entry);
  85. path.addToIndex(entry);
  86. if (e.isDirectory)
  87. current = entry;
  88. }
  89. }
  90. return bIndexNbSector;
  91. }
  92. private static void writeIndex(string as_file, byte ai_nbSector, listPathElement index)
  93. {
  94. index.SortById();
  95. using (BinaryWriter bwIndex = new BinaryWriter(File.Open(Variables.dirPack + as_file, FileMode.Create)))
  96. {
  97. bwIndex.Write(ai_nbSector);
  98. foreach (pathElement entryPath in index.getEntries())
  99. {
  100. if (entryPath.Name != "")
  101. {
  102. if (entryPath.IsDirectory)
  103. {
  104. bwIndex.Write((byte)(entryPath.Name.Length + 0x82));
  105. bwIndex.Write((byte)entryPath.Level);
  106. bwIndex.Write(entryPath.Name.ToCharArray());
  107. }
  108. else
  109. {
  110. if (entryPath.IsCompressed)
  111. bwIndex.Write((byte)(entryPath.Name.Length + 0x41));
  112. else
  113. bwIndex.Write((byte)(entryPath.Name.Length + 1));
  114. bwIndex.Write(entryPath.Name.ToCharArray());
  115. bwIndex.Write((UInt16)entryPath.Sector);
  116. bwIndex.Write((byte)(entryPath.Sector / 0x10000));
  117. bwIndex.Write((UInt32)entryPath.SizeIn);
  118. if (entryPath.IsCompressed)
  119. {
  120. bwIndex.Write((UInt16)entryPath.SizeOut);
  121. bwIndex.Write((byte)(entryPath.SizeOut / 0x10000));
  122. }
  123. }
  124. }
  125. }
  126. bwIndex.Write((byte)0);
  127. int size = (int)bwIndex.BaseStream.Length;
  128. padding(bwIndex, ref size);
  129. }
  130. }
  131. private static void padding(BinaryWriter a_bw, ref int size)
  132. {
  133. char[] hack = _copyright.ToCharArray();
  134. int id = 0;
  135. while (size % _sectorSize != 0)
  136. {
  137. a_bw.Write(hack[id++]);
  138. size++;
  139. if (id >= hack.Length)
  140. id = 0;
  141. }
  142. }
  143. private static int AddFileToStream(string pathname, ref int num, BinaryReader br, int size, bool regroup)
  144. {
  145. if (_bw == null)
  146. _bw = new BinaryWriter(File.Open(string.Format("{0}{1:00}", pathname, num), FileMode.Create));
  147. long pos = _bw.BaseStream.Position;
  148. int size_rest = _maxSizeFile - (int)_bw.BaseStream.Length;
  149. if (!regroup && size > size_rest)
  150. {
  151. _bw.Write(br.ReadBytes(size_rest), 0, size_rest);
  152. _bw.Close();
  153. _bw.Dispose();
  154. num++;
  155. _bw = new BinaryWriter(File.Open(string.Format("{0}{1:00}", pathname, num), FileMode.Create));
  156. _bw.Write(br.ReadBytes(size - size_rest), 0, size - size_rest);
  157. }
  158. else
  159. _bw.Write(br.ReadBytes(size), 0, size);
  160. padding(_bw, ref size);
  161. return size;
  162. }
  163. private static EnumSource findFile(pathElement entry, string numberFile)
  164. {
  165. // Check if the file is in the INSERT directory
  166. if (File.Exists(Variables.dirPack + entry.Name))
  167. return EnumSource.PACK_DIR;
  168. // Check if the file is in the UNPACK directory
  169. if (File.Exists(Variables.dirUnpack + numberFile + entry.FullPath))
  170. return EnumSource.UNPACK_DIR;
  171. // Otherwise, get the file from iso files
  172. return EnumSource.ISO_FILE;
  173. }
  174. #endregion
  175. #region Public methods
  176. /// <summary>
  177. /// Unpack all files from an index
  178. /// </summary>
  179. /// <param name="indexName">Pathname of the index</param>
  180. public static void unpackIsoFiles(string indexName)
  181. {
  182. BinaryReader br = null;
  183. byte bIndexNbSector = 0;
  184. int numFileIndex;
  185. int numFileOpen = -1;
  186. int iIndexSize = 0;
  187. string fileNameBase = Path.GetFileNameWithoutExtension(indexName);
  188. int.TryParse(Path.GetExtension(indexName).Substring(1), out numFileIndex);
  189. string directoryName = Variables.dirUnpack + string.Format("{0:D2}", numFileIndex);
  190. listPathElement index = new listPathElement();
  191. Trace.Write(string.Format("Reading index ({0}) : ", indexName));
  192. // Lecture de l'index
  193. try
  194. {
  195. bIndexNbSector = readIndex(indexName, index);
  196. index.SortBySector();
  197. }
  198. catch (Exception ex)
  199. {
  200. Trace.WriteLine(string.Format("ERROR : {0}", ex.Message));
  201. return;
  202. }
  203. Trace.WriteLine("OK");
  204. iIndexSize = bIndexNbSector * _sectorSize;
  205. try
  206. {
  207. Trace.WriteLine("Extracting files");
  208. Trace.Indent();
  209. foreach (pathElement entryPath in index.getEntries())
  210. {
  211. if (!entryPath.IsDirectory)
  212. {
  213. Trace.WriteLine(string.Format("Create file {0}", entryPath.FullPath));
  214. Directory.CreateDirectory(directoryName + Path.GetDirectoryName(entryPath.FullPath));
  215. int id = getIdFile(entryPath.Position, iIndexSize) + numFileIndex;
  216. double pos = (entryPath.Position - iIndexSize) % _maxSizeFile;
  217. if (numFileOpen == -1 || numFileOpen != id)
  218. {
  219. if (br != null)
  220. {
  221. br.Close();
  222. br.Dispose();
  223. }
  224. br = new BinaryReader(File.Open(string.Format("{0}.{1:D2}", fileNameBase, id), FileMode.Open));
  225. numFileOpen = id;
  226. }
  227. br.BaseStream.Seek((int)pos, SeekOrigin.Begin);
  228. int size_rest = (int)br.BaseStream.Length - (int)pos;
  229. using (BinaryWriter bw = new BinaryWriter(File.Open(directoryName + entryPath.FullPath, FileMode.Create)))
  230. {
  231. if (size_rest >= entryPath.SizeIn)
  232. bw.Write(br.ReadBytes((int)entryPath.SizeIn));
  233. else
  234. {
  235. bw.Write(br.ReadBytes(size_rest));
  236. int num = id + 1;
  237. if (br != null)
  238. {
  239. br.Close();
  240. br.Dispose();
  241. }
  242. br = new BinaryReader(File.Open(string.Format("{0}.{1:D2}", fileNameBase, num), FileMode.Open));
  243. numFileOpen = num;
  244. bw.Write(br.ReadBytes((int)entryPath.SizeIn - size_rest));
  245. }
  246. }
  247. }
  248. }
  249. }
  250. catch (Exception ex)
  251. {
  252. Trace.WriteLine(string.Format("==> ERROR : {0}", ex.Message));
  253. return;
  254. }
  255. finally
  256. {
  257. Trace.Unindent();
  258. }
  259. }
  260. /// <summary>
  261. /// Pack all files to index
  262. /// </summary>
  263. /// <param name="indexName">Pathname of the index</param>
  264. /// <param name="regroup">Used to know if the program pack files in 1 ou more files</param>
  265. public static void packIsoFiles(string indexName, bool regroup)
  266. {
  267. BinaryReader br = null;
  268. byte bIndexNbSector = 0;
  269. long l_sector = 0;
  270. long l_position = 0;
  271. int iIndexSize = 0;
  272. int numFileIndex;
  273. int numFileWrite = -1;
  274. int idSave = -1;
  275. int.TryParse(Path.GetExtension(indexName).Substring(1), out numFileIndex);
  276. string fileNameBase = Path.GetFileNameWithoutExtension(indexName);
  277. string filename = "";
  278. string directoryUnpackName = Variables.dirUnpack + string.Format("{0:D2}", numFileIndex);
  279. listPathElement index = new listPathElement();
  280. Trace.Write(string.Format("Reading index ({0}) : ", indexName));
  281. // Lecture de l'index
  282. try
  283. {
  284. bIndexNbSector = readIndex(indexName, index);
  285. index.SortBySector();
  286. }
  287. catch (Exception ex)
  288. {
  289. Trace.WriteLine(string.Format("ERROR : {0}", ex.Message));
  290. return;
  291. }
  292. l_sector += bIndexNbSector;
  293. iIndexSize = bIndexNbSector * _sectorSize;
  294. l_position += iIndexSize;
  295. numFileWrite = numFileIndex + 1;
  296. try
  297. {
  298. Trace.WriteLine("Inserting files");
  299. Trace.Indent();
  300. string s_pathname = string.Format("{0}{1}.", Variables.dirFinal, fileNameBase);
  301. Directory.CreateDirectory(Variables.dirFinal);
  302. foreach (pathElement entryPath in index.getEntries())
  303. {
  304. if (!entryPath.IsDirectory)
  305. {
  306. long size = 0;
  307. EnumSource idFile = findFile(entryPath, string.Format("{0:D2}", numFileIndex));
  308. if (idFile == EnumSource.PACK_DIR || idFile == EnumSource.UNPACK_DIR)
  309. {
  310. if (idFile == EnumSource.PACK_DIR)
  311. {
  312. Trace.WriteLine(string.Format("From {0} : file {1}", Variables.dirPack, entryPath.FullPath));
  313. filename = Variables.dirPack + entryPath.Name;
  314. }
  315. else
  316. {
  317. Trace.WriteLine(string.Format("From {0} : file {1}", Variables.dirUnpack, entryPath.FullPath));
  318. filename = directoryUnpackName + entryPath.FullPath;
  319. }
  320. using (BinaryReader brFile = new BinaryReader(File.Open(filename, FileMode.Open)))
  321. {
  322. size = brFile.BaseStream.Length;
  323. if (entryPath.IsCompressed)
  324. {
  325. // Compression du fichier
  326. entryPath.SizeIn = (UInt32)size;
  327. //entryPath.SizeOut = entryPath.SizeIn;
  328. }
  329. else
  330. {
  331. entryPath.SizeIn = (UInt32)size;
  332. //entryPath.SizeOut = entryPath.SizeIn;
  333. }
  334. int size_new = AddFileToStream(s_pathname, ref numFileWrite, brFile, (int)size, regroup);
  335. entryPath.Position = (UInt32)l_position;
  336. entryPath.Sector = entryPath.Position / _sectorSize;
  337. l_position += size_new;
  338. }
  339. }
  340. else
  341. {
  342. int id = getIdFile(entryPath.Position, iIndexSize) + numFileIndex;
  343. filename = string.Format("{0}.{1:D2}", fileNameBase, id);
  344. Trace.WriteLine(string.Format("From {0} : file {1}", filename, entryPath.FullPath));
  345. size = entryPath.SizeIn;
  346. double pos = (entryPath.Position - iIndexSize) % _maxSizeFile;
  347. int size_new = 0;
  348. if (br != null && id != idSave)
  349. {
  350. br.Close();
  351. br.Dispose();
  352. br = null;
  353. }
  354. if (br == null)
  355. {
  356. br = new BinaryReader(File.Open(filename, FileMode.Open));
  357. idSave = id;
  358. }
  359. br.BaseStream.Seek((int)pos, SeekOrigin.Begin);
  360. int size_rest = (int)br.BaseStream.Length - (int)pos;
  361. if (size_rest >= size)
  362. size_new = AddFileToStream(s_pathname, ref numFileWrite, br, (int)size, regroup);
  363. else
  364. {
  365. int sizeTemp = AddFileToStream(s_pathname, ref numFileWrite, br, size_rest, regroup);
  366. int num = id + 1;
  367. size_new = sizeTemp;
  368. if (br != null)
  369. {
  370. br.Close();
  371. br.Dispose();
  372. }
  373. filename = string.Format("{0}.{1:D2}", fileNameBase, num);
  374. br = new BinaryReader(File.Open(filename, FileMode.Open));
  375. idSave = num;
  376. sizeTemp = AddFileToStream(s_pathname, ref numFileWrite, br, (int)entryPath.SizeIn - size_rest, regroup);
  377. size_new += sizeTemp;
  378. }
  379. entryPath.Position = (UInt32)l_position;
  380. entryPath.Sector = entryPath.Position / _sectorSize;
  381. l_position += size_new;
  382. }
  383. }
  384. }
  385. _bw.Close();
  386. _bw.Dispose();
  387. writeIndex(indexName, bIndexNbSector, index);
  388. }
  389. catch (Exception ex)
  390. {
  391. Trace.WriteLine(string.Format("==> ERROR : {0}", ex.Message));
  392. return;
  393. }
  394. finally
  395. {
  396. Trace.Unindent();
  397. }
  398. }
  399. /// <summary>
  400. /// List files of an index
  401. /// </summary>
  402. /// <param name="indexName">Pathname of the index</param>
  403. public static void listFiles(string indexName)
  404. {
  405. string outputName;
  406. byte bIndexNbSector = 0;
  407. int iIndexSize;
  408. int numFile;
  409. int.TryParse(Path.GetExtension(indexName).Substring(1), out numFile);
  410. listPathElement index = new listPathElement();
  411. Trace.Write(string.Format("Reading index file ({0}) : ", indexName));
  412. try
  413. {
  414. Directory.CreateDirectory(Variables.dirUnpack);
  415. outputName = string.Format("{0}{1}{2}", Variables.dirUnpack, indexName, _listExtension);
  416. Variables.traceLog.Off(typeTraceListeners.CONSOLE);
  417. Variables.traceLog.On(typeTraceListeners.FILE, outputName);
  418. bIndexNbSector = readIndex(indexName, index);
  419. index.SortBySector();
  420. iIndexSize = bIndexNbSector * _sectorSize;
  421. foreach (pathElement entryPath in index.getEntries())
  422. {
  423. if (!entryPath.IsDirectory)
  424. {
  425. double d = (entryPath.Position - iIndexSize) / _maxSizeFile;
  426. int id = (int)Math.Floor(d) + 1;
  427. Trace.WriteLine(string.Format("{0,-36}Sector={1,-15}SizeIn={2,-15}SizeOut={3,-15}File=xenosaga.{4:D2}", entryPath.FullPath, entryPath.Sector, entryPath.SizeIn, entryPath.SizeOut, id + numFile));
  428. }
  429. }
  430. Variables.traceLog.On(typeTraceListeners.CONSOLE);
  431. Variables.traceLog.Off(typeTraceListeners.FILE, outputName);
  432. Variables.traceLog.Close(outputName);
  433. Trace.WriteLine("OK");
  434. }
  435. catch (Exception ex)
  436. {
  437. Trace.WriteLine(string.Format("ERROR : {0}", ex.Message));
  438. return;
  439. }
  440. }
  441. #endregion
  442. }
  443. }