namespace SHNDecrypt { using System; using System.Collections.Generic; using System.Data; using System.Globalization; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; public class SHNFile { private uint ColumnCount; private int[] ColumnLengths; private string[] ColumnNames; public List columns; private uint[] ColumnTypes; public byte[] CryptHeader; public byte[] data; private uint DefaultRecordLength; public Dictionary displayToReal; public uint Header; public bool isTextData; public string Path; private uint RecordCount; public DataTable table; public SHNFile() { this.table = new DataTable(); this.displayToReal = new Dictionary(); this.columns = new List(); } public SHNFile(string path) { this.table = new DataTable(); this.displayToReal = new Dictionary(); this.columns = new List(); try { BinaryReaderEx ex; this.columns.Clear(); this.Path = path; if (System.IO.Path.GetFileNameWithoutExtension(path).ToLower().Contains("textdata")) { this.isTextData = true; } using (ex = new BinaryReaderEx(File.OpenRead(path))) { if (path.EndsWith(".shn")) { this.CryptHeader = ex.ReadBytes(0x20); this.data = ex.ReadBytes(ex.ReadInt32() - 0x24); } else { this.data = ex.ReadBytes((int) ex.Length); } } this.Decrypt(this.data, 0, this.data.Length - 0x24); ex = new BinaryReaderEx(new MemoryStream(this.data)); this.Header = ex.ReadUInt32(); this.RecordCount = ex.ReadUInt32(); this.DefaultRecordLength = ex.ReadUInt32(); this.ColumnCount = ex.ReadUInt32(); this.ColumnNames = new string[this.ColumnCount]; this.ColumnTypes = new uint[this.ColumnCount]; this.ColumnLengths = new int[this.ColumnCount]; int num = 2; int num2 = 0; for (uint i = 0; i < this.ColumnCount; i++) { string str = ex.ReadString(0x30); uint num4 = ex.ReadUInt32(); int num5 = ex.ReadInt32(); SHNColumn item = new SHNColumn(); if ((str.Length == 0) || string.IsNullOrWhiteSpace(str)) { str = "UnkCol" + num2.ToString(); num2++; } item.name = str; item.Type = num4; item.Lenght = num5; this.columns.Add(item); this.ColumnNames[i] = str; this.ColumnTypes[i] = num4; this.ColumnLengths[i] = num5; num += num5; } if (num != this.DefaultRecordLength) { throw new Exception("Wrong record length!"); } this.GenerateColumns(this.table, this.columns); this.ReadRows(ex, this.table); } catch (Exception) { } } public void CreateColumn(string name, int len, uint type, string defaultval) { SHNColumn item = new SHNColumn { name = name, Lenght = len, Type = type }; this.columns.Add(item); DataColumn column = new DataColumn { ColumnName = name, DefaultValue = defaultval, DataType = this.GetType(item) }; this.table.Columns.Add(column); } public void CreateDefaultLayout() { this.CryptHeader = new byte[0x20]; this.SetCryptHeader("3B 02 00 00 32 30 30 35 2D 30 38 2D 32 36 20 BF C0 C8 C4 20 32 3A 33 00 6A 7F 00 00 01 00 00 00"); this.Header = 0; this.CreateColumn("Empty Column", 0xff, 0x18, ""); this.Path = "New File.shn"; } public void CreateSQL(out string Output, bool drop) { Output = string.Empty; string name = "data_" + System.IO.Path.GetFileNameWithoutExtension(this.Path); Output = Output + SQLConv.CreateHeader(name, drop) + "\r\n"; for (int i = 0; i < this.table.Columns.Count; i++) { string str2 = ""; string str6 = str2; str2 = str6 + "`" + this.table.Columns[i].Caption + "` " + SQLConv.GetSQLType(this.table.Columns[i].DataType); if ((i + 1) != this.table.Columns.Count) { str2 = str2 + ","; } str2 = str2 + "\r\n"; Output = Output + str2; } Output = Output + "); \r\n\r\n"; int num2 = 0; int count = 0x7d0; if (this.table.Rows.Count < 0x7d0) { count = this.table.Rows.Count; } while (num2 < (this.table.Rows.Count - 1)) { Output = Output + SQLConv.InsterInto(name, this.table.Columns); int num4 = this.table.Columns.Count; for (int j = num2; j < (count + num2); j++) { string str3 = "("; for (int k = 0; k < num4; k++) { string prefix = SQLConv.GetPrefix(this.table.Columns[k].DataType); string str5 = Convert.ToString(this.table.Rows[j][k]).Replace("'", @"\'"); str3 = str3 + prefix + str5 + prefix; if ((k + 1) != num4) { str3 = str3 + ","; } } str3 = str3 + ")"; if ((j + 1) != (count + num2)) { str3 = str3 + ","; } else { str3 = str3 + ";"; } Output = Output + str3 + "\r\n"; } num2 += count; if ((this.table.Rows.Count - num2) < 0x7d0) { count = this.table.Rows.Count - num2; } } } private void Decrypt(byte[] data, int index, int length) { if (((index < 0) | (length < 1)) | ((index + length) > data.Length)) { throw new IndexOutOfRangeException(); } byte num = (byte) length; for (int i = length - 1; i >= 0; i--) { data[i] = (byte) (data[i] ^ num); byte num3 = (byte) i; num3 = (byte) (num3 & 15); num3 = (byte) (num3 & 0x55); num3 = (byte) (num3 ^ ((byte) (((byte) i) * 11))); num3 = (byte) (num3 ^ num); num3 = (byte) (num3 ^ 170); num = num3; } } public void DeleteColumn(string name) { this.columns.Remove(this.GetColByName(name)); this.table.Columns.Remove(this.GetDataColByName(name)); } public void Dispose() { this.table = null; this.CryptHeader = null; } public void EditColumnName(string from, string to) { this.GetDataColByName(from).ColumnName = to; this.GetColByName(from).name = to; } public void exportCVS(string path) { TextWriter writer = new StreamWriter(path); foreach (DataColumn column in this.table.Columns) { SHNColumn colByName = this.GetColByName(column.ColumnName); writer.Write(colByName.name + ", "); } writer.Write(writer.NewLine); foreach (DataRow row in this.table.Rows) { for (int i = 0; i < this.table.Columns.Count; i++) { string source = row[i].ToString(); if (source.Contains('"')) { source = source.Replace('"', ' '); } writer.Write("\"" + source + "\""); if ((i + 1) == this.table.Columns.Count) { writer.Write(writer.NewLine); } else { writer.Write(','); } } } writer.Close(); } private void GenerateColumns(DataTable table, List cols) { for (int i = 0; i < cols.Count; i++) { DataColumn column = new DataColumn { ColumnName = cols[i].name, DataType = this.GetType(cols[i]) }; table.Columns.Add(column); } } public SHNColumn GetColByName(string name) { foreach (SHNColumn column in this.columns) { if (column.name.ToLower() == name.ToLower()) { return column; } } return null; } public int getColIndex(string name) { for (int i = 0; i < this.table.Columns.Count; i++) { if (this.table.Columns[i].ColumnName == name) { return i; } } return -1; } public string GetCryptString() { string str = ""; for (int i = 0; i < this.CryptHeader.Length; i++) { if (i != (this.CryptHeader.Length - 1)) { str = str + this.CryptHeader[i].ToString("X2") + " "; } else { str = str + this.CryptHeader[i].ToString("X2"); } } return str; } public DataColumn GetDataColByName(string name) { for (int i = 0; i < this.table.Columns.Count; i++) { if (this.table.Columns[i].ColumnName == name) { return this.table.Columns[i]; } } return null; } public uint GetDefaultRecLen() { uint num = 2; foreach (DataColumn column in this.table.Columns) { SHNColumn colByName = this.GetColByName(column.ColumnName); num += (uint) colByName.Lenght; } return num; } public int GetRowByIndex(int ColIndex, string RowInput) { for (int i = 0; i < this.table.Rows.Count; i++) { if (this.table.Rows[i][ColIndex].ToString().ToLower() == RowInput.ToLower()) { return i; } } return -1; } public System.Type GetType(SHNColumn col) { switch (col.Type) { case 1: case 12: return typeof(byte); case 2: return typeof(ushort); case 3: case 11: return typeof(uint); case 5: return typeof(float); case 9: case 0x18: case 0x1a: return typeof(string); case 13: case 0x15: return typeof(short); case 0x10: return typeof(byte); case 0x11: return typeof(string); case 0x12: case 0x1b: return typeof(uint); case 20: return typeof(sbyte); case 0x16: return typeof(int); } return typeof(object); } public void LoadMe(string path) { BinaryReaderEx ex = new BinaryReaderEx(File.OpenRead(path)); if (path.EndsWith(".shn")) { this.CryptHeader = ex.ReadBytes(0x20); this.data = ex.ReadBytes(ex.ReadInt32() - 0x48); } else { this.data = ex.ReadBytes((int) ex.Length); } ex.Close(); this.Decrypt(this.data, 0, this.data.Length); } private void ReadRows(BinaryReaderEx r, DataTable table) { object[] values = new object[this.columns.Count]; for (uint i = 0; i < this.RecordCount; i++) { r.ReadUInt16(); for (int j = 0; j < this.columns.Count; j++) { switch (this.columns[j].Type) { case 1: values[j] = r.ReadByte(); break; case 2: values[j] = r.ReadUInt16(); break; case 3: values[j] = r.ReadUInt32(); break; case 5: values[j] = r.ReadSingle(); break; case 9: values[j] = r.ReadString(this.ColumnLengths[j]); break; case 11: values[j] = r.ReadUInt32(); break; case 12: values[j] = r.ReadByte(); break; case 13: values[j] = r.ReadInt16(); break; case 0x10: values[j] = r.ReadByte(); break; case 0x11: values[j] = r.ReadString(0x20); break; case 0x12: values[j] = r.ReadUInt32(); break; case 20: values[j] = r.ReadSByte(); break; case 0x15: values[j] = r.ReadInt16(); break; case 0x16: values[j] = r.ReadInt32(); break; case 0x18: values[j] = r.ReadString(this.ColumnLengths[j]); break; case 0x1a: values[j] = r.ReadString(); break; case 0x1b: values[j] = r.ReadUInt32(); break; } } table.Rows.Add(values); } } public bool Save(string file) { MemoryStream output = new MemoryStream(); BinaryWriter w = new BinaryWriter(output); try { w.Write(this.Header); w.Write(this.table.Rows.Count); w.Write(this.GetDefaultRecLen()); w.Write(this.table.Columns.Count); for (int i = 0; i < this.table.Columns.Count; i++) { SHNColumn colByName = this.GetColByName(this.table.Columns[this.displayToReal[i]].ColumnName); if (colByName.name.Contains("UnkCol")) { w.Write(new byte[0x30]); } else { this.WriteString(w, colByName.name, 0x30); } w.Write(colByName.Type); w.Write(colByName.Lenght); } this.WriteRows(w); byte[] sourceArray = output.GetBuffer(); long length = output.Length; byte[] destinationArray = new byte[length]; Array.Copy(sourceArray, destinationArray, length); this.Decrypt(destinationArray, 0, destinationArray.Length - 0x24); w.Close(); w = new BinaryWriter(File.Create(file)); w.Write(this.CryptHeader); w.Write((int) (destinationArray.Length + 0x24)); w.Write(destinationArray); w.Close(); this.Path = file; return true; } catch (Exception exception) { w.Close(); MessageBox.Show("Could not save file: " + exception.Message, "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return false; } } public void SetCryptHeader(string hexString) { string[] strArray = hexString.Split(new char[] { ' ' }); if (strArray.Length != 0x20) { throw new Exception("Incorrect header length!"); } for (int i = 0; i < strArray.Length; i++) { this.CryptHeader[i] = byte.Parse(strArray[i], NumberStyles.HexNumber); } } private void WriteRows(BinaryWriter w) { for (int i = 0; i < this.table.Rows.Count; i++) { DataRow row = this.table.Rows[i]; long position = w.BaseStream.Position; w.Write((ushort) 0); for (int j = 0; j < this.table.Columns.Count; j++) { object obj2 = row.ItemArray[this.displayToReal[j]]; if (obj2 == null) { obj2 = "0"; } SHNColumn colByName = this.GetColByName(this.table.Columns[this.displayToReal[j]].ColumnName); switch (colByName.Type) { case 1: { if (obj2 is string) { obj2 = byte.Parse((string) obj2); } w.Write((byte) obj2); continue; } case 2: { if (obj2 is string) { obj2 = ushort.Parse((string) obj2); } w.Write((ushort) obj2); continue; } case 3: { if (obj2 is string) { obj2 = uint.Parse((string) obj2); } w.Write((uint) obj2); continue; } case 4: case 6: case 7: case 8: case 10: case 14: case 15: case 0x13: case 0x17: case 0x19: { continue; } case 5: { if (obj2 is string) { obj2 = float.Parse((string) obj2); } w.Write((float) obj2); continue; } case 9: { if (!string.IsNullOrWhiteSpace(obj2.ToString())) { break; } this.WriteString(w, obj2.ToString(), colByName.Lenght); continue; } case 11: { if (obj2 is string) { obj2 = uint.Parse((string) obj2); } w.Write((uint) obj2); continue; } case 12: { if (obj2 is string) { obj2 = byte.Parse((string) obj2); } w.Write((byte) obj2); continue; } case 13: { if (obj2 is string) { obj2 = short.Parse((string) obj2); } w.Write((short) obj2); continue; } case 0x10: { if (obj2 is string) { obj2 = byte.Parse((string) obj2); } w.Write((byte) obj2); continue; } case 0x11: { this.WriteString(w, (string) obj2, 0x20); continue; } case 0x12: { if (obj2 is string) { obj2 = uint.Parse((string) obj2); } w.Write((uint) obj2); continue; } case 20: { if (obj2 is string) { obj2 = sbyte.Parse((string) obj2); } w.Write((sbyte) obj2); continue; } case 0x15: { if (obj2 is string) { obj2 = short.Parse((string) obj2); } w.Write((short) obj2); continue; } case 0x16: { if (obj2 is string) { obj2 = int.Parse((string) obj2); } w.Write((int) obj2); continue; } case 0x18: { this.WriteString(w, (string) obj2, colByName.Lenght); continue; } case 0x1a: { this.WriteString(w, (string) obj2, -1); continue; } case 0x1b: { if (obj2 is string) { obj2 = uint.Parse((string) obj2); } w.Write((uint) obj2); continue; } default: { continue; } } this.WriteString(w, (string) obj2, colByName.Lenght); } long num4 = w.BaseStream.Position - position; long offset = w.BaseStream.Position; w.BaseStream.Seek(position, SeekOrigin.Begin); w.Write((ushort) num4); w.BaseStream.Seek(offset, SeekOrigin.Begin); } } private void WriteString(BinaryWriter w, string s, int length) { byte[] bytes = Encoding.GetEncoding(Program.eT).GetBytes(s); if (length == -1) { w.Write(bytes); w.Write((byte) 0); } else { byte[] destinationArray = new byte[length]; Array.Copy(bytes, destinationArray, Math.Min(length, bytes.Length)); w.Write(destinationArray); } } } }