ByteReader.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. //----------------------------------------------
  2. // NGUI: Next-Gen UI kit
  3. // Copyright © 2011-2014 Tasharen Entertainment
  4. //----------------------------------------------
  5. using UnityEngine;
  6. using System.Text;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. /// <summary>
  10. /// MemoryStream.ReadLine has an interesting oddity: it doesn't always advance the stream's position by the correct amount:
  11. /// http://social.msdn.microsoft.com/Forums/en-AU/Vsexpressvcs/thread/b8f7837b-e396-494e-88e1-30547fcf385f
  12. /// Solution? Custom line reader with the added benefit of not having to use streams at all.
  13. /// </summary>
  14. public class ByteReader
  15. {
  16. byte[] mBuffer;
  17. int mOffset = 0;
  18. public ByteReader(byte[] bytes) { mBuffer = bytes; }
  19. public ByteReader(TextAsset asset) { mBuffer = asset.bytes; }
  20. /// <summary>
  21. /// Read the contents of the specified file and return a Byte Reader to work with.
  22. /// </summary>
  23. static public ByteReader Open(string path)
  24. {
  25. #if UNITY_EDITOR || (!UNITY_FLASH && !NETFX_CORE && !UNITY_WP8)
  26. FileStream fs = File.OpenRead(path);
  27. if (fs != null)
  28. {
  29. fs.Seek(0, SeekOrigin.End);
  30. byte[] buffer = new byte[fs.Position];
  31. fs.Seek(0, SeekOrigin.Begin);
  32. fs.Read(buffer, 0, buffer.Length);
  33. fs.Close();
  34. return new ByteReader(buffer);
  35. }
  36. #endif
  37. return null;
  38. }
  39. /// <summary>
  40. /// Whether the buffer is readable.
  41. /// </summary>
  42. public bool canRead { get { return (mBuffer != null && mOffset < mBuffer.Length); } }
  43. /// <summary>
  44. /// Read a single line from the buffer.
  45. /// </summary>
  46. static string ReadLine(byte[] buffer, int start, int count)
  47. {
  48. #if UNITY_FLASH
  49. // Encoding.UTF8 is not supported in Flash :(
  50. StringBuilder sb = new StringBuilder();
  51. int max = start + count;
  52. for (int i = start; i < max; ++i)
  53. {
  54. byte byte0 = buffer[i];
  55. if ((byte0 & 128) == 0)
  56. {
  57. // If an UCS fits 7 bits, its coded as 0xxxxxxx. This makes ASCII character represented by themselves
  58. sb.Append((char)byte0);
  59. }
  60. else if ((byte0 & 224) == 192)
  61. {
  62. // If an UCS fits 11 bits, it is coded as 110xxxxx 10xxxxxx
  63. if (++i == count) break;
  64. byte byte1 = buffer[i];
  65. int ch = (byte0 & 31) << 6;
  66. ch |= (byte1 & 63);
  67. sb.Append((char)ch);
  68. }
  69. else if ((byte0 & 240) == 224)
  70. {
  71. // If an UCS fits 16 bits, it is coded as 1110xxxx 10xxxxxx 10xxxxxx
  72. if (++i == count) break;
  73. byte byte1 = buffer[i];
  74. if (++i == count) break;
  75. byte byte2 = buffer[i];
  76. if (byte0 == 0xEF && byte1 == 0xBB && byte2 == 0xBF)
  77. {
  78. // Byte Order Mark -- generally the first 3 bytes in a Windows-saved UTF-8 file. Skip it.
  79. }
  80. else
  81. {
  82. int ch = (byte0 & 15) << 12;
  83. ch |= (byte1 & 63) << 6;
  84. ch |= (byte2 & 63);
  85. sb.Append((char)ch);
  86. }
  87. }
  88. else if ((byte0 & 248) == 240)
  89. {
  90. // If an UCS fits 21 bits, it is coded as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  91. if (++i == count) break;
  92. byte byte1 = buffer[i];
  93. if (++i == count) break;
  94. byte byte2 = buffer[i];
  95. if (++i == count) break;
  96. byte byte3 = buffer[i];
  97. int ch = (byte0 & 7) << 18;
  98. ch |= (byte1 & 63) << 12;
  99. ch |= (byte2 & 63) << 6;
  100. ch |= (byte3 & 63);
  101. sb.Append((char)ch);
  102. }
  103. }
  104. return sb.ToString();
  105. #else
  106. return Encoding.UTF8.GetString(buffer, start, count);
  107. #endif
  108. }
  109. /// <summary>
  110. /// Read a single line from the buffer.
  111. /// </summary>
  112. public string ReadLine() { return ReadLine(true); }
  113. /// <summary>
  114. /// Read a single line from the buffer.
  115. /// </summary>
  116. public string ReadLine(bool skipEmptyLines)
  117. {
  118. int max = mBuffer.Length;
  119. // Skip empty characters
  120. if (skipEmptyLines)
  121. {
  122. while (mOffset < max && mBuffer[mOffset] < 32) ++mOffset;
  123. }
  124. int end = mOffset;
  125. if (end < max)
  126. {
  127. for (; ; )
  128. {
  129. if (end < max)
  130. {
  131. int ch = mBuffer[end++];
  132. if (ch != '\n' && ch != '\r') continue;
  133. }
  134. else ++end;
  135. string line = ReadLine(mBuffer, mOffset, end - mOffset - 1);
  136. mOffset = end;
  137. return line;
  138. }
  139. }
  140. mOffset = max;
  141. return null;
  142. }
  143. /// <summary>
  144. /// Assume that the entire file is a collection of key/value pairs.
  145. /// </summary>
  146. public Dictionary<string, string> ReadDictionary()
  147. {
  148. Dictionary<string, string> dict = new Dictionary<string, string>();
  149. char[] separator = new char[] { '=' };
  150. while (canRead)
  151. {
  152. string line = ReadLine();
  153. if (line == null) break;
  154. if (line.StartsWith("//")) continue;
  155. #if UNITY_FLASH
  156. string[] split = line.Split(separator, System.StringSplitOptions.RemoveEmptyEntries);
  157. #else
  158. string[] split = line.Split(separator, 2, System.StringSplitOptions.RemoveEmptyEntries);
  159. #endif
  160. if (split.Length == 2)
  161. {
  162. string key = split[0].Trim();
  163. string val = split[1].Trim().Replace("\\n", "\n");
  164. dict[key] = val;
  165. }
  166. }
  167. return dict;
  168. }
  169. static BetterList<string> mTemp = new BetterList<string>();
  170. /// <summary>
  171. /// Read a single line of Comma-Separated Values from the file.
  172. /// </summary>
  173. public BetterList<string> ReadCSV()
  174. {
  175. mTemp.Clear();
  176. string line = "";
  177. bool insideQuotes = false;
  178. int wordStart = 0;
  179. while (canRead)
  180. {
  181. if (insideQuotes)
  182. {
  183. string s = ReadLine(false);
  184. if (s == null) return null;
  185. s = s.Replace("\\n", "\n");
  186. line += "\n" + s;
  187. ++wordStart;
  188. }
  189. else
  190. {
  191. line = ReadLine(true);
  192. if (line == null) return null;
  193. line = line.Replace("\\n", "\n");
  194. wordStart = 0;
  195. }
  196. for (int i = wordStart, imax = line.Length; i < imax; ++i)
  197. {
  198. char ch = line[i];
  199. if (ch == ',')
  200. {
  201. if (!insideQuotes)
  202. {
  203. mTemp.Add(line.Substring(wordStart, i - wordStart));
  204. wordStart = i + 1;
  205. }
  206. }
  207. else if (ch == '"')
  208. {
  209. if (insideQuotes)
  210. {
  211. if (i + 1 >= imax)
  212. {
  213. mTemp.Add(line.Substring(wordStart, i - wordStart).Replace("\"\"", "\""));
  214. return mTemp;
  215. }
  216. if (line[i + 1] != '"')
  217. {
  218. mTemp.Add(line.Substring(wordStart, i - wordStart).Replace("\"\"", "\""));
  219. insideQuotes = false;
  220. if (line[i + 1] == ',')
  221. {
  222. ++i;
  223. wordStart = i + 1;
  224. }
  225. }
  226. else ++i;
  227. }
  228. else
  229. {
  230. wordStart = i + 1;
  231. insideQuotes = true;
  232. }
  233. }
  234. }
  235. if (wordStart < line.Length)
  236. {
  237. if (insideQuotes) continue;
  238. mTemp.Add(line.Substring(wordStart, line.Length - wordStart));
  239. }
  240. return mTemp;
  241. }
  242. return null;
  243. }
  244. }