//----------------------------------------------
|
|
// NGUI: Next-Gen UI kit
|
|
// Copyright © 2011-2014 Tasharen Entertainment
|
|
//----------------------------------------------
|
|
|
|
using UnityEngine;
|
|
using System.Text;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
|
|
/// <summary>
|
|
/// MemoryStream.ReadLine has an interesting oddity: it doesn't always advance the stream's position by the correct amount:
|
|
/// http://social.msdn.microsoft.com/Forums/en-AU/Vsexpressvcs/thread/b8f7837b-e396-494e-88e1-30547fcf385f
|
|
/// Solution? Custom line reader with the added benefit of not having to use streams at all.
|
|
/// </summary>
|
|
|
|
public class ByteReader
|
|
{
|
|
byte[] mBuffer;
|
|
int mOffset = 0;
|
|
|
|
public ByteReader (byte[] bytes) { mBuffer = bytes; }
|
|
public ByteReader (TextAsset asset) { mBuffer = asset.bytes; }
|
|
|
|
/// <summary>
|
|
/// Read the contents of the specified file and return a Byte Reader to work with.
|
|
/// </summary>
|
|
|
|
static public ByteReader Open (string path)
|
|
{
|
|
#if UNITY_EDITOR || (!UNITY_FLASH && !NETFX_CORE && !UNITY_WP8)
|
|
FileStream fs = File.OpenRead(path);
|
|
|
|
if (fs != null)
|
|
{
|
|
fs.Seek(0, SeekOrigin.End);
|
|
byte[] buffer = new byte[fs.Position];
|
|
fs.Seek(0, SeekOrigin.Begin);
|
|
fs.Read(buffer, 0, buffer.Length);
|
|
fs.Close();
|
|
return new ByteReader(buffer);
|
|
}
|
|
#endif
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Whether the buffer is readable.
|
|
/// </summary>
|
|
|
|
public bool canRead { get { return (mBuffer != null && mOffset < mBuffer.Length); } }
|
|
|
|
/// <summary>
|
|
/// Read a single line from the buffer.
|
|
/// </summary>
|
|
|
|
static string ReadLine (byte[] buffer, int start, int count)
|
|
{
|
|
#if UNITY_FLASH
|
|
// Encoding.UTF8 is not supported in Flash :(
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
int max = start + count;
|
|
|
|
for (int i = start; i < max; ++i)
|
|
{
|
|
byte byte0 = buffer[i];
|
|
|
|
if ((byte0 & 128) == 0)
|
|
{
|
|
// If an UCS fits 7 bits, its coded as 0xxxxxxx. This makes ASCII character represented by themselves
|
|
sb.Append((char)byte0);
|
|
}
|
|
else if ((byte0 & 224) == 192)
|
|
{
|
|
// If an UCS fits 11 bits, it is coded as 110xxxxx 10xxxxxx
|
|
if (++i == count) break;
|
|
byte byte1 = buffer[i];
|
|
int ch = (byte0 & 31) << 6;
|
|
ch |= (byte1 & 63);
|
|
sb.Append((char)ch);
|
|
}
|
|
else if ((byte0 & 240) == 224)
|
|
{
|
|
// If an UCS fits 16 bits, it is coded as 1110xxxx 10xxxxxx 10xxxxxx
|
|
if (++i == count) break;
|
|
byte byte1 = buffer[i];
|
|
if (++i == count) break;
|
|
byte byte2 = buffer[i];
|
|
|
|
if (byte0 == 0xEF && byte1 == 0xBB && byte2 == 0xBF)
|
|
{
|
|
// Byte Order Mark -- generally the first 3 bytes in a Windows-saved UTF-8 file. Skip it.
|
|
}
|
|
else
|
|
{
|
|
int ch = (byte0 & 15) << 12;
|
|
ch |= (byte1 & 63) << 6;
|
|
ch |= (byte2 & 63);
|
|
sb.Append((char)ch);
|
|
}
|
|
}
|
|
else if ((byte0 & 248) == 240)
|
|
{
|
|
// If an UCS fits 21 bits, it is coded as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
|
if (++i == count) break;
|
|
byte byte1 = buffer[i];
|
|
if (++i == count) break;
|
|
byte byte2 = buffer[i];
|
|
if (++i == count) break;
|
|
byte byte3 = buffer[i];
|
|
|
|
int ch = (byte0 & 7) << 18;
|
|
ch |= (byte1 & 63) << 12;
|
|
ch |= (byte2 & 63) << 6;
|
|
ch |= (byte3 & 63);
|
|
sb.Append((char)ch);
|
|
}
|
|
}
|
|
return sb.ToString();
|
|
#else
|
|
return Encoding.UTF8.GetString(buffer, start, count);
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a single line from the buffer.
|
|
/// </summary>
|
|
|
|
public string ReadLine () { return ReadLine(true); }
|
|
|
|
/// <summary>
|
|
/// Read a single line from the buffer.
|
|
/// </summary>
|
|
|
|
public string ReadLine (bool skipEmptyLines)
|
|
{
|
|
int max = mBuffer.Length;
|
|
|
|
// Skip empty characters
|
|
if (skipEmptyLines)
|
|
{
|
|
while (mOffset < max && mBuffer[mOffset] < 32) ++mOffset;
|
|
}
|
|
|
|
int end = mOffset;
|
|
|
|
if (end < max)
|
|
{
|
|
for (; ; )
|
|
{
|
|
if (end < max)
|
|
{
|
|
int ch = mBuffer[end++];
|
|
if (ch != '\n' && ch != '\r') continue;
|
|
}
|
|
else ++end;
|
|
|
|
string line = ReadLine(mBuffer, mOffset, end - mOffset - 1);
|
|
mOffset = end;
|
|
return line;
|
|
}
|
|
}
|
|
mOffset = max;
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Assume that the entire file is a collection of key/value pairs.
|
|
/// </summary>
|
|
|
|
public Dictionary<string, string> ReadDictionary ()
|
|
{
|
|
Dictionary<string, string> dict = new Dictionary<string, string>();
|
|
char[] separator = new char[] { '=' };
|
|
|
|
while (canRead)
|
|
{
|
|
string line = ReadLine();
|
|
if (line == null) break;
|
|
if (line.StartsWith("//")) continue;
|
|
|
|
#if UNITY_FLASH
|
|
string[] split = line.Split(separator, System.StringSplitOptions.RemoveEmptyEntries);
|
|
#else
|
|
string[] split = line.Split(separator, 2, System.StringSplitOptions.RemoveEmptyEntries);
|
|
#endif
|
|
|
|
if (split.Length == 2)
|
|
{
|
|
string key = split[0].Trim();
|
|
string val = split[1].Trim().Replace("\\n", "\n");
|
|
dict[key] = val;
|
|
}
|
|
}
|
|
return dict;
|
|
}
|
|
|
|
static BetterList<string> mTemp = new BetterList<string>();
|
|
|
|
/// <summary>
|
|
/// Read a single line of Comma-Separated Values from the file.
|
|
/// </summary>
|
|
|
|
public BetterList<string> ReadCSV ()
|
|
{
|
|
mTemp.Clear();
|
|
string line = "";
|
|
bool insideQuotes = false;
|
|
int wordStart = 0;
|
|
|
|
while (canRead)
|
|
{
|
|
if (insideQuotes)
|
|
{
|
|
string s = ReadLine(false);
|
|
if (s == null) return null;
|
|
s = s.Replace("\\n", "\n");
|
|
line += "\n" + s;
|
|
++wordStart;
|
|
}
|
|
else
|
|
{
|
|
line = ReadLine(true);
|
|
if (line == null) return null;
|
|
line = line.Replace("\\n", "\n");
|
|
wordStart = 0;
|
|
}
|
|
|
|
for (int i = wordStart, imax = line.Length; i < imax; ++i)
|
|
{
|
|
char ch = line[i];
|
|
|
|
if (ch == ',')
|
|
{
|
|
if (!insideQuotes)
|
|
{
|
|
mTemp.Add(line.Substring(wordStart, i - wordStart));
|
|
wordStart = i + 1;
|
|
}
|
|
}
|
|
else if (ch == '"')
|
|
{
|
|
if (insideQuotes)
|
|
{
|
|
if (i + 1 >= imax)
|
|
{
|
|
mTemp.Add(line.Substring(wordStart, i - wordStart).Replace("\"\"", "\""));
|
|
return mTemp;
|
|
}
|
|
|
|
if (line[i + 1] != '"')
|
|
{
|
|
mTemp.Add(line.Substring(wordStart, i - wordStart).Replace("\"\"", "\""));
|
|
insideQuotes = false;
|
|
|
|
if (line[i + 1] == ',')
|
|
{
|
|
++i;
|
|
wordStart = i + 1;
|
|
}
|
|
}
|
|
else ++i;
|
|
}
|
|
else
|
|
{
|
|
wordStart = i + 1;
|
|
insideQuotes = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wordStart < line.Length)
|
|
{
|
|
if (insideQuotes) continue;
|
|
mTemp.Add(line.Substring(wordStart, line.Length - wordStart));
|
|
}
|
|
return mTemp;
|
|
}
|
|
return null;
|
|
}
|
|
}
|