StringsBase.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using System.Collections.Generic;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. namespace OpenVIII
  7. {
  8. /// <summary>
  9. /// Loads strings from FF8 files
  10. /// </summary>
  11. public partial class Strings
  12. {
  13. #region Classes
  14. public abstract class StringsBase
  15. {
  16. #region Fields
  17. protected Memory.Archive Archive;
  18. protected string[] Filenames;
  19. protected StringFile Files;
  20. protected FF8StringReference.Settings Settings;
  21. #endregion Fields
  22. #region Constructors
  23. protected StringsBase()
  24. {
  25. }
  26. protected void SetValues(Memory.Archive archive, params string[] filenames)
  27. {
  28. Debug.WriteLine("Task={0}, Thread={2}, [Files={1}]",
  29. Task.CurrentId, string.Join(", ", filenames),
  30. Thread.CurrentThread.ManagedThreadId);
  31. Archive = archive;
  32. Filenames = filenames;
  33. }
  34. #endregion Constructors
  35. #region Indexers
  36. public FF8StringReference this[uint sectionid, int stringid] => Files[sectionid, stringid];
  37. #endregion Indexers
  38. #region Methods
  39. public Memory.Archive GetArchive() => Archive;
  40. public IReadOnlyList<string> GetFilenames() => Filenames;
  41. public StringFile GetFiles() => Files;
  42. /// <summary>
  43. /// <para>
  44. /// So you read the pointers at location, you get so many pointers then skip so many
  45. /// bytes before getting more pointers. Do this till start of next section.
  46. /// </para>
  47. /// </summary>
  48. /// <param name="br">BinaryReader where data is.</param>
  49. /// <param name="filename">file you are reading from</param>
  50. /// <param name="PointerStart">Section where pointers are.</param>
  51. /// <param name="StringStart">Section where strings are</param>
  52. /// <param name="grab">Get so many pointers</param>
  53. /// <param name="skip">Then skip so many bytes</param>
  54. protected void Get_Strings_BinMSG(BinaryReader br, string filename, uint PointerStart, uint StringStart, uint grab = 0, uint skip = 0)
  55. {
  56. Loc fpos = Files.subPositions[(int)PointerStart];
  57. br.BaseStream.Seek(fpos.seek, SeekOrigin.Begin);
  58. if (Files.sPositions.ContainsKey(PointerStart))
  59. {
  60. }
  61. else
  62. {
  63. ushort b = 0;
  64. ushort last = b;
  65. if (!Files.sPositions.ContainsKey(PointerStart))
  66. {
  67. Files.sPositions.Add(PointerStart, new List<FF8StringReference>());
  68. uint g = 1;
  69. while (br.BaseStream.Position < fpos.max)
  70. {
  71. b = br.ReadUInt16();
  72. if (last > b)
  73. break;
  74. else
  75. {
  76. if (b != 0xFFFF)
  77. {
  78. Files.sPositions[PointerStart].Add(new FF8StringReference(Archive, filename, b + StringStart, settings: Settings));
  79. last = b;
  80. }
  81. else
  82. Files.sPositions[PointerStart].Add(null);
  83. if (grab > 0 && ++g > grab)
  84. {
  85. br.BaseStream.Seek(skip, SeekOrigin.Current);
  86. g = 1;
  87. }
  88. }
  89. }
  90. }
  91. }
  92. }
  93. protected void Get_Strings_ComplexStr(BinaryReader br, string filename, uint key, List<uint> list)
  94. {
  95. uint[] fPaddings;
  96. fPaddings = mngrp_read_padding(br, Files.subPositions[(int)key], 1);
  97. Files.sPositions.Add(key, new List<FF8StringReference>());
  98. for (uint p = 0; p < fPaddings.Length; p += 2)
  99. {
  100. key = list[(int)fPaddings[(int)p + 1]];
  101. Loc fpos = Files.subPositions[(int)key];
  102. uint fpad = fPaddings[p] + fpos.seek;
  103. br.BaseStream.Seek(fpad, SeekOrigin.Begin);
  104. if (!Files.sPositions.ContainsKey(key))
  105. Files.sPositions.Add(key, new List<FF8StringReference>());
  106. br.BaseStream.Seek(fpad + 6, SeekOrigin.Begin);
  107. //byte[] UNK = br.ReadBytes(6);
  108. ushort len = br.ReadUInt16();
  109. uint stop = (uint)(br.BaseStream.Position + len - 9); //6 for UNK, 2 for len 1, for end null
  110. Files.sPositions[key].Add(new FF8StringReference(Archive, filename, (uint)br.BaseStream.Position, settings: Settings));
  111. //entry contains possible more than one string so I am scanning for null
  112. while (br.BaseStream.Position + 1 < stop)
  113. {
  114. byte b = br.ReadByte();
  115. if (b == 0) Files.sPositions[key].Add(new FF8StringReference(Archive, filename, (uint)br.BaseStream.Position, settings: Settings));
  116. }
  117. }
  118. }
  119. /// <summary>
  120. /// TODO: make this work with more than one file.
  121. /// </summary>
  122. /// <param name="br"></param>
  123. /// <param name="spos"></param>
  124. /// <param name="key"></param>
  125. /// <param name="pad"></param>
  126. protected void Get_Strings_Offsets(BinaryReader br, string filename, uint key, bool pad = false)
  127. {
  128. Loc fpos = Files.subPositions[(int)key];
  129. uint[] fPaddings = pad ? mngrp_read_padding(br, fpos) : (new uint[] { 1 });
  130. Files.sPositions.Add(key, new List<FF8StringReference>());
  131. for (uint p = 0; p < fPaddings.Length; p++)
  132. {
  133. if (fPaddings[p] <= 0) continue;
  134. uint fpad = pad ? fPaddings[p] + fpos.seek : fpos.seek;
  135. br.BaseStream.Seek(fpad, SeekOrigin.Begin);
  136. if (br.BaseStream.Position + 4 < br.BaseStream.Length)
  137. {
  138. int count = br.ReadUInt16();
  139. for (int i = 0; i < count && br.BaseStream.Position + 2 < br.BaseStream.Length; i++)
  140. {
  141. uint c = br.ReadUInt16();
  142. if (c < br.BaseStream.Length && c != 0)
  143. {
  144. c += fpad;
  145. Files.sPositions[key].Add(new FF8StringReference(Archive, filename, c, settings: Settings));
  146. }
  147. }
  148. }
  149. }
  150. }
  151. protected abstract void GetFileLocations(BinaryReader br);
  152. protected abstract void LoadArchiveFiles();
  153. protected uint[] mngrp_read_padding(BinaryReader br, Loc fpos, int type = 0)
  154. {
  155. uint[] fPaddings = null;
  156. br.BaseStream.Seek(fpos.seek, SeekOrigin.Begin);
  157. uint size = type == 0 ? br.ReadUInt16() : br.ReadUInt32();
  158. fPaddings = new uint[type == 0 ? size : size * type * 2];
  159. for (int i = 0; i < fPaddings.Length; i += 1 + type)
  160. {
  161. fPaddings[i] = br.ReadUInt16();
  162. if (type == 0 && fPaddings[i] + fpos.seek >= fpos.max)
  163. fPaddings[i] = 0;
  164. //if (fPaddings[i] != 0)
  165. // fPaddings[i] += fpos.seek;
  166. for (int j = 1; j < type + 1; j++)
  167. {
  168. fPaddings[i + j] = br.ReadUInt16();
  169. }
  170. }
  171. return fPaddings;
  172. }
  173. protected abstract void DefaultValues();
  174. static public T Load<T>() where T : StringsBase,new()
  175. {
  176. T r = new T();
  177. r.DefaultValues();
  178. r.LoadArchiveFiles();
  179. return r;
  180. }
  181. protected void LoadArchiveFiles_Simple()
  182. {
  183. ArchiveWorker aw = new ArchiveWorker(Archive, true);
  184. MemoryStream ms;
  185. using (BinaryReader br = new BinaryReader(ms = new MemoryStream(aw.GetBinaryFile(Filenames[0], true))))
  186. {
  187. Files = new StringFile(1);
  188. Files.subPositions.Add(new Loc { seek = 0, length = uint.MaxValue });
  189. Get_Strings_Offsets(br, Filenames[0], 0);
  190. ms = null;
  191. }
  192. }
  193. }
  194. #endregion Methods
  195. }
  196. #endregion Classes
  197. }