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.

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