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.

476 lines
17 KiB

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. #endregion
  162. #region Public methods
  163. public static void unpackIsoFiles(string indexName)
  164. {
  165. BinaryReader br = null;
  166. byte bIndexNbSector = 0;
  167. int numFileIndex;
  168. int numFileOpen = -1;
  169. int iIndexSize = 0;
  170. string fileNameBase = Path.GetFileNameWithoutExtension(indexName);
  171. int.TryParse(Path.GetExtension(indexName).Substring(1), out numFileIndex);
  172. string directoryName = Variables.dirUnpack + string.Format("{0:D2}", numFileIndex);
  173. listPathElement index = new listPathElement();
  174. Console.WriteLine("Traitement de l'index {0}", indexName);
  175. // Lecture de l'index
  176. try
  177. {
  178. bIndexNbSector = readIndex(indexName, index);
  179. index.SortBySector();
  180. }
  181. catch (Exception ex)
  182. {
  183. Console.WriteLine(" (EE) Erreur lors de la lecture de l'index : {0}", ex.Message);
  184. return;
  185. }
  186. iIndexSize = bIndexNbSector * _sectorSize;
  187. try
  188. {
  189. foreach (pathElement entryPath in index.getEntries())
  190. {
  191. if (!entryPath.IsDirectory)
  192. {
  193. Console.WriteLine(" Ecriture du fichier {0}", entryPath.FullPath);
  194. Directory.CreateDirectory(directoryName + Path.GetDirectoryName(entryPath.FullPath));
  195. int id = getIdFile(entryPath.Position, iIndexSize) + numFileIndex;
  196. double pos = (entryPath.Position - iIndexSize) % _maxSizeFile;
  197. if (numFileOpen == -1 || numFileOpen != id)
  198. {
  199. if (br != null)
  200. {
  201. br.Close();
  202. br.Dispose();
  203. }
  204. br = new BinaryReader(File.Open(string.Format("{0}.{1:D2}", fileNameBase, id), FileMode.Open));
  205. numFileOpen = id;
  206. }
  207. br.BaseStream.Seek((int)pos, SeekOrigin.Begin);
  208. int size_rest = (int)br.BaseStream.Length - (int)pos;
  209. using (BinaryWriter bw = new BinaryWriter(File.Open(directoryName + entryPath.FullPath, FileMode.Create)))
  210. {
  211. if (size_rest >= entryPath.SizeIn)
  212. bw.Write(br.ReadBytes((int)entryPath.SizeIn));
  213. else
  214. {
  215. bw.Write(br.ReadBytes(size_rest));
  216. int num = id + 1;
  217. if (br != null)
  218. {
  219. br.Close();
  220. br.Dispose();
  221. }
  222. br = new BinaryReader(File.Open(string.Format("{0}.{1:D2}", fileNameBase, num), FileMode.Open));
  223. numFileOpen = num;
  224. bw.Write(br.ReadBytes((int)entryPath.SizeIn - size_rest));
  225. }
  226. }
  227. }
  228. }
  229. }
  230. catch (Exception ex)
  231. {
  232. Console.WriteLine(" (EE) Erreur lors de l'extraction des fichiers : {0}", ex.Message);
  233. return;
  234. }
  235. }
  236. public static void packIsoFiles(string indexName, bool regroup)
  237. {
  238. BinaryReader br = null;
  239. byte bIndexNbSector = 0;
  240. long l_sector = 0;
  241. long l_position = 0;
  242. int iIndexSize = 0;
  243. int numFileIndex;
  244. int numFileWrite = -1;
  245. int idSave = -1;
  246. string fileNameBase = Path.GetFileNameWithoutExtension(indexName);
  247. int.TryParse(Path.GetExtension(indexName).Substring(1), out numFileIndex);
  248. listPathElement index = new listPathElement();
  249. Console.WriteLine("Traitement de l'index {0}", indexName);
  250. // Lecture de l'index
  251. try
  252. {
  253. bIndexNbSector = readIndex(indexName, index);
  254. index.SortBySector();
  255. }
  256. catch (Exception ex)
  257. {
  258. Console.WriteLine(" (EE) Erreur lors de la lecture de l'index : {0}", ex.Message);
  259. return;
  260. }
  261. l_sector += bIndexNbSector;
  262. iIndexSize = bIndexNbSector * _sectorSize;
  263. l_position += iIndexSize;
  264. numFileWrite = numFileIndex + 1;
  265. try
  266. {
  267. string s_pathname = string.Format("{0}{1}.", Variables.dirPack, fileNameBase);
  268. Directory.CreateDirectory(Variables.dirPack);
  269. foreach (pathElement entryPath in index.getEntries())
  270. {
  271. if (!entryPath.IsDirectory)
  272. {
  273. long size = 0;
  274. if (File.Exists(Variables.dirInsert + entryPath.Name))
  275. {
  276. Console.WriteLine(" Insertion du fichier {0}", entryPath.FullPath);
  277. using (BinaryReader brFile = new BinaryReader(File.Open(Variables.dirInsert + entryPath.Name, FileMode.Open)))
  278. {
  279. size = brFile.BaseStream.Length;
  280. if (entryPath.IsCompressed)
  281. {
  282. // Compression du fichier
  283. entryPath.SizeIn = (UInt32)size;
  284. //entryPath.SizeOut = entryPath.SizeIn;
  285. }
  286. else
  287. {
  288. entryPath.SizeIn = (UInt32)size;
  289. //entryPath.SizeOut = entryPath.SizeIn;
  290. }
  291. int size_new = AddFileToStream(s_pathname, ref numFileWrite, brFile, (int)size, regroup);
  292. entryPath.Position = (UInt32)l_position;
  293. entryPath.Sector = entryPath.Position / _sectorSize;
  294. l_position += size_new;
  295. }
  296. }
  297. else
  298. {
  299. Console.WriteLine(" Copie du fichier {0}", entryPath.FullPath);
  300. size = entryPath.SizeIn;
  301. int id = getIdFile(entryPath.Position, iIndexSize) + numFileIndex;
  302. double pos = (entryPath.Position - iIndexSize) % _maxSizeFile;
  303. int size_new = 0;
  304. if (br != null && id != idSave)
  305. {
  306. br.Close();
  307. br.Dispose();
  308. br = null;
  309. }
  310. if (br == null)
  311. {
  312. br = new BinaryReader(File.Open(string.Format("{0}.{1:D2}", fileNameBase, id), FileMode.Open));
  313. idSave = id;
  314. }
  315. br.BaseStream.Seek((int)pos, SeekOrigin.Begin);
  316. int size_rest = (int)br.BaseStream.Length - (int)pos;
  317. if (size_rest >= size)
  318. size_new = AddFileToStream(s_pathname, ref numFileWrite, br, (int)size, regroup);
  319. else
  320. {
  321. int sizeTemp = AddFileToStream(s_pathname, ref numFileWrite, br, size_rest, regroup);
  322. int num = id + 1;
  323. size_new = sizeTemp;
  324. if (br != null)
  325. {
  326. br.Close();
  327. br.Dispose();
  328. }
  329. br = new BinaryReader(File.Open(string.Format("{0}.{1:D2}", fileNameBase, num), FileMode.Open));
  330. idSave = num;
  331. sizeTemp = AddFileToStream(s_pathname, ref numFileWrite, br, (int)entryPath.SizeIn - size_rest, regroup);
  332. size_new += sizeTemp;
  333. }
  334. entryPath.Position = (UInt32)l_position;
  335. entryPath.Sector = entryPath.Position / _sectorSize;
  336. l_position += size_new;
  337. }
  338. }
  339. }
  340. _bw.Close();
  341. _bw.Dispose();
  342. writeIndex(indexName, bIndexNbSector, index);
  343. }
  344. catch (Exception ex)
  345. {
  346. Console.WriteLine("(EE) Erreur lors de l'insertion des fichiers : {0}", ex.Message);
  347. return;
  348. }
  349. }
  350. public static void listFiles(string indexName)
  351. {
  352. byte bIndexNbSector = 0;
  353. int iIndexSize;
  354. int numFile;
  355. int.TryParse(Path.GetExtension(indexName).Substring(1), out numFile);
  356. listPathElement index = new listPathElement();
  357. Console.WriteLine("Traitement de l'index {0}", indexName);
  358. try
  359. {
  360. Directory.CreateDirectory(Variables.dirUnpack);
  361. using (StreamWriter sw = new StreamWriter(string.Format("{0}{1}{2}", Variables.dirUnpack, indexName, _listExtension)))
  362. {
  363. TextWriterTraceListener twtl_trace = new TextWriterTraceListener(sw);
  364. Trace.Listeners.Add(twtl_trace);
  365. bIndexNbSector = readIndex(indexName, index);
  366. index.SortBySector();
  367. iIndexSize = bIndexNbSector * _sectorSize;
  368. foreach (pathElement entryPath in index.getEntries())
  369. {
  370. if (!entryPath.IsDirectory)
  371. {
  372. double d = (entryPath.Position - iIndexSize) / _maxSizeFile;
  373. int id = (int)Math.Floor(d) + 1;
  374. 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));
  375. }
  376. }
  377. }
  378. }
  379. catch (Exception ex)
  380. {
  381. Console.WriteLine(" (EE) Erreur lors de la lecture de l'index : {0}", ex.Message);
  382. return;
  383. }
  384. }
  385. #endregion
  386. }
  387. }