FF8StringReference.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. namespace OpenVIII
  6. {
  7. /// <summary>
  8. /// This class stores the reference to where the string is. Can be read with Read();
  9. /// </summary>
  10. public class FF8StringReference : FF8String
  11. {
  12. #region Fields
  13. private readonly Memory.Archive Archive;
  14. private readonly string Filename;
  15. private readonly long Offset;
  16. private readonly ushort ReadLength;
  17. private readonly Settings StringSettings;
  18. /// <summary>
  19. /// Check if had read already encause the actual length is 0.
  20. /// </summary>
  21. private bool HadRead = false;
  22. private object lockvar = new object();
  23. #endregion Fields
  24. #region Constructors
  25. public FF8StringReference(Memory.Archive archive, string filename, long offset, ushort length = 0, Settings settings = Settings.None)
  26. {
  27. Archive = archive;
  28. Filename = filename;
  29. Offset = offset;
  30. ReadLength = length;
  31. StringSettings = settings;
  32. }
  33. #endregion Constructors
  34. #region Enums
  35. [Flags]
  36. public enum Settings : byte
  37. {
  38. None = 0x0,
  39. //May contain multibyte characters
  40. MultiCharByte = 0x1,
  41. //May require replacement of tags from Namedic
  42. Namedic = 0x2,
  43. }
  44. #endregion Enums
  45. #region Properties
  46. /// <summary>
  47. /// multi characters bytes and double character bytes
  48. /// </summary>
  49. /// TODO replace me.
  50. public static Dictionary<byte, FF8String> ByteToString { get; private set; }
  51. public override int Length
  52. {
  53. get
  54. {
  55. if (base.Length == 0) Read();
  56. return base.Length;
  57. }
  58. }
  59. public override byte[] Value
  60. {
  61. get
  62. {
  63. if (base.Length == 0) Read();
  64. return base.Value;
  65. }
  66. set => base.Value = value;
  67. }
  68. #endregion Properties
  69. #region Methods
  70. public static void Init()
  71. {
  72. if (ByteToString == null)
  73. {
  74. ByteToString = new Dictionary<byte, FF8String>
  75. {
  76. //{0x01, "" },
  77. {0xC6, "VI"},// pos:166, col:20, row:9 --
  78. {0xC7, "II"},// pos:167, col:21, row:9 --
  79. //pc version sysfld00 and 01
  80. {0xCC, "GA"},// pos:172, col:5, row:9 --
  81. {0xCD, "ME"},// pos:173, col:6, row:9 --
  82. {0xCE, "FO"},// pos:174, col:7, row:9 --
  83. {0xCF, "LD"},// pos:175, col:8, row:9 --
  84. {0xD0, "ER"},// pos:176, col:9, row:9 --
  85. ////original texture - sysfont
  86. //{0xCC, "ME"},// pos:172, col:5, row:9 --
  87. //{0xCD, "MO"},// pos:173, col:6, row:9 --
  88. //{0xCE, "RY"},// pos:174, col:7, row:9 --
  89. //{0xCF, "CA"},// pos:175, col:8, row:9 --
  90. //{0xD0, "RD"},// pos:176, col:9, row:9 --
  91. {0xD1, "Sl"},// pos:177, col:10, row:9 --
  92. {0xD2, "ot"},// pos:178, col:11, row:9 --
  93. {0xD3, "ing"},// pos:179, col:12, row:10 --
  94. {0xD4, "St"},// pos:180, col:13, row:10 --
  95. {0xD5, "ec"},// pos:181, col:14, row:10 --
  96. {0xD6, "kp"},// pos:182, col:15, row:10 --
  97. {0xD7, "la"},// pos:183, col:16, row:10 --
  98. {0xD8, ":z"},// pos:184, col:17, row:10 --
  99. {0xD9, "Fr"},// pos:185, col:18, row:10 --
  100. {0xDA, "nt"},// pos:186, col:19, row:10 --
  101. {0xDB, "elng"},// pos:187, col:20, row:10 --
  102. {0xDC, "re"},// pos:188, col:21, row:10 --
  103. {0xDD, "S:"},// pos:189, col:1, row:10 --
  104. {0xDE, "so"},// pos:190, col:2, row:10 --
  105. {0xDF, "Ra"},// pos:191, col:3, row:10 --
  106. {0xE0, "nu"},// pos:192, col:4, row:10 --
  107. {0xE1, "ra"},// pos:193, col:5, row:10 --
  108. // all above is renderable meaning there is an image in the texture atlas for it.
  109. // all below needs expanded into single byte characters.
  110. //{0xE3, ""},// pos:195, col:0, row:0 --
  111. //{0xE4, ""},// pos:196, col:0, row:0 --
  112. //{0xE5, ""},// pos:197, col:0, row:0 --
  113. //{0xE6, ""},// pos:198, col:0, row:0 --
  114. //{0xE7, ""},// pos:199, col:0, row:0 --
  115. {0xE8, "in"},// pos:200, col:0, row:0 --
  116. {0xE9, "e "},// pos:201, col:0, row:0 --
  117. {0xEA, "ne"},// pos:202, col:0, row:0 --
  118. {0xEB, "to"},// pos:203, col:0, row:0 --
  119. {0xEC, "re"},// pos:204, col:0, row:0 --
  120. {0xED, "HP"},// pos:205, col:0, row:0 --
  121. {0xEE, "l "},// pos:206, col:0, row:0 --
  122. {0xEF, "ll"},// pos:207, col:0, row:0 --
  123. {0xF0, "GF"},// pos:208, col:0, row:0 --
  124. {0xF1, "nt"},// pos:209, col:0, row:0 --
  125. {0xF2, "il"},// pos:210, col:0, row:0 --
  126. {0xF3, "o "},// pos:211, col:0, row:0 --
  127. {0xF4, "ef"},// pos:212, col:0, row:0 --
  128. {0xF5, "on"},// pos:213, col:0, row:0 --
  129. {0xF6, " w"},// pos:214, col:0, row:0 --
  130. {0xF7, " r"},// pos:215, col:0, row:0 --
  131. {0xF8, "wi"},// pos:216, col:0, row:0 --
  132. {0xF9, "fi"},// pos:217, col:0, row:0 --
  133. //{0xFA, ""},// pos:218, col:0, row:0 --
  134. {0xFB, "s "},// pos:219, col:0, row:0 --
  135. {0xFC, "ar"},// pos:220, col:0, row:0 --
  136. //{0xFD, ""},// pos:221, col:0, row:0 --
  137. {0xFE, " S"},// pos:222, col:0, row:0 --
  138. {0xFF, "ag"},// pos:223, col:0, row:0 --
  139. };
  140. }
  141. }
  142. private void InsertNamedic()
  143. {
  144. if (Length > 0)
  145. {
  146. int i = 0;
  147. do
  148. {
  149. i = Array.FindIndex(base.Value, i, Length - i, x => x == 0x0E);
  150. if (i >= 0)
  151. {
  152. byte id = (byte)(value[i + 1] - 0x20);
  153. byte[] newdata = Memory.Strings.Read(Strings.FileID.NAMEDIC, 0, id);
  154. byte[] end = value.Skip(2 + i).ToArray();
  155. Array.Resize(ref value, Length + newdata.Length - 2);
  156. Array.Copy(newdata, 0, value, i, newdata.Length);
  157. Array.Copy(end, 0, value, i + newdata.Length, end.Length);
  158. i += newdata.Length;
  159. }
  160. }
  161. while (i >= 0 && i < Length);
  162. }
  163. }
  164. private void Read()
  165. {
  166. lock (lockvar)
  167. if (base.Length == 0 && !HadRead)
  168. {
  169. HadRead = true;
  170. ArchiveWorker aw = new ArchiveWorker(Archive, true);
  171. using (BinaryReader br = new BinaryReader(new MemoryStream(aw.GetBinaryFile(Filename, true))))
  172. {
  173. br.BaseStream.Seek(Offset, SeekOrigin.Begin);
  174. if (ReadLength > 0 && (StringSettings & Settings.MultiCharByte) == 0) // ReadLength set, read that. unless contains multicharbytes
  175. Value = br.ReadBytes(ReadLength);
  176. else // Length unknown read to null
  177. {
  178. using (BinaryWriter bw = new BinaryWriter(new MemoryStream()))
  179. {
  180. for (int i = 0; i < br.BaseStream.Length; i++)
  181. {
  182. if (ReadLength > 0 && i > ReadLength) break;
  183. byte b = br.ReadByte();
  184. if (i == 0 || b != 0)
  185. {
  186. if (b > 0xE1 && (StringSettings & Settings.MultiCharByte) != 0 && ByteToString.ContainsKey(b))
  187. bw.Write(ByteToString[b].Value);
  188. else
  189. bw.Write(b);
  190. }
  191. else break;
  192. }
  193. Value = ((MemoryStream)bw.BaseStream).ToArray();
  194. }
  195. }
  196. }
  197. if ((StringSettings & Settings.Namedic) != 0)
  198. {
  199. InsertNamedic();
  200. }
  201. }
  202. }
  203. #endregion Methods
  204. public static FF8String operator +(FF8StringReference a, FF8String b) => (FF8String)a + b;
  205. public static FF8String operator +(FF8String a, FF8StringReference b) => a + (FF8String)b;
  206. public static FF8String operator +(FF8StringReference a, FF8StringReference b) => (FF8String)a + (FF8String)b;
  207. public static FF8String operator +(FF8StringReference a, string b) => (FF8String)a + b;
  208. public static FF8String operator +(string a, FF8StringReference b) => a + (FF8String)b;
  209. /// old read method encase i missed something.
  210. //public FF8String Read(BinaryReader br, FileID fid, uint pos)
  211. //{
  212. // if (pos == 0)
  213. // return new FF8String("");
  214. // if (pos < br.BaseStream.Length)
  215. // using (MemoryStream os = new MemoryStream(50))
  216. // {p
  217. // br.BaseStream.Seek(pos, SeekOrigin.Begin);
  218. // int c = 0;
  219. // byte b = 0;
  220. // do
  221. // {
  222. // if (br.BaseStream.Position > br.BaseStream.Length) break;
  223. // //sometimes strings start with 00 or 01. But there is another 00 at the end.
  224. // //I think it's for SeeD test like 1 is right and 0 is wrong. for now i skip them.
  225. // b = br.ReadByte();
  226. // if (b != 0 && b != 1)
  227. // {
  228. // os.WriteByte(b);
  229. // }
  230. // c++;
  231. // }
  232. // while (b != 0 || c == 0);
  233. // if (os.Length > 0)
  234. // return os.ToArray();
  235. // }
  236. // return null;
  237. //}
  238. }
  239. }