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.

539 lines
19 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
  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)
  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 + 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. string fileNameBase = Path.GetFileNameWithoutExtension(indexName);
  274. string filename = "";
  275. int.TryParse(Path.GetExtension(indexName).Substring(1), out numFileIndex);
  276. listPathElement index = new listPathElement();
  277. Trace.Write(string.Format("Reading index ({0}) : ", indexName));
  278. // Lecture de l'index
  279. try
  280. {
  281. bIndexNbSector = readIndex(indexName, index);
  282. index.SortBySector();
  283. }
  284. catch (Exception ex)
  285. {
  286. Trace.WriteLine(string.Format("ERROR : {0}", ex.Message));
  287. return;
  288. }
  289. l_sector += bIndexNbSector;
  290. iIndexSize = bIndexNbSector * _sectorSize;
  291. l_position += iIndexSize;
  292. numFileWrite = numFileIndex + 1;
  293. try
  294. {
  295. Trace.WriteLine("Inserting files");
  296. Trace.Indent();
  297. string s_pathname = string.Format("{0}{1}.", Variables.dirPack, fileNameBase);
  298. Directory.CreateDirectory(Variables.dirPack);
  299. foreach (pathElement entryPath in index.getEntries())
  300. {
  301. if (!entryPath.IsDirectory)
  302. {
  303. long size = 0;
  304. int idFile = findFile(entryPath);
  305. if (idFile == 1 || idFile == 2)
  306. {
  307. if (idFile == 1)
  308. {
  309. Trace.WriteLine(string.Format("From {0} : file {1}", Variables.dirInsert, entryPath.FullPath));
  310. filename = Variables.dirInsert + entryPath.Name;
  311. }
  312. else
  313. {
  314. Trace.WriteLine(string.Format("From {0} : file {1}", Variables.dirUnpack, entryPath.FullPath));
  315. filename = Variables.dirUnpack + entryPath.FullPath;
  316. }
  317. using (BinaryReader brFile = new BinaryReader(File.Open(filename, FileMode.Open)))
  318. {
  319. size = brFile.BaseStream.Length;
  320. if (entryPath.IsCompressed)
  321. {
  322. // Compression du fichier
  323. entryPath.SizeIn = (UInt32)size;
  324. //entryPath.SizeOut = entryPath.SizeIn;
  325. }
  326. else
  327. {
  328. entryPath.SizeIn = (UInt32)size;
  329. //entryPath.SizeOut = entryPath.SizeIn;
  330. }
  331. int size_new = AddFileToStream(s_pathname, ref numFileWrite, brFile, (int)size, regroup);
  332. entryPath.Position = (UInt32)l_position;
  333. entryPath.Sector = entryPath.Position / _sectorSize;
  334. l_position += size_new;
  335. }
  336. }
  337. else
  338. {
  339. int id = getIdFile(entryPath.Position, iIndexSize) + numFileIndex;
  340. filename = string.Format("{0}.{1:D2}", fileNameBase, id);
  341. Trace.WriteLine(string.Format("From {0} : file {1}", filename, entryPath.FullPath));
  342. size = entryPath.SizeIn;
  343. double pos = (entryPath.Position - iIndexSize) % _maxSizeFile;
  344. int size_new = 0;
  345. if (br != null && id != idSave)
  346. {
  347. br.Close();
  348. br.Dispose();
  349. br = null;
  350. }
  351. if (br == null)
  352. {
  353. br = new BinaryReader(File.Open(filename, FileMode.Open));
  354. idSave = id;
  355. }
  356. br.BaseStream.Seek((int)pos, SeekOrigin.Begin);
  357. int size_rest = (int)br.BaseStream.Length - (int)pos;
  358. if (size_rest >= size)
  359. size_new = AddFileToStream(s_pathname, ref numFileWrite, br, (int)size, regroup);
  360. else
  361. {
  362. int sizeTemp = AddFileToStream(s_pathname, ref numFileWrite, br, size_rest, regroup);
  363. int num = id + 1;
  364. size_new = sizeTemp;
  365. if (br != null)
  366. {
  367. br.Close();
  368. br.Dispose();
  369. }
  370. filename = string.Format("{0}.{1:D2}", fileNameBase, num);
  371. br = new BinaryReader(File.Open(filename, FileMode.Open));
  372. idSave = num;
  373. sizeTemp = AddFileToStream(s_pathname, ref numFileWrite, br, (int)entryPath.SizeIn - size_rest, regroup);
  374. size_new += sizeTemp;
  375. }
  376. entryPath.Position = (UInt32)l_position;
  377. entryPath.Sector = entryPath.Position / _sectorSize;
  378. l_position += size_new;
  379. }
  380. }
  381. }
  382. _bw.Close();
  383. _bw.Dispose();
  384. writeIndex(indexName, bIndexNbSector, index);
  385. }
  386. catch (Exception ex)
  387. {
  388. Trace.WriteLine(string.Format("==> ERROR : {0}", ex.Message));
  389. return;
  390. }
  391. finally
  392. {
  393. Trace.Unindent();
  394. }
  395. }
  396. /// <summary>
  397. /// List files of an index
  398. /// </summary>
  399. /// <param name="indexName">Pathname of the index</param>
  400. public static void listFiles(string indexName)
  401. {
  402. string outputName;
  403. byte bIndexNbSector = 0;
  404. int iIndexSize;
  405. int numFile;
  406. int.TryParse(Path.GetExtension(indexName).Substring(1), out numFile);
  407. listPathElement index = new listPathElement();
  408. Trace.Write(string.Format("Reading index file ({0}) : ", indexName));
  409. try
  410. {
  411. Directory.CreateDirectory(Variables.dirUnpack);
  412. outputName = string.Format("{0}{1}{2}", Variables.dirUnpack, indexName, _listExtension);
  413. using (StreamWriter sw = new StreamWriter(outputName))
  414. {
  415. Functions.ManageListener(false, true, sw);
  416. bIndexNbSector = readIndex(indexName, index);
  417. index.SortBySector();
  418. iIndexSize = bIndexNbSector * _sectorSize;
  419. foreach (pathElement entryPath in index.getEntries())
  420. {
  421. if (!entryPath.IsDirectory)
  422. {
  423. double d = (entryPath.Position - iIndexSize) / _maxSizeFile;
  424. int id = (int)Math.Floor(d) + 1;
  425. 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));
  426. }
  427. }
  428. Functions.ManageListener(true, false);
  429. }
  430. Trace.WriteLine("OK");
  431. }
  432. catch (Exception ex)
  433. {
  434. Trace.WriteLine(string.Format("ERROR : {0}", ex.Message));
  435. return;
  436. }
  437. }
  438. #endregion
  439. }
  440. }