using System; using System.Text; using System.Linq; using System.Collections.Generic; using LitJson; using Newtonsoft.Json.Linq; namespace Sog { public class TabBinFile { private string FileName; private string[] Titles; private string[] Types; private Dictionary m_titleIndex; private int LineLength; private int LineCount; private int[] LinePosList; private int[] ColPosList; private int ColCount; private byte[] m_bodyBlock; // 除去头部的两行的 content; private List m_stringBlock; private string m_splitFlag = "*$*"; private int headerLength; private int CurrentColIndex = 0; public int CurrentLine { get; private set; } public TabBinFile(string strFileName, byte[] content) { FileName = strFileName; GetHeader(content); int bodyLen = LineCount * LineLength; m_bodyBlock = content.Skip(4 + headerLength).Take(bodyLen).ToArray(); m_stringBlock = content.Skip(4 + headerLength + bodyLen).Take(content.Length - (4 + headerLength + bodyLen)) .ToArray().ToList(); ColCount = Titles.Length; SetPos(); Begin(); } public void Begin() { CurrentLine = -1; } public bool Next() { CurrentLine++; if (CurrentLine >= LineCount) return false; return true; } public void SetCurrentLine(int currentLine) { CurrentLine = currentLine; } public void SetCurrentCol(int currentCol) { CurrentColIndex = currentCol; } private void SetPos() { int position = 0; int flag = 0; if (ColPosList == null) { ColPosList = new int[Titles.Length]; } foreach (var item in Types) { ColPosList[flag] = position; switch (item) { case "int": case "uint": case "uint_key": case "int_group": case "int_key": position += 4; flag++; break; case "long": position += 8; flag++; break; case "string": case "json": case "array": case "string_lan": case "string_key": // 先长度后位置 position += 4; position += 4; flag++; break; default: break; } } if (LinePosList == null) { LinePosList = new int[LineCount]; } for (int i = 0; i < LineCount; i++) { LinePosList[i] = i * LineLength; } } private void GetHeader(byte[] content) { int titlesLen = (int)((content[0] & 0xFF) | ((content[1] & 0xFF) << 8) | ((content[2] & 0xFF) << 16) | ((content[3] & 0xFF) << 24)); headerLength += 4; byte[] titles = content.Skip(headerLength).Take(titlesLen).ToArray(); headerLength += titlesLen; string strTitle = Encoding.UTF8.GetString(titles); Titles = strTitle.Split(m_splitFlag.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (m_titleIndex == null) { m_titleIndex = new Dictionary(); for (int i = 0; i < Titles.Count(); i++) { m_titleIndex.Add(Titles[i], i); } } int typesLen = (int)((content[headerLength] & 0xFF) | ((content[headerLength + 1] & 0xFF) << 8) | ((content[headerLength + 2] & 0xFF) << 16) | ((content[headerLength + 3] & 0xFF) << 24)); headerLength += 4; byte[] types = content.Skip(headerLength).Take(typesLen).ToArray(); headerLength += typesLen; string strTypes = Encoding.UTF8.GetString(types); Types = strTypes.Split(m_splitFlag.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); LineLength = (int)((content[headerLength] & 0xFF) | ((content[headerLength + 1] & 0xFF) << 8) | ((content[headerLength + 2] & 0xFF) << 16) | ((content[headerLength + 3] & 0xFF) << 24)); headerLength += 4; LineCount = (int)((content[headerLength] & 0xFF) | ((content[headerLength + 1] & 0xFF) << 8) | ((content[headerLength + 2] & 0xFF) << 16) | ((content[headerLength + 3] & 0xFF) << 24)); } public uint GetuintByIndex(string key = null) { int colIndex = CurrentColIndex; if (key != null) { if (!m_titleIndex.ContainsKey(key)) { return 0; } colIndex = m_titleIndex[key]; } int valuePos = ColPosList[colIndex] + LinePosList[CurrentLine]; if (CurrentColIndex >= ColCount - 1) { CurrentColIndex = 0; } else { CurrentColIndex++; } return (uint)((m_bodyBlock[valuePos] & 0xFF) | ((m_bodyBlock[valuePos + 1] & 0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & 0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & 0xFF) << 24)); } public int GetintByIndex(string key = null) { int colIndex = CurrentColIndex; if (key != null) { if (!m_titleIndex.ContainsKey(key)) { return 0; } colIndex = m_titleIndex[key]; } int valuePos = ColPosList[colIndex] + LinePosList[CurrentLine]; if (CurrentColIndex >= ColCount - 1) { CurrentColIndex = 0; } else { CurrentColIndex++; } return (int)((m_bodyBlock[valuePos] & 0xFF) | ((m_bodyBlock[valuePos + 1] & 0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & 0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & 0xFF) << 24)); } public long GetlongByIndex(string key = null) { int colIndex = CurrentColIndex; if (key != null) { if (!m_titleIndex.ContainsKey(key)) { return 0; } colIndex = m_titleIndex[key]; } int valuePos = ColPosList[colIndex] + LinePosList[CurrentLine]; if (CurrentColIndex >= ColCount - 1) { CurrentColIndex = 0; } else { CurrentColIndex++; } return (long)((m_bodyBlock[valuePos] & (long)0xFF) | ((m_bodyBlock[valuePos + 1] & (long)0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & (long)0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & (long)0xFF) << 24) | ((m_bodyBlock[valuePos + 4] & (long)0xFF) << 32) | ((m_bodyBlock[valuePos + 5] & (long)0xFF) << 40) | ((m_bodyBlock[valuePos + 6] & (long)0xFF) << 48) | ((m_bodyBlock[valuePos + 7] & (long)0xFF) << 56)); } public long[] GetlongArrayByIndex(string key = null) { int colIndex = CurrentColIndex; if (key != null) { if (!m_titleIndex.ContainsKey(key)) { return Array.Empty(); } colIndex = m_titleIndex[key]; } int valuePos = ColPosList[colIndex] + LinePosList[CurrentLine]; int strlen = (int)((m_bodyBlock[valuePos] & 0xFF) | ((m_bodyBlock[valuePos + 1] & 0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & 0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & 0xFF) << 24)); valuePos += 4; int strpos = (int)((m_bodyBlock[valuePos] & 0xFF) | ((m_bodyBlock[valuePos + 1] & 0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & 0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & 0xFF) << 24)); if (CurrentColIndex >= ColCount - 1) { CurrentColIndex = 0; } else { CurrentColIndex++; } var bytes = m_stringBlock.Skip(strpos).Take(strlen).ToArray(); var length = bytes.Length / 8; var result = new long[length]; for (var i = 0; i < length; i++) { long value = 0; value |= ((long)bytes[i * 8 + 0] & 0xFF); value |= ((long)bytes[i * 8 + 1] & 0xFF) << 8; value |= ((long)bytes[i * 8 + 2] & 0xFF) << 16; value |= ((long)bytes[i * 8 + 3] & 0xFF) << 24; value |= ((long)bytes[i * 8 + 4] & 0xFF) << 32; value |= ((long)bytes[i * 8 + 5] & 0xFF) << 40; value |= ((long)bytes[i * 8 + 6] & 0xFF) << 48; value |= ((long)bytes[i * 8 + 7] & 0xFF) << 56; result[i] = value; } return result; } public int[] GetintArrayByIndex(string key = null) { int colIndex = CurrentColIndex; if (key != null) { if (!m_titleIndex.ContainsKey(key)) { return Array.Empty(); } colIndex = m_titleIndex[key]; } int valuePos = ColPosList[colIndex] + LinePosList[CurrentLine]; int strlen = (int)((m_bodyBlock[valuePos] & 0xFF) | ((m_bodyBlock[valuePos + 1] & 0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & 0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & 0xFF) << 24)); valuePos += 4; int strpos = (int)((m_bodyBlock[valuePos] & 0xFF) | ((m_bodyBlock[valuePos + 1] & 0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & 0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & 0xFF) << 24)); if (CurrentColIndex >= ColCount - 1) { CurrentColIndex = 0; } else { CurrentColIndex++; } var bytes = m_stringBlock.Skip(strpos).Take(strlen).ToArray(); int length = bytes.Length / 4; var result = new int[length]; for (int i = 0; i < length; i++) { int value = 0; value |= (bytes[i * 4 + 0] & 0xFF); value |= (bytes[i * 4 + 1] & 0xFF) << 8; value |= (bytes[i * 4 + 2] & 0xFF) << 16; value |= (bytes[i * 4 + 3] & 0xFF) << 24; result[i] = value; } return result; } public uint[] GetuintArrayByIndex(string key = null) { int colIndex = CurrentColIndex; if (key != null) { if (!m_titleIndex.ContainsKey(key)) { return Array.Empty(); } colIndex = m_titleIndex[key]; } int valuePos = ColPosList[colIndex] + LinePosList[CurrentLine]; int strlen = (int)((m_bodyBlock[valuePos] & 0xFF) | ((m_bodyBlock[valuePos + 1] & 0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & 0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & 0xFF) << 24)); valuePos += 4; int strpos = (int)((m_bodyBlock[valuePos] & 0xFF) | ((m_bodyBlock[valuePos + 1] & 0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & 0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & 0xFF) << 24)); if (CurrentColIndex >= ColCount - 1) { CurrentColIndex = 0; } else { CurrentColIndex++; } var bytes = m_stringBlock.Skip(strpos).Take(strlen).ToArray(); int length = bytes.Length / 4; var result = new uint[length]; for (int i = 0; i < length; i++) { uint value = 0; value |= ((uint)bytes[i * 4 + 0] & 0xFF); value |= ((uint)bytes[i * 4 + 1] & 0xFF) << 8; value |= ((uint)bytes[i * 4 + 2] & 0xFF) << 16; value |= ((uint)bytes[i * 4 + 3] & 0xFF) << 24; result[i] = value; } return result; } public string GetstringByIndex(string key = null) { int colIndex = CurrentColIndex; if (key != null) { if (!m_titleIndex.ContainsKey(key)) { return ""; } colIndex = m_titleIndex[key]; } int valuePos = ColPosList[colIndex] + LinePosList[CurrentLine]; int strlen = (int)((m_bodyBlock[valuePos] & 0xFF) | ((m_bodyBlock[valuePos + 1] & 0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & 0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & 0xFF) << 24)); valuePos += 4; int strpos = (int)((m_bodyBlock[valuePos] & 0xFF) | ((m_bodyBlock[valuePos + 1] & 0xFF) << 8) | ((m_bodyBlock[valuePos + 2] & 0xFF) << 16) | ((m_bodyBlock[valuePos + 3] & 0xFF) << 24)); if (CurrentColIndex >= ColCount - 1) { CurrentColIndex = 0; } else { CurrentColIndex++; } return GetParseStringPos(strlen, strpos); } public string[] GetstringArrayByIndex(string key = null) { var str = GetstringByIndex(key); if (string.IsNullOrEmpty(str) || str.Equals("0")) { return Array.Empty(); } var arr = new string[str.Length / 2 + 1]; var validCount = 0; var sb = new StringBuilder(); foreach (var c in str) { if (c == ';') { if (sb.Length > 0) { arr[validCount++] = sb.ToString(); sb.Clear(); } else { arr[validCount++] = ""; sb.Clear(); } } else { sb.Append(c); } } if (sb.Length > 0) { arr[validCount++] = sb.ToString(); } var ret = new string[validCount]; for (var i = 0; i < validCount; i++) { ret[i] = arr[i]; } return ret; } public JObject GetJObjectByIndex(string key = null) { var str = GetstringByIndex(key); if (string.IsNullOrEmpty(str)||string.IsNullOrEmpty(str.Trim())) { return null; } return JObject.Parse(str); } public JArray GetJArrayByIndex(string key = null) { var str = GetstringByIndex(key); if (string.IsNullOrEmpty(str)) { return null; } return JArray.Parse(str); } private string GetParseStringPos(int strLen, int postion) { return Encoding.UTF8.GetString(m_stringBlock.Skip(postion).Take(strLen).ToArray()); } private int FromBinaryToInt(byte[] binaryBits, int offset = 0) { int value; value = (int)((binaryBits[offset] & 0xFF) | ((binaryBits[offset + 1] & 0xFF) << 8) | ((binaryBits[offset + 2] & 0xFF) << 16) | ((binaryBits[offset + 3] & 0xFF) << 24)); return value; } private long FromBinaryToLong(byte[] binaryBits, int offset = 0) { long value; value = (long)((binaryBits[offset] & (long)0xFF) | ((binaryBits[offset + 1] & (long)0xFF) << 8) | ((binaryBits[offset + 2] & (long)0xFF) << 16) | ((binaryBits[offset + 3] & (long)0xFF) << 24) | ((binaryBits[offset + 4] & (long)0xFF) << 32) | ((binaryBits[offset + 5] & (long)0xFF) << 40) | ((binaryBits[offset + 6] & (long)0xFF) << 48) | ((binaryBits[offset + 7] & (long)0xFF) << 56)); return value; } public uint Getuint(string strColName) { int nColIndex = Array.IndexOf(Titles, strColName); if (nColIndex < 0) { TraceLog.Error("TabBinFile: read data error, file:{0}, colName:{1}", FileName, strColName); return 0; } int valuePos = ColPosList[nColIndex] + LinePosList[CurrentLine]; return (uint)FromBinaryToInt(m_bodyBlock.Skip(valuePos).Take(4).ToArray()); } public int Getint(string strColName) { int nColIndex = Array.IndexOf(Titles, strColName); if (nColIndex < 0) { TraceLog.Error("TabBinFile: read data error, file:{0}, colName:{1}", FileName, strColName); return 0; } int valuePos = ColPosList[nColIndex] + LinePosList[CurrentLine]; return FromBinaryToInt(m_bodyBlock.Skip(valuePos).Take(4).ToArray()); } public long Getlong(string strColName) { int nColIndex = Array.IndexOf(Titles, strColName); if (nColIndex < 0) { TraceLog.Error("TabBinFile: read data error, file:{0}, colName:{1}", FileName, strColName); return 0; } int valuePos = ColPosList[nColIndex] + LinePosList[CurrentLine]; return FromBinaryToInt(m_bodyBlock.Skip(valuePos).Take(8).ToArray()); } public string Getstring(string strColName) { int nColIndex = Array.IndexOf(Titles, strColName); if (nColIndex < 0) { TraceLog.Error("TabBinFile: read data error, file:{0}, colName:{1}", FileName, strColName); return ""; } int valuePos = ColPosList[nColIndex] + LinePosList[CurrentLine]; int strlen = FromBinaryToInt(m_bodyBlock.Skip(valuePos).Take(4).ToArray()); valuePos += 4; int strpos = FromBinaryToInt(m_bodyBlock.Skip(valuePos).Take(4).ToArray()); return GetParseStringPos(strlen, strpos); } } }