public XmlCookedElement(XmlCookedAttribute xmlAttribute, ObjectDelegator.FieldDelegate fieldDelegate) { XmlAttribute = xmlAttribute; FieldDelegate = fieldDelegate; }
public static ObjectDelegator GetExcelDelegator(DataFile excelFile, IDictionary<String, ObjectDelegator> objectDelegators) { ObjectDelegator excelDelegator; if (!objectDelegators.TryGetValue(excelFile.StringId, out excelDelegator)) { Type rowType = excelFile.Attributes.RowType; FieldInfo[] fieldInfos = rowType.GetFields(); excelDelegator = new ObjectDelegator(fieldInfos); objectDelegators.Add(excelFile.StringId, excelDelegator); } return excelDelegator; }
public static void TestAllCodeValues() { FileManager fileManager = new FileManager(Config.HglDir); fileManager.LoadTableFiles(); int fileCountWithCode = 0; foreach (DataFile dataFile in fileManager.DataFiles.Values) { if (!dataFile.IsExcelFile) continue; ExcelFile excelFile = (ExcelFile)dataFile; Debug.Write(String.Format("Checking code fields within file {0}... ", excelFile.StringId)); FieldInfo[] fieldInfos = excelFile.Attributes.RowType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo[] codeFields = (from fi in fieldInfos where fi.Name == "code" select fi).ToArray(); if (codeFields.Length == 0) { Debug.WriteLine("None found."); continue; } //if (excelFile.StringId == "ACT") //{ // int bp = 0; // ExcelFile.Code codeObj = new ExcelFile.Code(); // codeObj = "AAB"; // int codeInt = codeObj; //} Debug.Assert(codeFields.Length == 1); Debug.WriteLine(String.Format("{0} fields found.", codeFields.Length)); fileCountWithCode++; ObjectDelegator objectDelegator = new ObjectDelegator(codeFields); Debug.WriteLine("Codes found: "); foreach (FieldInfo fieldInfo in codeFields) { foreach (Object row in excelFile.Rows) { int code = 0; if (fieldInfo.FieldType == typeof(short)) { code = (int)(short)objectDelegator["code"](row); } //else if (fieldInfo.FieldType == typeof(ExcelFile.Code)) //{ // code = (ExcelFile.Code)objectDelegator["code"](row); //} //else if (fieldInfo.FieldType == typeof(ExcelFile.ShortCode)) //{ // code = (ExcelFile.ShortCode)objectDelegator["code"](row); //} else { code = (int)objectDelegator["code"](row); } if (code == 0) continue; char char1 = (char)(code & 0xFF); char char2 = (char)((code & 0xFF00) >> 8); char char3 = (char)((code & 0xFF0000) >> 16); char char4 = (char)((code & 0xFF000000) >> 24); Debug.Assert(_CharCodeCharValue(char1)); Debug.Assert(_CharCodeCharValue(char2)); Debug.Assert(_CharCodeCharValue(char3)); Debug.Assert(_CharCodeCharValue(char4)); Debug.Write(String.Format(" {0}{1}{2}{3}", char1, char2, char3, char4)); } } Debug.WriteLine(""); } Debug.WriteLine(String.Format("{0} files with code fields checked.", fileCountWithCode)); }
/// <summary> /// Function to conver the TCv4 excel files to SP client formats. /// </summary> public static void ConvertTCv4ExcelToSP() { // init file manager and load excel files FileManager fileManager = new FileManager(Config.HglDir); fileManager.ExtractAllExcel(); FileManager fileManagerTCv4 = new FileManager(Config.HglDir, FileManager.ClientVersions.TestCenter); fileManager.LoadTableFiles(); fileManagerTCv4.LoadTableFiles(true); if (fileManager.DataFiles.Count == 0) { Debug.WriteLine("Error: No Excel files loaded!"); return; } if (fileManagerTCv4.DataFiles.Count == 0) { Debug.WriteLine("Error: No TCv4 Excel files loaded!"); return; } // convert tables //int converted = -1; Dictionary<String, ObjectDelegator> objectDelegators = new Dictionary<String, ObjectDelegator>(); foreach (ExcelFile excelFile in fileManager.DataFiles.Values.Where(dataFile => dataFile.IsExcelFile)) { //if (++converted >= 5) break; Debug.WriteLine("Converting Excel table " + excelFile.StringId + "..."); // obviously don't want to convert this one if (excelFile.StringId == "EXCELTABLES") continue; // we can't convert stats as some index entries are hard-coded... if (excelFile.StringId == "STATS") continue; // game crashes with this converted... if (excelFile.StringId == "UNITMODES") continue; // don't bother with these two as there's no TCv4 equivalent (they don't matter anyways) if (excelFile.StringId == "LANGUAGE" || excelFile.StringId == "REGION") continue; // ensure we have a TCv4 version loaded String stringIdTCv4 = "_TCv4_" + excelFile.StringId; ExcelFile excelFileTCv4 = (ExcelFile)fileManagerTCv4.GetDataFile(stringIdTCv4); if (excelFileTCv4 == null) { Debug.WriteLine("Error: TCv4 Excel file not found: " + stringIdTCv4); continue; } // table specialisation stuffs bool isAchievements = false; bool isAffixes = false; bool isCharacterClass = false; //bool isCharDisplay = false; //bool isInventory = false; switch (excelFile.StringId) { case "ACHIEVEMENTS": isAchievements = true; break; case "AFFIXES": isAffixes = true; break; case "CHARACTER_CLASS": isCharacterClass = true; break; //case "CHARDISPLAY": // isCharDisplay = true; // break; //case "INVENTORY": // isInventory = true; // break; } // genereal type-init stuffs; get our object delegators ObjectDelegator excelDelegator; ObjectDelegator excelDelegatorTCv41; ObjectDelegator excelDelegatorTCv42 = null; Type rowType = excelFile.Attributes.RowType; Type rowTypeTCv41 = excelFileTCv4.Attributes.RowType; Type rowTypeTCv42 = null; FieldInfo[] fieldInfos = rowType.GetFields(); FieldInfo[] fieldInfosTCv41 = rowTypeTCv41.GetFields(); FieldInfo[] fieldInfosTCv42 = null; // need to copy row headers (private field) as well FieldInfo rowHeaderField = rowType.GetField("header", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo rowHeaderFieldTCv4 = rowTypeTCv41.GetField("header", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Array.Resize(ref fieldInfos, fieldInfos.Length + 1); Array.Resize(ref fieldInfosTCv41, fieldInfosTCv41.Length + 1); fieldInfos[fieldInfos.Length - 1] = rowHeaderField; fieldInfosTCv41[fieldInfosTCv41.Length - 1] = rowHeaderFieldTCv4; // create delegates if (!objectDelegators.TryGetValue(excelFile.StringId, out excelDelegator)) { excelDelegator = new ObjectDelegator(fieldInfos); objectDelegators.Add(excelFile.StringId, excelDelegator); } if (!objectDelegators.TryGetValue(stringIdTCv4, out excelDelegatorTCv41)) { excelDelegatorTCv41 = new ObjectDelegator(fieldInfosTCv41); objectDelegators.Add(stringIdTCv4, excelDelegatorTCv41); } // table specialisation inititialisation //// achievements Dictionary<int, int> unitTypeOverflow = null; if (isAchievements) { unitTypeOverflow = new Dictionary<int, int>(); } //// affixes ExcelFile affixGroupsTable = null; List<String> affixGroupsList = null; List<Int32> affixGroupWeightScripts = null; if (isAffixes) { affixGroupsTable = fileManagerTCv4.GetDataFile("_TCv4_AFFIX_GROUPS") as ExcelFile; affixGroupsList = new List<String>(); affixGroupWeightScripts = new List<Int32>(); Debug.Assert(affixGroupsTable != null); rowTypeTCv42 = affixGroupsTable.Attributes.RowType; fieldInfosTCv42 = rowTypeTCv42.GetFields(); FieldInfo rowHeaderFieldTCv42 = rowTypeTCv42.GetField("header", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Array.Resize(ref fieldInfosTCv42, fieldInfosTCv42.Length + 1); fieldInfosTCv42[fieldInfosTCv42.Length - 1] = rowHeaderFieldTCv42; excelDelegatorTCv42 = new ObjectDelegator(fieldInfosTCv42); } // debug: ensure we have same columns if (!isAchievements && !isCharacterClass && !isAffixes) { bool hasSameFields = true; foreach (FieldInfo fieldInfo in fieldInfos) { FieldInfo fieldInfoTCv4 = (from fi in fieldInfosTCv41 where fi.Name == fieldInfo.Name select fi).FirstOrDefault(); if (fieldInfoTCv4 == null) { Debug.WriteLine("Field not found in TCv4 table: " + fieldInfo.Name); hasSameFields = false; continue; } if (fieldInfo.FieldType == fieldInfoTCv4.FieldType || fieldInfo.FieldType.BaseType == typeof(Enum)) continue; Debug.WriteLine(String.Format("FieldInfo '{0}' of type '{1}' does not match TCv4 of type '{2}'", fieldInfo.Name, fieldInfo.FieldType, fieldInfoTCv4.FieldType)); hasSameFields = false; } if (!hasSameFields) { Debug.WriteLine("Error: The Excel types do not have the same fields!"); continue; } } // begin conversion process Object[] rows = new Object[excelFileTCv4.Rows.Count]; bool failed = false; int col = -1; byte[] scriptBuffer = new byte[1024]; int scriptBufferOffset = 1; // first byte is null foreach (FieldInfo fieldInfo in fieldInfos) // loop by column { col++; ObjectDelegator.FieldGetValueDelegate getTCv4Value1 = null; ObjectDelegator.FieldGetValueDelegate getTCv4Value2 = null; ObjectDelegator.FieldGetValueDelegate getTCv4Value3 = null; ObjectDelegator.FieldSetValueDelegate setValue1 = excelDelegator.GetFieldSetDelegate(fieldInfo.Name); ObjectDelegator.FieldSetValueDelegate setValue2 = null; ObjectDelegator.FieldGetValueDelegate getValue = excelDelegator.GetFieldGetDelegate(fieldInfo.Name); ExcelFile.OutputAttribute outputAttribute = ExcelFile.GetExcelAttribute(fieldInfo); // table specialisation stuffs bool isUnitTypeField = false; // achievements bool isItemField = false; // achievements bool isUnitVersionToGetSkillRespec = false; // character class bool isGroup = false; // affixes if (isAchievements && (fieldInfo.Name.StartsWith("unitType") || fieldInfo.Name == "item")) { if (fieldInfo.Name.StartsWith("unitType")) { String monsterFieldName = "monsterUnitType" + fieldInfo.Name.Last(); String itemFieldName = "itemUnitType" + fieldInfo.Name.Last(); getTCv4Value1 = excelDelegatorTCv41.GetFieldGetDelegate(monsterFieldName); getTCv4Value2 = excelDelegatorTCv41.GetFieldGetDelegate(itemFieldName); isUnitTypeField = true; } else if (fieldInfo.Name == "item") { isItemField = true; } } else if (isCharacterClass && fieldInfo.Name == "unitVersionToGetSkillRespec") { isUnitVersionToGetSkillRespec = true; } else if (isAffixes && (fieldInfo.Name == "group" || fieldInfo.Name == "groupWeight")) { if (fieldInfo.Name == "groupWeight") continue; // we can skip it as we're setting it during group column getTCv4Value1 = excelDelegatorTCv41.GetFieldGetDelegate(fieldInfo.Name); // to get group affix index getTCv4Value2 = excelDelegatorTCv42.GetFieldGetDelegate("name"); // to get group affix name getTCv4Value3 = excelDelegatorTCv42.GetFieldGetDelegate("weight"); // to get group affix weight setValue2 = excelDelegator.GetFieldSetDelegate("groupWeight"); // to set group weight isGroup = true; } else { getTCv4Value1 = excelDelegatorTCv41.GetFieldGetDelegate(fieldInfo.Name); } // copy/convert field data int row = -1; foreach (Object rowTCv4 in excelFileTCv4.Rows) // loop by row { if (rows[++row] == null) rows[row] = Activator.CreateInstance(excelFile.Attributes.RowType); Object value; // achievements special stuffs if (isAchievements && (isUnitTypeField || isItemField)) { if (isUnitTypeField) { int monsterValue = (int)getTCv4Value1(rowTCv4); int itemValue = (int)getTCv4Value2(rowTCv4); if (monsterValue != 0 && itemValue != 0) { Debug.Assert(!unitTypeOverflow.ContainsKey(row)); unitTypeOverflow.Add(row, itemValue); itemValue = 0; } else if (monsterValue == 0 && itemValue == 0 && unitTypeOverflow.ContainsKey(row)) { itemValue = unitTypeOverflow[row]; unitTypeOverflow.Remove(row); } value = (itemValue == 0) ? monsterValue : itemValue; } else { value = 0; } } else if (isCharacterClass && isUnitVersionToGetSkillRespec) { value = getValue(excelFile.Rows[row]); } else if (isAffixes && isGroup) { Debug.Assert(getTCv4Value1 != null && getTCv4Value2 != null && getTCv4Value3 != null); int affixGroupRowIndex = (int)getTCv4Value1(rowTCv4); if (affixGroupRowIndex == -1) { setValue2(rows[row], 0); value = -1; } else { int affixGroupStringOffset = (int)getTCv4Value2(affixGroupsTable.Rows[affixGroupRowIndex]); int affixGroupWeight = (int)getTCv4Value3(affixGroupsTable.Rows[affixGroupRowIndex]); setValue2(rows[row], scriptBufferOffset); FileTools.WriteToBuffer(ref scriptBuffer, ref scriptBufferOffset, new[] { (Int32)ExcelScript.ScriptOpCodes.Push, affixGroupWeight, 0 }.ToByteArray()); String affixGroupString = affixGroupsTable.ReadStringTable(affixGroupStringOffset); int affixGroupStringIndex = affixGroupsList.IndexOf(affixGroupString); if (affixGroupStringIndex == -1) { affixGroupStringIndex = affixGroupsList.Count; affixGroupsList.Add(affixGroupString); } value = affixGroupStringIndex; } } else { Debug.Assert(getTCv4Value1 != null); value = getTCv4Value1(rowTCv4); } if (outputAttribute == null) { setValue1(rows[row], value); continue; } if (outputAttribute.IsBitmask) { if (value.GetType().BaseType != typeof(Enum)) { Debug.WriteLine("Error: IsBitmask is not of type Enum: " + fieldInfo.Name); failed = true; break; } Type spBitMask = fieldInfo.FieldType; Type tcBitMask = value.GetType(); uint currentMask = (uint)value; uint convertedMask = 0; for (int i = 0; i < 32; i++) { uint testBit = (uint)1 << i; if ((currentMask & testBit) == 0) continue; String bitString = Enum.GetName(tcBitMask, testBit); if (bitString == null) continue; if (Enum.IsDefined(spBitMask, bitString)) { convertedMask += (uint)Enum.Parse(spBitMask, bitString); } } value = convertedMask; } else if (outputAttribute.IsScript) { //int scriptOffset = (int)value; //if (scriptOffset != 0) //{ // ExcelScript excelScriptTCv4 = new ExcelScript(fileManagerTCv4); // try // { // excelScriptTCv4.Decompile(excelFileTCv4.ScriptBuffer, scriptOffset, null, excelFileTCv4.StringId, row, col, fieldInfo.Name); // } // catch (Exception e) // { // Debug.WriteLine("TCv4 Decompile Error:\n" + e); // continue; // } // ExcelScript excelScriptCompiler = new ExcelScript(fileManagerTCv4, true, true); // try // { // excelScriptCompiler.Compile(excelScriptTCv4.ScriptString, null, excelFileTCv4.StringId, row, col, fieldInfo.Name); // value = scriptBufferOffset; // } // catch (Exceptions.ScriptUnknownFunctionException e) // { // if (isCharDisplay || isInventory) // { // value = 0; // } // else // { // Debug.WriteLine("SP Recompile Error: \n" + excelScriptTCv4.ScriptString + "\n" + e); // value = 0; // //continue; // } // } // catch (Exception e) // { // Debug.WriteLine("SP Recompile Error: \n" + excelScriptTCv4.ScriptString + "\n" + e); // value = 0; // //continue; // } // if ((int)value != 0) // { // FileTools.WriteToBuffer(ref scriptBuffer, ref scriptBufferOffset, excelScriptCompiler.ScriptCode.ToByteArray()); // } //} } setValue1(rows[row], value); } if (failed) break; } if (failed) { Debug.WriteLine("Error: Excel conversion failed: " + excelFile.StringId); continue; } // finish conversion process by "changing" the TCv4 type excelFileTCv4.ConvertType(excelFile, rows); if (scriptBufferOffset != 1) { excelFileTCv4.SetScriptCode(scriptBuffer); } if (isAffixes) { excelFileTCv4.SetSecondaryStringsCollection(affixGroupsList); } byte[] convertedBytes = excelFileTCv4.ToByteArray(); String writePath = Path.Combine(Config.HglDir, excelFile.FilePath); String backupPath = writePath + ".bak"; if (File.Exists(backupPath)) File.Delete(backupPath); File.Move(writePath, backupPath); File.WriteAllBytes(writePath, convertedBytes); //int bp2 = 0; } //int bp1 = 0; }
/// <summary> /// This function checks every row/col of every excel file, determining if it needs to be visible/public or not. /// Any element non-zero for all rows, needs to be public (or add new OutputAttribute for "const" values?) /// </summary> public static void ExcelValuesDeepScan() { FileManager fileManager = new FileManager(Config.HglDir); fileManager.ExtractAllExcel(); Dictionary<uint, uint> rowTypeCounts = new Dictionary<uint, uint>(); Dictionary<String, uint[]> outputMessages = new Dictionary<String, uint[]>(); Dictionary<String, ObjectDelegator> objectDelegators = new Dictionary<String, ObjectDelegator>(); foreach (PackFileEntry fileEntry in fileManager.FileEntries.Values) { if (!fileEntry.Name.EndsWith(ExcelFile.Extension)) continue; byte[] fileBytes = fileManager.GetFileBytes(fileEntry, true); Debug.Assert(fileBytes != null); ExcelFile excelFile = new ExcelFile(fileBytes, fileEntry.Path); if (excelFile.Attributes.IsEmpty) continue; Debug.WriteLine("Checking file: " + fileEntry.Path); uint structureId = excelFile.Attributes.StructureId; uint structureUseCount = 0; if (rowTypeCounts.TryGetValue(structureId, out structureUseCount)) { rowTypeCounts[structureId] = ++structureUseCount; } else { rowTypeCounts.Add(structureId, 1); } ObjectDelegator excelDelegator; Type rowType = excelFile.Attributes.RowType; FieldInfo[] fieldInfos = rowType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); int rowCount = excelFile.Rows.Count; // create delegates if (!objectDelegators.TryGetValue(excelFile.StringId, out excelDelegator)) { excelDelegator = new ObjectDelegator(fieldInfos); objectDelegators.Add(excelFile.StringId, excelDelegator); } // check by column, by row int col = -1; foreach (FieldInfo fieldInfo in fieldInfos) { if (++col == 0) continue; // row header ObjectDelegator.FieldGetValueDelegate getValue = excelDelegator.GetFieldGetDelegate(fieldInfo.Name); ExcelFile.OutputAttribute outputAttribute = ExcelFile.GetExcelAttribute(fieldInfo); bool isArray = false; bool allEqual = true; Object firstValue = null; Array firstValueArray = null; int arrayIndexFirstDifferent = -1; int row = -1; String message = null; foreach (Object value in excelFile.Rows.Select(rowObject => getValue(rowObject))) { arrayIndexFirstDifferent = -1; if (++row == 0) { if (fieldInfo.FieldType.BaseType == typeof(Array)) { firstValueArray = (Array)value; isArray = true; IEnumerator enumerator = firstValueArray.GetEnumerator(); enumerator.MoveNext(); firstValue = enumerator.Current; } else { firstValue = value; } continue; } if (isArray) { Array objArray = (Array)value; Debug.Assert(firstValueArray != null); bool arrayEqual = true; IEnumerator enumeratorFirst = firstValueArray.GetEnumerator(); IEnumerator enumeratorCurrent = objArray.GetEnumerator(); while (enumeratorFirst.MoveNext()) { enumeratorCurrent.MoveNext(); arrayIndexFirstDifferent++; Object objFirst = enumeratorFirst.Current; Object objCurrent = enumeratorCurrent.Current; if (firstValue == null) firstValue = objFirst; if (objFirst.Equals(objCurrent)) continue; arrayEqual = false; break; } if (arrayEqual) continue; allEqual = false; break; } Debug.Assert(firstValue != null); if (firstValue.Equals(value)) continue; allEqual = false; break; } Debug.Assert(firstValue != null); Object constValue = null; bool ignoreConstCheck = false; if (outputAttribute != null) { constValue = outputAttribute.ConstantValue; ignoreConstCheck = outputAttribute.DebugIgnoreConstantCheck; } if (fieldInfo.IsPrivate) { if (!allEqual) { message = String.Format("Warning: Private column (Type = {1}, StructureId = 0x{2}) \"{0}\" has per-row differing values", fieldInfo.Name, fieldInfo.FieldType, structureId.ToString("X8")); // need to add structureId to ensure message is unique per structure type if (isArray) { message += ", first index differing: " + arrayIndexFirstDifferent; } } else // allEqual && IsPrivate { if (isArray) { if (fieldInfo.FieldType == typeof(Int32[])) { if (firstValue.Equals((Int32)0)) continue; } else if (fieldInfo.FieldType == typeof(byte[])) { if (firstValue.Equals((byte)0x00)) continue; } else { Debug.Assert(false, "Unexpected Array Type: " + fieldInfo.FieldType); } if (outputAttribute != null && firstValue.Equals(outputAttribute.ConstantValue)) continue; message = String.Format("Warning: Private column (Type = {2}, StructureId = 0x{3}) \"{0}\" has constant value not zero \"{1}\"", fieldInfo.Name, firstValue, fieldInfo.FieldType, structureId.ToString("X8")); } else // not array { if (firstValue.Equals(constValue)) continue; if (fieldInfo.FieldType == typeof(Int32) && ((Int32)firstValue == 0 && (firstValue.Equals(constValue) || constValue == null))) continue; if (fieldInfo.FieldType == typeof(Int16) && ((Int16)firstValue == 0 && (firstValue.Equals(constValue) || constValue == null))) continue; message = String.Format("Warning: Private column (Type = {2}, StructureId = 0x{3}) \"{0}\" has constant value not zero \"{1}\"", fieldInfo.Name, firstValue, fieldInfo.FieldType, structureId.ToString("X8")); if (outputAttribute != null && outputAttribute.ConstantValue != null) message += " (outputAttribute.ConstantValue is set)"; } } } else // IsPublic { if (ignoreConstCheck) continue; if (allEqual && fieldInfo.IsPublic && rowCount != 1 && (outputAttribute == null || outputAttribute.ConstantValue == null)) { message = String.Format("Notice: Public column (Type = {2}, StructureId = 0x{3}) \"{0}\" has constant value \"{1}\"", fieldInfo.Name, firstValue, fieldInfo.FieldType, structureId.ToString("X8")); } } if (message == null) continue; uint[] messageCounts; if (outputMessages.TryGetValue(message, out messageCounts)) { outputMessages[message] = new[] { messageCounts[0] + 1, structureId }; } else { outputMessages.Add(message, new uint[] { 1, structureId }); } } //int bp3 = 0; } String previousStringId = null; StringWriter stringWriter = new StringWriter(); foreach (KeyValuePair<String, uint[]> message in outputMessages) { String msg = message.Key; uint msgCount = message.Value[0]; uint forStructureId = message.Value[1]; uint structureCount = rowTypeCounts[forStructureId]; if (structureCount != msgCount) continue; // if not equal, then we have a message in one table, but in another table it's not applicable String[] stringIds1 = (from dataTableAttribute in DataFile.DataFileMap where dataTableAttribute.Value.StructureId == forStructureId select dataTableAttribute.Key).ToArray(); String[] stringIds2 = (from dataTableAttribute in DataFile.DataFileMapTestCenter where dataTableAttribute.Value.StructureId == forStructureId select dataTableAttribute.Key).ToArray(); String[] stringIds3 = (from dataTableAttribute in DataFile.DataFileMapResurrection where dataTableAttribute.Value.StructureId == forStructureId select dataTableAttribute.Key).ToArray(); String[] stringIds4 = (from dataTableAttribute in DataFile.DataFileMapMod where dataTableAttribute.Value.StructureId == forStructureId select dataTableAttribute.Key).ToArray(); String stringIdPrepend = String.Join(",", stringIds1) + String.Join(",", stringIds2) + String.Join(",", stringIds3) + String.Join(",", stringIds4); if (previousStringId != stringIdPrepend) { //Console.WriteLine(stringIdPrepend); stringWriter.WriteLine(stringIdPrepend); previousStringId = stringIdPrepend; } //Console.WriteLine(msg); stringWriter.WriteLine(msg); } File.WriteAllText(@"C:\asdf.txt", stringWriter.ToString()); }
private DataTable _LoadExcelTable(ExcelFile excelFile, bool doRelations, bool force) { String tableName = excelFile.StringId; DataTable dataTable = XlsDataSet.Tables[tableName]; if (dataTable != null && !force) return dataTable; if (dataTable != null) { XlsDataSet.Relations.Clear(); XlsDataSet.Tables.Remove(tableName); } dataTable = XlsDataSet.Tables.Add(tableName); dataTable.TableName = tableName; dataTable.ExtendedProperties.Add("FileHeader", excelFile._excelFileHeader.DeepClone()); Type dataType = excelFile.Attributes.RowType; List<OutputAttribute> outputAttributes = new List<OutputAttribute>(); #region Generate Columns DataColumn indexColumn = dataTable.Columns.Add("Index"); indexColumn.AutoIncrement = true; indexColumn.Unique = true; dataTable.PrimaryKey = new[] { indexColumn }; outputAttributes.Add(null); FieldInfo[] fieldInfos = dataType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fieldInfos) { OutputAttribute excelAttribute = ExcelFile.GetExcelAttribute(fieldInfo); // The only private field we add is the TableHeader if (fieldInfo.IsPrivate) { if (fieldInfo.FieldType != typeof(ExcelFile.RowHeader)) continue; outputAttributes.Add(null); dataTable.Columns.Add(fieldInfo.Name, typeof(String)); continue; } Type fieldType = fieldInfo.FieldType; bool isArray = false; bool isEnum = false; if (fieldInfo.FieldType.BaseType == typeof(Array)) { fieldType = typeof(String); isArray = true; } else if (fieldInfo.FieldType.BaseType == typeof(Enum) && excelAttribute == null) { fieldType = fieldInfo.FieldType; isEnum = true; } DataColumn dataColumn = dataTable.Columns.Add(fieldInfo.Name, fieldType); if (isArray) { dataColumn.ExtendedProperties.Add(ColumnKeys.IsArray, true); } else if (isEnum) { dataColumn.ExtendedProperties.Add(ColumnKeys.IsEnum, true); } if (excelAttribute == null) { outputAttributes.Add(null); continue; } outputAttributes.Add(excelAttribute); if (excelAttribute.IsStringOffset) { dataColumn.DataType = typeof(String); dataColumn.ExtendedProperties.Add(ColumnKeys.IsStringOffset, true); dataColumn.DefaultValue = String.Empty; } if (excelAttribute.IsScript) { dataColumn.DataType = typeof(String); dataColumn.ExtendedProperties.Add(ColumnKeys.IsScript, true); dataColumn.DefaultValue = String.Empty; } if (excelAttribute.IsSecondaryString) { dataColumn.DataType = typeof(String); dataColumn.ExtendedProperties.Add(ColumnKeys.IsSecondaryString, true); dataColumn.DefaultValue = String.Empty; } if (excelAttribute.IsStringIndex) { dataColumn.ExtendedProperties.Add(ColumnKeys.IsStringIndex, true); // Add new column for the string DataColumn dataColumnString = dataTable.Columns.Add(fieldInfo.Name + "_string", typeof(String)); dataColumnString.DefaultValue = String.Empty; outputAttributes.Add(null); dataColumnString.ExtendedProperties.Add(ColumnKeys.IsRelationGenerated, true); } if (excelAttribute.IsTableIndex) { dataColumn.ExtendedProperties.Add(ColumnKeys.IsTableIndex, true); // Add new column for the string DataColumn dataColumnString = dataTable.Columns.Add(fieldInfo.Name + "_string", typeof(String)); dataColumnString.DefaultValue = String.Empty; outputAttributes.Add(null); dataColumnString.ExtendedProperties.Add(ColumnKeys.IsRelationGenerated, true); } if (excelAttribute.IsBitmask) { dataColumn.ExtendedProperties.Add(ColumnKeys.IsBitmask, true); } if (excelAttribute.IsBool) { dataColumn.ExtendedProperties.Add(ColumnKeys.IsBool, true); } } if (excelFile.Attributes.HasStats) // items, missiles, monsters, objects, players { DataColumn extendedDataColumn = dataTable.Columns.Add("Stats"); extendedDataColumn.DataType = typeof(String); extendedDataColumn.ExtendedProperties.Add(ExcelFile.ColumnTypeKeys.IsStats, true); outputAttributes.Add(null); } #endregion #region Generate Rows int row = 1; object[] baseRow = new object[outputAttributes.Count]; ObjectDelegator objectDelegator = new ObjectDelegator(fieldInfos); foreach (Object tableRow in excelFile.Rows) { int col = 1; foreach (FieldInfo fieldInfo in fieldInfos) { Object value = objectDelegator[fieldInfo.Name](tableRow); if (fieldInfo.IsPrivate) { if (fieldInfo.FieldType != typeof(ExcelFile.RowHeader)) continue; baseRow[col++] = FileTools.ObjectToStringGeneric(value, ","); continue; } OutputAttribute excelOutputAttribute = outputAttributes[col]; if (excelOutputAttribute == null) { if (value.GetType().BaseType == typeof(Array)) { value = ((Array)value).ToString(","); } baseRow[col++] = value; continue; } if (excelOutputAttribute.IsStringOffset) { int valueInt = (int)value; baseRow[col++] = (valueInt != -1) ? excelFile.ReadStringTable(valueInt) : String.Empty; continue; } if (excelOutputAttribute.IsSecondaryString) { int valueInt = (int)value; baseRow[col++] = (valueInt != -1) ? excelFile.ReadSecondaryStringTable(valueInt) : String.Empty; continue; } if (excelOutputAttribute.IsScript) { int scriptOffset = (int)value; if (scriptOffset == 0) { baseRow[col++] = String.Empty; continue; } String script; if (scriptOffset == 9649 && excelFile.StringId == "SKILLS") // todo: not sure what's with this script... { /* Compiled Bytes: * 26,30,700,6,26,1,399,358,669,616562688,711,26,62,3,17,669,641728512,26,8,711,26,62,3,17,358,669,322961408,26,5,700,6,26,1,399,358,388,0 * * Ending Stack (FIFO): * SetStat669('sfx_attack_pct', 'all', 30 * ($sklvl - 1)) * SetStat669('sfx_duration_pct', 'all', get_skill_level(@unit, 'Shield_Mastery')) * SetStat669('damage_percent_skill', 8 * get_skill_level(@unit, 'Shield_Mastery')) * SetStat669('damage_percent_skill', 8 * get_skill_level(@unit, 'Shield_Mastery')) + 5 * ($sklvl - 1) * * The last SetStat has strange overhang - decompiling wrong? * Or is it "supposed" to be there? * i.e. It's actually decompiling correctly, but because I've assumed such scripts to be wrong (as the end +5... segment is useless) we get the Stack exception */ int[] scriptCode = excelFile.ReadScriptTable(scriptOffset); script = scriptCode != null ? FileTools.ArrayToStringGeneric(scriptCode, ",") : "ScriptError"; baseRow[col++] = script; continue; } //if (fieldInfo.Name == "props1" && row == 45) //{ // int bp = 0; //} ExcelScript excelScript = new ExcelScript(this); try { if (ExcelScript.DebugEnabled) { int[] scriptCode = excelFile.ReadScriptTable(scriptOffset); script = scriptCode != null ? FileTools.ArrayToStringGeneric(scriptCode, ",") : String.Empty; script = excelScript.Decompile(excelFile.ScriptBuffer, scriptOffset, script, excelFile.StringId, row, col, fieldInfo.Name); } else { script = excelScript.Decompile(excelFile.ScriptBuffer, scriptOffset); } //if (script.StartsWith("GetStat666('skill_points_bonus_total', '') > -1;")) //{ // int bp = 0; //} } catch (Exception) { int[] scriptCode = excelFile.ReadScriptTable(scriptOffset); script = scriptCode != null ? FileTools.ArrayToStringGeneric(scriptCode, ",") : "ScriptError"; } baseRow[col++] = script; continue; } if (excelOutputAttribute.IsTableIndex || excelOutputAttribute.IsStringIndex) { if (value.GetType().BaseType == typeof(Array)) { value = ((Array)value).ToString(","); } else { value = (int)value; } baseRow[col++] = value; col++; // for _strings relational column continue; } // Else its something else, ie bitmask, bool, table/string index baseRow[col++] = value; } // stats, only a component of the UnitData row type if (excelFile.Attributes.HasStats) { baseRow[col++] = FileTools.ArrayToStringGeneric(excelFile.ReadStats(row - 1), ","); } dataTable.Rows.Add(baseRow); row++; } #endregion // Generate Relationships as required if (doRelations) _GenerateRelations(excelFile); return dataTable; }
/// <summary> /// Initialise private variables and generate excel script functions if required. /// </summary> public ExcelScript(FileManager fileManager) { if (fileManager == null) throw new ArgumentNullException("fileManager", "File Manager cannot be null."); if (!fileManager.DataFiles.ContainsKey("STATS")) throw new Exceptions.ScriptNotInitialisedException("The supplied file manager did not have a valid Stats table."); // these initial counts are required for script compiling when determing if a function is from the .exe or from an Excel table if (!_haveExcelFunctions) { _initCallFunctionsCountSinglePlayer = CallFunctionsSinglePlayer.Count; _initCallFunctionsTestCenterCount = CallFunctionsTestCenter.Count; _initCallFunctionsResurrectionCount = CallFunctionsResurrection.Count; } _fileManager = fileManager; if (_fileManager.IsVersionResurrection || _fileManager.IsVersionMod) { CallFunctions = CallFunctionsResurrection; _initCallFunctionsCount = _initCallFunctionsResurrectionCount; _debugRoot = DebugRootResurrection; } else if (_fileManager.IsVersionTestCenter) { CallFunctions = CallFunctionsTestCenter; _initCallFunctionsCount = _initCallFunctionsTestCenterCount; _debugRoot = DebugRootTestCenter; } else { CallFunctions = CallFunctionsSinglePlayer; _initCallFunctionsCount = _initCallFunctionsCountSinglePlayer; _debugRoot = DebugRoot; } _statsTable = (ExcelFile)_fileManager.DataFiles["STATS"]; _statsDelegator = _fileManager.DataFileDelegators["STATS"]; if (_globalDebug) EnableDebug(true); if (CallFunctions.Count == _initCallFunctionsCount) _GenerateExcelScriptFunctions(); }
public byte[] ExportSQL(FileManager fileManager, string tablePrefix = "") { string[] sqlReserved = new string[] { "group", "condition", "left", "right", "default", "key", "force", "analyze", "kill", "usage", "order" }; StringWriter stringWriter = new StringWriter(); string tableName = String.Format("{0}{1}", tablePrefix, StringId.ToLower()); stringWriter.WriteLine(String.Format("CREATE TABLE {0} (", tableName)); stringWriter.WriteLine("\tid INT NOT NULL PRIMARY KEY,"); String columnDec = "\t{0} {1}{2}"; int colCount = 1; ObjectDelegator objectDelegator; if (fileManager == null || !fileManager.DataFileDelegators.ContainsKey(StringId)) { objectDelegator = new ObjectDelegator(Attributes.RowType.GetFields()); FieldInfo headerField = DataType.GetField("header", BindingFlags.Instance | BindingFlags.NonPublic); objectDelegator.AddField(headerField); } else { objectDelegator = fileManager.DataFileDelegators[StringId]; } int noColumns = objectDelegator.FieldCount - 1; // remove header foreach (ObjectDelegator.FieldDelegate field in objectDelegator) { if (field.Name == "header") continue; // dont want this String columnName = field.Name; String dataType = String.Empty; String formatted = String.Empty; if (sqlReserved.Where(str => str == columnName.ToLower()).Any() == true) { columnName = "a" + columnName; } // Special types OutputAttribute excelOutput = GetExcelAttribute(field.Info); if (excelOutput != null) { if (excelOutput.IsScript || excelOutput.IsSecondaryString || excelOutput.IsStringOffset) dataType = "TEXT"; else if (excelOutput.IsBitmask) dataType = "BIGINT"; } if (dataType == String.Empty) { if (field.FieldType == typeof(int)) dataType = "INT"; else if (field.FieldType == typeof(float)) dataType = "DECIMAL"; else if (field.FieldType == typeof(byte)) dataType = "TINYINT"; else if (field.FieldType == typeof(short)) dataType = "SMALLINT"; else if (field.FieldType == typeof(uint) || field.FieldType == typeof(Int64)) dataType = "BIGINT"; else if (field.FieldType == typeof(string)) { MarshalAsAttribute marshalAs = (MarshalAsAttribute)field.Info.GetCustomAttributes(typeof(MarshalAsAttribute), false).First(); dataType = String.Format("VARCHAR({0})", marshalAs.SizeConst); } else if (field.FieldType.BaseType == typeof(Array)) { dataType = "TEXT"; } } formatted = String.Format(columnDec, columnName, dataType, colCount < noColumns ? "," : String.Empty); stringWriter.WriteLine(formatted); colCount++; } stringWriter.WriteLine(");"); stringWriter.WriteLine("INSERT INTO {0}", tableName); stringWriter.WriteLine("VALUES"); colCount = 1; int rowCount = 0; int noRows = Rows.Count; StringWriter valueString = new StringWriter(); foreach (Object rowObject in Rows) { valueString.Write(String.Format("\t({0},", rowCount)); // write the id foreach (ObjectDelegator.FieldDelegate field in objectDelegator) { if (field.Name == "header") continue; // dont want this OutputAttribute excelOutput = GetExcelAttribute(field.Info); Object objValue = field.GetValue(rowObject); bool valueParsed = false; if (excelOutput != null) { if (excelOutput.IsScript) { int[] scriptTable = ReadScriptTable((int)objValue); if (scriptTable != null) { int offset = (int)objValue; int[] scriptbuffer = ReadScriptTable(offset); String scriptString = FileTools.ArrayToStringGeneric(scriptbuffer, ","); try { if (fileManager != null) { ExcelScript excelScript = new ExcelScript(fileManager); scriptString = excelScript.Decompile(_scriptBuffer, offset); scriptString = StringToSQLString(scriptString); scriptString = EncapsulateString(scriptString); valueString.Write(scriptString); } else { valueString.Write(scriptString); } } catch (Exception e) { valueString.Write(EncapsulateString(scriptString)); Debug.WriteLine(e.ToString()); scriptString = "ScriptError(" + scriptString + ")"; } } else { valueString.Write("\"\""); } valueParsed = true; } else if (excelOutput.IsSecondaryString) { if ((int)objValue != -1) { string secString = ReadSecondaryStringTable((int)objValue); valueString.Write(String.Format("\"{0}\"", secString)); } else { valueString.Write("\"\""); } valueParsed = true; } else if (excelOutput.IsStringOffset) { string offString = ReadStringTable((int)objValue); offString = StringToSQLString(offString); offString = String.Format("\"{0}\"", offString); valueString.Write(offString); valueParsed = true; } else if (excelOutput.IsBitmask) { valueString.Write((uint)objValue); valueParsed = true; } } if (valueParsed == false) { if (field.FieldType == typeof(string)) { string strValue = EncapsulateString(StringToSQLString((objValue.ToString()))); valueString.Write(strValue); } else if (field.FieldType.BaseType == typeof(Array)) { string strValue = EncapsulateString(((Array)objValue).ToString(",")); valueString.Write(strValue); } else if (field.FieldType == typeof(float)) { string strValue = ((float)objValue).ToString("r"); valueString.Write(strValue); } else { valueString.Write(objValue); } } if (colCount < noColumns) valueString.Write(","); else valueString.Write(")"); colCount++; } if (rowCount < noRows - 1) valueString.WriteLine(","); else valueString.WriteLine(";"); rowCount++; colCount = 1; } stringWriter.Write(valueString.ToString()); byte[] buffer = FileTools.StringToASCIIByteArray(stringWriter.ToString()); return buffer; }
public ExcelFile(String filePath, FileManager.ClientVersions clientVersion = FileManager.ClientVersions.SinglePlayer) { Thread.CurrentThread.CurrentCulture = Common.EnglishUSCulture; IsExcelFile = true; FilePath = filePath; StringId = _GetStringId(filePath); if (StringId == null) throw new Exceptions.DataFileStringIdNotFound(filePath); // get the excel type attributes DataFileAttributes dataFileAttributes = null; if (clientVersion == FileManager.ClientVersions.Mod) { DataFileMapMod.TryGetValue(StringId, out dataFileAttributes); } if (dataFileAttributes == null && (clientVersion == FileManager.ClientVersions.Resurrection || clientVersion == FileManager.ClientVersions.Mod)) { DataFileMapResurrection.TryGetValue(StringId, out dataFileAttributes); } if (dataFileAttributes == null && clientVersion == FileManager.ClientVersions.TestCenter) { DataFileMapTestCenter.TryGetValue(StringId, out dataFileAttributes); } if (dataFileAttributes == null) { DataFileMap.TryGetValue(StringId, out dataFileAttributes); } Attributes = dataFileAttributes; if (Attributes == null) return; // create field delegators if (Attributes.RowType != null) { FieldInfo[] dataFileFields = Attributes.RowType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); dataFileFields = dataFileFields.OrderBy(f => f.MetadataToken).ToArray(); // order by defined order - GetFields does not guarantee ordering Delegator = new ObjectDelegator(dataFileFields); } else { Debug.WriteLine("Warning: Excel Definition has no RowType defined: " + StringId); } // if we're empty, then just return if (Attributes.IsEmpty) { HasIntegrity = true; Rows = new List<Object>(); return; } // we're using hard-coded mysh script table for SKILLS if (StringId == "SKILLS") _myshBuffer = Skills.Mysh.Data; // we aren't parsing file data, so need to manually assign a structure id _excelFileHeader.StructureID = Attributes.StructureId; }
public byte[] ExportCSV(FileManager fileManager, IEnumerable<String> columnNames = null) { if (Attributes.IsEmpty) return new byte[0]; //// init stuffs byte[] csvBuffer = new byte[1024]; int csvOffset = 0; bool isProperties = (StringId == "PROPERTIES" || StringId == "_TCv4_PROPERTIES"); ObjectDelegator objectDelegator; if (fileManager == null || !fileManager.DataFileDelegators.ContainsKey(StringId)) { objectDelegator = new ObjectDelegator(Attributes.RowType.GetFields()); FieldInfo headerField = DataType.GetField("header", BindingFlags.Instance | BindingFlags.NonPublic); objectDelegator.AddField(headerField); } else { objectDelegator = fileManager.DataFileDelegators[StringId]; } //// header row // tables can have different header values String tableHeaderStr = String.Format("{0}({1})", StringId, FileTools.ObjectToStringGeneric(_excelFileHeader, ",")); // rest of columns List<String> columnsList = new List<String> { tableHeaderStr }; foreach (ObjectDelegator.FieldDelegate fieldDelegate in objectDelegator) { if (columnNames == null) { if (!fieldDelegate.IsPublic) continue; } else if (!columnNames.Contains(fieldDelegate.Name)) { continue; } columnsList.Add(fieldDelegate.Name); } // excel table type-specific columns if (Attributes.HasStats) columnsList.Add("Stats"); if (isProperties) columnsList.Add("Script"); // column header row String[] columns = columnsList.ToArray(); int colCount = columns.Length; int rowCount = Count + 1; // +1 for column headers //// csv generation String[][] strings = new string[rowCount][]; strings[0] = columns; int col = -1; foreach (ObjectDelegator.FieldDelegate fieldDelegate in objectDelegator) { if (!columns.Contains(fieldDelegate.Name) && fieldDelegate.Name != "header") continue; col++; OutputAttribute excelAttribute = GetExcelAttribute(fieldDelegate.Info); //if (fieldDelegate.Name == "spawnFromMonsterUnitType") //{ // int bp = 0; //} int row = 0; foreach (Object rowObject in Rows) { String[] rowStr = strings[++row]; if (rowStr == null) { rowStr = new String[colCount]; strings[row] = rowStr; } if (fieldDelegate.Name == "header") { RowHeader rowHeader = (RowHeader)fieldDelegate.GetValue(rowObject); rowStr[col] = FileTools.ObjectToStringGeneric(rowHeader, ","); continue; } if (fieldDelegate.Name == "code") { int code; if (fieldDelegate.FieldType == typeof(short)) { code = (int)(short)fieldDelegate.GetValue(rowObject); // yes, that extra (int) is *needed* to cast the short correctly } else { code = (int)fieldDelegate.GetValue(rowObject); } if (StringId == "REGION") // can't export region code values as chars due to weird chars { rowStr[col] = "\"" + code + "\""; } else { rowStr[col] = "\"" + _CodeToString(code) + "\""; } continue; } bool isArray = (fieldDelegate.FieldType.BaseType == typeof(Array)); if (excelAttribute != null) { if (excelAttribute.IsTableIndex && fileManager != null) { int[] indexValues; Object indexObj = fieldDelegate.GetValue(rowObject); if (isArray) { indexValues = (int[])indexObj; } else { indexValues = new[] { (int)indexObj }; } String[] indexStrs = new String[indexValues.Length]; for (int i = 0; i < indexStrs.Length; i++) { if (indexValues[i] == -1) // empty string/no code { indexStrs[i] = "-1"; continue; } String tableStringId = excelAttribute.TableStringId; String negative = String.Empty; if (indexValues[i] < 0) { indexValues[i] *= -1; negative = "-"; } String indexStr = null; if (fileManager.DataTableHasColumn(tableStringId, "code")) { int code = fileManager.GetExcelIntFromStringId(tableStringId, indexValues[i], "code"); if (code != 0) indexStr = _CodeToString(code); } else if (fileManager.DataTableHasColumn(tableStringId, "name")) { indexStr = fileManager.GetExcelStringFromStringId(tableStringId, indexValues[i], "name"); } if (indexStr == null) { indexStr = fileManager.GetExcelStringFromStringId(tableStringId, indexValues[i]); } indexStrs[i] = negative + indexStr; } rowStr[col] = "\"" + String.Join(",", indexStrs) + "\""; continue; } if (excelAttribute.IsStringOffset) { int offset = (int)fieldDelegate.GetValue(rowObject); if (offset != -1) { rowStr[col] = ReadStringTable(offset); } continue; } if (excelAttribute.IsScript) { int offset = (int)fieldDelegate.GetValue(rowObject); if ((offset == 0)) { FileTools.WriteToBuffer(ref csvBuffer, ref csvOffset, FileTools.StringToASCIIByteArray("0")); continue; } int[] buffer = ReadScriptTable(offset); if (buffer == null) throw new Exceptions.ScriptFormatException("The script bytes were unable to be read using ReadScriptTable.", offset); String scriptString = FileTools.ArrayToStringGeneric(buffer, ","); if (fileManager != null) { if (offset == 9325 /*from DataTable export*/ || offset == 9649 /*from Object export*/ && StringId == "SKILLS") // todo: not sure what's with this script... { /* Compiled Bytes: * 26,30,700,6,26,1,399,358,669,616562688,711,26,62,3,17,669,641728512,26,8,711,26,62,3,17,358,669,322961408,26,5,700,6,26,1,399,358,388,0 * * Ending Stack (FIFO): * SetStat669('sfx_attack_pct', 'all', 30 * ($sklvl - 1)) * SetStat669('sfx_duration_pct', 'all', get_skill_level(@unit, 'Shield_Mastery')) * SetStat669('damage_percent_skill', 8 * get_skill_level(@unit, 'Shield_Mastery')) * SetStat669('damage_percent_skill', 8 * get_skill_level(@unit, 'Shield_Mastery')) + 5 * ($sklvl - 1) * * The last SetStat has strange overhang - decompiling wrong? * Or is it "supposed" to be there? * i.e. It's actually decompiling correctly, but because I've assumed such scripts to be wrong (as the end +5... segment is useless) we get the Stack exception */ scriptString = "ScriptError(" + scriptString + ")"; } else { try { ExcelScript excelScript = new ExcelScript(fileManager); scriptString = "\"" + excelScript.Decompile(_scriptBuffer, offset, scriptString, StringId, row, col, fieldDelegate.Name) + "\""; } catch (Exception e) { Debug.WriteLine(e.ToString()); scriptString = "ScriptError(" + scriptString + ")"; } } } rowStr[col] = scriptString; continue; } if (excelAttribute.IsSecondaryString) { int index = (int)fieldDelegate.GetValue(rowObject); if (index != -1) { rowStr[col] = SecondaryStrings[index]; } continue; } if (excelAttribute.IsBitmask) { rowStr[col] = "\"" + fieldDelegate.GetValue(rowObject) + "\""; continue; } } Object outValue = fieldDelegate.GetValue(rowObject); if (isArray) { rowStr[col] = ((Array)outValue).ToString(","); } else if (fieldDelegate.FieldType == typeof(float)) { rowStr[col] = ((float)outValue).ToString("r"); } //else if (fieldDelegate.FieldType.BaseType == typeof(Enum)) // might as well export enums as their string representations //{ // rowStr[col] = ((UInt32)outValue).ToString(); //} else { rowStr[col] = outValue.ToString(); } } } // stats if (Attributes.HasStats) { col++; int row = -1; foreach (String[] rowStr in strings) { if (row == -1) // columns header row { row++; continue; } rowStr[col] = StatsBuffer[row++].ToString(","); } } // properties scripts if (isProperties) { // not point in doing this //if (tableHeader.Unknown1 != 2 || scriptRow == ExcelFunctions.Count - 1) // need 1 extra row for some reason col++; int row = -1; foreach (String[] rowStr in strings) { if (row == -1) { row++; continue; } if (row >= ExcelFunctions.Count) break; ExcelFunction excelScript = ExcelFunctions[row++]; String excelScriptFunction = String.Empty; foreach (ExcelFunction.Parameter paramater in excelScript.Parameters) { excelScriptFunction += String.Format("\n{0},{1},{2},{3}", paramater.Name, paramater.Unknown, paramater.TypeId, paramater.TypeValues.ToString(",")); } if (excelScript.ScriptByteCode != null) { int offset = 0; excelScriptFunction += "\n" + FileTools.ByteArrayToInt32Array(excelScript.ScriptByteCode, ref offset, excelScript.ScriptByteCode.Length / 4).ToString(",") + "\n"; } rowStr[col] = excelScriptFunction; } } //// join string arrays and create byte array String[] rows = new String[rowCount]; col = 0; foreach (String[] rowStr in strings) { rows[col] = String.Join("\t", rowStr); col++; } String csvString = String.Join(Environment.NewLine, rows); return csvString.ToASCIIByteArray(); }
private bool _ParseCSV(byte[] csvBytes, FileManager fileManager, Dictionary<String, ExcelFile> csvExcelFiles) { // function setup int stringBufferOffset = 0; int integerBufferOffset = 1; bool isProperties = (StringId == "PROPERTIES" || StringId == "_TCv4_PROPERTIES"); ObjectDelegator objectDelegator; OutputAttribute[] excelAttributes; bool needOutputAttributes = true; if (fileManager == null || !fileManager.DataFileDelegators.ContainsKey(StringId)) { FieldInfo[] fieldInfos = DataType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); fieldInfos = fieldInfos.OrderBy(f => f.MetadataToken).ToArray(); // order by defined order - GetFields does not guarantee ordering objectDelegator = new ObjectDelegator(fieldInfos); excelAttributes = new OutputAttribute[fieldInfos.Length]; } else { objectDelegator = fileManager.DataFileDelegators[StringId]; excelAttributes = new OutputAttribute[objectDelegator.FieldCount]; } String[][] tableRows; if (csvBytes == null) { tableRows = _csvTable; } else { // get columns int offset = 0; int colCount = 1; while (csvBytes[offset++] != '\n') if (csvBytes[offset] == CSVDelimiter) colCount++; tableRows = FileTools.CSVToStringArray(csvBytes, colCount, CSVDelimiter); } int rowCount = tableRows.Length; String[] columns = tableRows[0]; if (isProperties) { ExcelFunctions = new List<ExcelFunction>(); _scriptBuffer = new byte[1]; // properties is weird - do this just to ensure 100% byte-for-byte accuracy } // parse file header - could use Regex here - but don't think that'd but faster, in fact, probably a lot slower(?) - meh // format: %s(%s) // first %s = StringId, second %s = FileHeader as String String fileHeader = columns[0]; int fileHeaderStart = fileHeader.IndexOf("(") + 1; int fileHeaderEnd = fileHeader.IndexOf(")"); String fileHeaderStr = fileHeader.Substring(fileHeaderStart, fileHeaderEnd - fileHeaderStart); _excelFileHeader = FileTools.StringToObject<ExcelHeader>(fileHeaderStr, ",", FileHeaderFields); String strId = fileHeader.Substring(0, fileHeader.IndexOf("(")).Trim(); // asking for exception lol Debug.Assert(strId == StringId); // Parse the tableRows bool failedParsing = false; Rows = new List<Object>(); for (int row = 1; row < rowCount; row++) { int col = -1; int csvCol = 0; Object rowInstance = Activator.CreateInstance(DataType); foreach (ObjectDelegator.FieldDelegate fieldDelegate in objectDelegator) { col++; if (needOutputAttributes) excelAttributes[col] = GetExcelAttribute(fieldDelegate.Info); OutputAttribute excelAttribute = excelAttributes[col]; // columns not present if (!columns.Contains(fieldDelegate.Name)) { // create row header object if (fieldDelegate.FieldType == typeof(RowHeader)) { String headerString = tableRows[row][csvCol++]; RowHeader rowHeader = FileTools.StringToObject<RowHeader>(headerString, ",", RowHeaderFields); objectDelegator[fieldDelegate.Name, rowInstance] = rowHeader; continue; } // assign default values MarshalAsAttribute arrayMarshal = null; Array arrayInstance = null; if (fieldDelegate.FieldType.BaseType == typeof(Array)) { arrayMarshal = (MarshalAsAttribute)fieldDelegate.Info.GetCustomAttributes(typeof(MarshalAsAttribute), false).First(); arrayInstance = (Array)Activator.CreateInstance(fieldDelegate.FieldType, arrayMarshal.SizeConst); objectDelegator[fieldDelegate.Name, rowInstance] = arrayInstance; } else if (fieldDelegate.FieldType == typeof(String)) { objectDelegator[fieldDelegate.Name, rowInstance] = String.Empty; } // assign constant non-zero values if (excelAttribute == null || excelAttribute.ConstantValue == null) continue; if (fieldDelegate.FieldType.BaseType == typeof(Array)) { Debug.Assert(arrayInstance != null, "arrayInstance == null"); Debug.Assert(arrayMarshal != null, "arrayMarshal == null"); for (int i = 0; i < arrayMarshal.SizeConst; i++) { arrayInstance.SetValue(excelAttribute.ConstantValue, i); } } else { objectDelegator[fieldDelegate.Name, rowInstance] = excelAttribute.ConstantValue; } continue; } // columns present String value = tableRows[row][csvCol++]; if (fieldDelegate.Name == "code") { int code = (StringId == "REGION") ? int.Parse(value) : StringToCode(value); if (fieldDelegate.FieldType == typeof(short)) { objectDelegator[fieldDelegate.Name, rowInstance] = (short)code; } else { objectDelegator[fieldDelegate.Name, rowInstance] = code; } continue; } bool isArray = (fieldDelegate.FieldType.BaseType == typeof(Array)); bool isEnum = (fieldDelegate.FieldType.BaseType == typeof(Enum)); if (excelAttribute != null) { if (excelAttribute.IsTableIndex && fileManager != null) { int arraySize = 1; if (isArray) { MarshalAsAttribute arrayMarshal = (MarshalAsAttribute)fieldDelegate.Info.GetCustomAttributes(typeof(MarshalAsAttribute), false).First(); arraySize = arrayMarshal.SizeConst; Debug.Assert(arraySize > 0); } String[] indexStrs = value.Split(new[] { ',' }); Int32[] rowIndexValues = new int[arraySize]; for (int i = 0; i < arraySize; i++) rowIndexValues[i] = -1; int maxElements = indexStrs.Length; if (maxElements > arraySize) { Debug.WriteLine(String.Format("{0}: Loss of array elements detected. row = {1}, col = {2}.", StringId, row, col)); maxElements = arraySize; } for (int i = 0; i < maxElements; i++) { value = indexStrs[i]; if (value == "-1") continue; String tableStringId = excelAttribute.TableStringId; bool hasCodeColumn = fileManager.DataTableHasColumn(tableStringId, "code"); if (value.Length == 0 && hasCodeColumn) continue; //LEVEL references multiple blank TREASURE row index values - all appear to be empty rows though, so meh... //Debug.Assert(!String.IsNullOrEmpty(value)); int isNegative = 1; if (value.Length > 0 && value[0] == '-') { isNegative = -1; value = value.Substring(1, value.Length - 1); } int rowIndex = -1; ExcelFile relatedExcel = null; if (csvExcelFiles != null && csvExcelFiles.TryGetValue(tableStringId, out relatedExcel)) { rowIndex = relatedExcel._GetRowIndexFromValue(value, hasCodeColumn ? "code" : null); } if (relatedExcel == null) { if (hasCodeColumn && value.Length <= 4) { int code = StringToCode(value); rowIndex = fileManager.GetExcelRowIndexFromStringId(tableStringId, code, "code"); } else if (fileManager.DataTableHasColumn(tableStringId, "name")) { rowIndex = fileManager.GetExcelRowIndexFromStringId(tableStringId, value, "name"); } else { rowIndex = fileManager.GetExcelRowIndex(tableStringId, value); } } rowIndexValues[i] = rowIndex * isNegative; } if (isArray) { objectDelegator[fieldDelegate.Name, rowInstance] = rowIndexValues; } else { objectDelegator[fieldDelegate.Name, rowInstance] = rowIndexValues[0]; } continue; } if (excelAttribute.IsStringOffset) { if (_stringBuffer == null) _stringBuffer = new byte[1024]; if (String.IsNullOrEmpty(value)) { objectDelegator[fieldDelegate.Name, rowInstance] = -1; continue; } objectDelegator[fieldDelegate.Name, rowInstance] = stringBufferOffset; FileTools.WriteToBuffer(ref _stringBuffer, ref stringBufferOffset, FileTools.StringToASCIIByteArray(value)); stringBufferOffset++; // \0 continue; } if (excelAttribute.IsScript) { if ((fileManager == null && value == "0") || value == "") { objectDelegator[fieldDelegate.Name, rowInstance] = 0; continue; } if (_scriptBuffer == null) { _scriptBuffer = new byte[1024]; _scriptBuffer[0] = 0x00; } int[] scriptByteCode; if (fileManager != null) { ExcelScript excelScript = new ExcelScript(fileManager); scriptByteCode = excelScript.Compile(value, null, StringId, row, col, fieldDelegate.Name); } else { string[] splitValue = value.Split(','); int count = splitValue.Length; scriptByteCode = new int[count]; for (int i = 0; i < count; i++) { scriptByteCode[i] = int.Parse(splitValue[i]); } } objectDelegator[fieldDelegate.Name, rowInstance] = integerBufferOffset; FileTools.WriteToBuffer(ref _scriptBuffer, ref integerBufferOffset, scriptByteCode.ToByteArray()); continue; } if (excelAttribute.IsSecondaryString) { if (SecondaryStrings == null) SecondaryStrings = new List<String>(); if (value == "") { objectDelegator[fieldDelegate.Name, rowInstance] = -1; continue; } if (!SecondaryStrings.Contains(value)) { SecondaryStrings.Add(value); } objectDelegator[fieldDelegate.Name, rowInstance] = SecondaryStrings.IndexOf(value); continue; } if (excelAttribute.IsBitmask) { if (fieldDelegate.FieldType == typeof(UInt32)) { objectDelegator[fieldDelegate.Name, rowInstance] = UInt32.Parse(value); continue; } Object enumVal; try { enumVal = Enum.Parse(fieldDelegate.FieldType, value); } catch (Exception) { String[] enumStrings = value.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); String[] enumNames = Enum.GetNames(fieldDelegate.FieldType); String enumString = String.Empty; String enumSeperator = String.Empty; foreach (String enumStr in enumStrings) { if (!enumNames.Contains(enumStr)) { Debug.WriteLine(String.Format("{0}: bitfield name '{1}' not found.", StringId, enumStr)); continue; } enumString += enumSeperator + enumStr; enumSeperator = ","; } enumVal = enumString == "" ? 0 : Enum.Parse(fieldDelegate.FieldType, enumString); } objectDelegator[fieldDelegate.Name, rowInstance] = enumVal; continue; } } try { Object objValue; if (isArray) { if (fieldDelegate.FieldType == typeof(Int32[])) { objValue = FileTools.StringToArray<Int32>(value, ","); } else { Type elementType = fieldDelegate.FieldType.GetElementType(); if (elementType.BaseType == typeof(Enum)) { String[] enumStrs = value.Split(new[] { ',' }, StringSplitOptions.None); Array enumsArray = Array.CreateInstance(elementType, enumStrs.Length); int i = 0; foreach (String enumStr in enumStrs) { enumsArray.SetValue(Enum.Parse(elementType, enumStr), i++); } objValue = enumsArray; } else { throw new NotImplementedException("if (fieldInfo.FieldType.BaseType == typeof(Array)) :: Type = " + elementType.BaseType); } } objectDelegator[fieldDelegate.Name, rowInstance] = objValue; } else if (isEnum) { object enumVal = Enum.Parse(fieldDelegate.FieldType, value); objectDelegator[fieldDelegate.Name, rowInstance] = enumVal; } else { objValue = FileTools.StringToObject(value, fieldDelegate.FieldType); objectDelegator[fieldDelegate.Name, rowInstance] = objValue; } } catch (Exception e) { Console.WriteLine("Critical Parsing Error: " + e); failedParsing = true; break; } } if (failedParsing) break; needOutputAttributes = false; // applicable only for Unit type; items, missiles, monsters, objects, players if (Attributes.HasStats) { if (StatsBuffer == null) StatsBuffer = new byte[rowCount - 1][]; String value = tableRows[row][csvCol]; String[] stringArray = value.Split(','); byte[] byteArray = new byte[stringArray.Length]; for (int i = 0; i < byteArray.Length; i++) { byteArray[i] = Byte.Parse(stringArray[i]); } StatsBuffer[row - 1] = byteArray; } // properties has extra Scripts stuffs // yea, this is a bit messy, but it's a single table only and mostly done out of curiosity if (isProperties) { String value = tableRows[row][csvCol]; String[] scripts = value.Split('\n'); ExcelFunction excelScript = new ExcelFunction(); if (scripts.Length > 1) { ExcelFunctions.Add(excelScript); } int i = 0; do { if (scripts.Length == 1) continue; i++; String[] values = scripts[i].Split(','); if (values.Length < 4) continue; // script parameters int typeValuesCount = values.Length - 3; ExcelFunction.Parameter parameter = new ExcelFunction.Parameter { Name = values[0], Unknown = UInt32.Parse(values[1]), TypeId = UInt32.Parse(values[2]), TypeValues = new int[typeValuesCount] }; for (int j = 0; j < typeValuesCount; j++) { parameter.TypeValues[j] = Int32.Parse(values[3 + j]); } excelScript.Parameters.Add(parameter); } while (i < scripts.Length - 1 - 2); // -2 for: last line is blank, and line before *might* be script values // last line will be script values if it exists if (i < scripts.Length - 2) { String[] values = scripts[++i].Split(','); int[] scriptValues = new int[values.Length]; for (int j = 0; j < values.Length; j++) { scriptValues[j] = Int32.Parse(values[j]); } excelScript.ScriptByteCode = scriptValues.ToByteArray(); } } Rows.Add(rowInstance); } // resize the integer and string buffers if they were used if (_stringBuffer != null) Array.Resize(ref _stringBuffer, stringBufferOffset); if (_scriptBuffer != null) Array.Resize(ref _scriptBuffer, integerBufferOffset); return HasIntegrity = true; }
/// <summary> /// Creates a ExcelFile based on the DataTable data. /// </summary> /// <param name="dataTable">The DataTable to read the data from.</param> /// <param name="fileManager">The FileManager to use for script compilations etc.</param> /// <returns>True if the DataTable parsed okay.</returns> public override bool ParseDataTable(DataTable dataTable, FileManager fileManager) { if (dataTable == null) throw new ArgumentNullException("dataTable", "DataTable can not be null!"); if (fileManager == null) throw new ArgumentNullException("fileManager", "FileManager can not be null!"); byte[] newStringBuffer = null; int newStringBufferOffset = 0; byte[] newScriptBuffer = (Attributes.HasScriptTable) ? new byte[1024] : null; int newScriptBufferOffset = 0; // don't start at 1 as it will resize the array wrong byte[][] newStatsBuffer = null; List<String> newSecondaryStrings = null; List<Object> newRows = new List<Object>(); bool failedParsing = false; const BindingFlags bindingFlags = (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] dataFields = DataType.GetFields(bindingFlags); OutputAttribute[] excelAttributes; ObjectDelegator objectDelegator; if (fileManager == null || !fileManager.DataFileDelegators.ContainsKey(StringId)) { FieldInfo[] fieldInfos = DataType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); objectDelegator = new ObjectDelegator(fieldInfos); excelAttributes = new OutputAttribute[fieldInfos.Length]; } else { objectDelegator = fileManager.DataFileDelegators[StringId]; excelAttributes = new OutputAttribute[objectDelegator.FieldCount]; } for (int row = 0; row < dataTable.Rows.Count; row++) { int col = 1; // Skip the indice column (column 0) Object rowInstance = Activator.CreateInstance(DataType); foreach (ObjectDelegator.FieldDelegate fieldDelegate in objectDelegator) { //if (fieldInfo.Name == "warpToFloor") //{ // int bp = 0; //} OutputAttribute attribute = GetExcelAttribute(fieldDelegate.Info); // Initialize private fields if (fieldDelegate.IsPrivate) { // will be in DataTable (first column) if (fieldDelegate.FieldType == typeof(RowHeader)) { String headerString = (String)dataTable.Rows[row][col++]; RowHeader rowHeader = FileTools.StringToObject<RowHeader>(headerString, ",", RowHeaderFields); fieldDelegate.SetValue(rowInstance, rowHeader); continue; } // will not be in DataTable MarshalAsAttribute arrayMarshal = null; Array arrayInstance = null; if (fieldDelegate.FieldType.BaseType == typeof(Array)) { arrayMarshal = (MarshalAsAttribute)fieldDelegate.Info.GetCustomAttributes(typeof(MarshalAsAttribute), false).First(); arrayInstance = (Array)Activator.CreateInstance(fieldDelegate.FieldType, arrayMarshal.SizeConst); fieldDelegate.SetValue(rowInstance, arrayInstance); } else if (fieldDelegate.FieldType == typeof(String)) { fieldDelegate.SetValue(rowInstance, String.Empty); } // assign constant non-zero values if (attribute == null || attribute.ConstantValue == null) continue; if (fieldDelegate.FieldType.BaseType == typeof(Array)) { Debug.Assert(arrayInstance != null, "arrayInstance == null"); Debug.Assert(arrayMarshal != null, "arrayMarshal == null"); for (int i = 0; i < arrayMarshal.SizeConst; i++) { arrayInstance.SetValue(attribute.ConstantValue, i); } } else { objectDelegator[fieldDelegate.Name, rowInstance] = attribute.ConstantValue; } continue; } // Public fields -> these are inside the datatable Object value = dataTable.Rows[row][col++]; bool isArray = (fieldDelegate.FieldType.BaseType == typeof(Array)); if (attribute != null) { if (attribute.IsTableIndex) { if (isArray) { int arraySize = 1; MarshalAsAttribute arrayMarshal = (MarshalAsAttribute)fieldDelegate.Info.GetCustomAttributes(typeof(MarshalAsAttribute), false).First(); arraySize = arrayMarshal.SizeConst; Debug.Assert(arraySize > 0); String strValue = value.ToString(); String[] indexStrs = strValue.Split(new[] { ',' }); Int32[] rowIndexValues = new int[arraySize]; for (int i = 0; i < arraySize; i++) rowIndexValues[i] = -1; int maxElements = indexStrs.Length; if (maxElements > arraySize) { Debug.WriteLine(String.Format("{0}: Loss of array elements detected. row = {1}, col = {2}.", StringId, row, col)); maxElements = arraySize; } int[] rowIndices = new int[maxElements]; for (int i = 0; i < maxElements; i++) { rowIndices[i] = int.Parse(indexStrs[i]); } objectDelegator[fieldDelegate.Name, rowInstance] = rowIndices; } else { objectDelegator[fieldDelegate.Name, rowInstance] = int.Parse(value.ToString()); } // we need to make sure the following data column is a relational column; some tables (and thus the relational column) aren't present, even though the column "links" to them (e.g. LEVEL_AREAS) DataColumn dataColumn = dataTable.Columns[col]; if (dataColumn.ExtendedProperties.ContainsKey(ColumnTypeKeys.IsRelationGenerated) && (bool)dataColumn.ExtendedProperties[ColumnTypeKeys.IsRelationGenerated]) { col++; } continue; } if (attribute.IsStringIndex) { fieldDelegate.SetValue(rowInstance, value); col++; // Skip lookup continue; } if (attribute.IsStringOffset) { String strValue = value as String; if (strValue == null) throw new Exception("A script was not presented as a String!"); if (newStringBuffer == null) { newStringBuffer = new byte[1024]; } if (String.IsNullOrEmpty(strValue)) // i.e. is empty { fieldDelegate.SetValue(rowInstance, -1); continue; } fieldDelegate.SetValue(rowInstance, newStringBufferOffset); FileTools.WriteToBuffer(ref newStringBuffer, ref newStringBufferOffset, FileTools.StringToASCIIByteArray(strValue)); FileTools.WriteToBuffer(ref newStringBuffer, ref newStringBufferOffset, (byte)0x00); continue; } if (attribute.IsScript) { String strValue = value as String; if (strValue == null || (fileManager == null && strValue == "0") || strValue == "") { objectDelegator[fieldDelegate.Name, rowInstance] = 0; continue; } //if (strValue == "GetStat666('skill_points_bonus_total', '') > -1;") //{ // int bp = 0; //} int[] scriptByteCode; int firstComma = -1; // is it an uncompiled int array if (strValue[0] >= '0' && strValue[0] <= '9') firstComma = strValue.IndexOf(','); if (fileManager != null && (firstComma == -1 || firstComma > 3)) // biggest opcode is 3 digits (this doesn't account for white space, but meh for now) { ExcelScript excelScript = new ExcelScript(fileManager); scriptByteCode = excelScript.Compile(strValue); } else { scriptByteCode = strValue.ToArray<int>(','); } if (newScriptBufferOffset == 0) newScriptBufferOffset++; // 0 = no/null script objectDelegator[fieldDelegate.Name, rowInstance] = newScriptBufferOffset; FileTools.WriteToBuffer(ref newScriptBuffer, ref newScriptBufferOffset, scriptByteCode.ToByteArray()); continue; } if (attribute.IsSecondaryString) { if (newSecondaryStrings == null) newSecondaryStrings = new List<String>(); String strValue = value as String; if (strValue == null) return false; if (String.IsNullOrEmpty(strValue)) { fieldDelegate.SetValue(rowInstance, -1); continue; } if (newSecondaryStrings.Contains(strValue) == false) { newSecondaryStrings.Add(strValue); } fieldDelegate.SetValue(rowInstance, newSecondaryStrings.IndexOf(strValue)); continue; } } try { if (fieldDelegate.FieldType != value.GetType()) // i.e. if the type hasn't been converted yet (no attributes means it wasn't converted above) { if (fieldDelegate.FieldType.BaseType == typeof(Enum)) { value = Enum.Parse(fieldDelegate.FieldType, value.ToString()); } else if (fieldDelegate.FieldType == typeof(Int32[])) { value = ((String)value).ToArray<Int32>(','); } else if (fieldDelegate.FieldType.BaseType == typeof(Array)) { Type elementType = fieldDelegate.FieldType.GetElementType(); if (elementType.BaseType == typeof(Enum)) { String[] enumStrs = ((String)value).Split(new[] { ',' }, StringSplitOptions.None); Array enumsArray = Array.CreateInstance(elementType, enumStrs.Length); int i = 0; foreach (String enumStr in enumStrs) { enumsArray.SetValue(Enum.Parse(elementType, enumStr), i++); } value = enumsArray; } else { throw new NotImplementedException("if (fieldInfo.FieldType.BaseType == typeof(Array)) :: Type = " + elementType.BaseType); } } else { value = Convert.ChangeType(value, fieldDelegate.FieldType); } } fieldDelegate.SetValue(rowInstance, value); } catch (Exception e) { ExceptionLogger.LogException(e); Console.WriteLine("Critical Parsing Error: " + e.Message); failedParsing = true; break; } } if (failedParsing) break; // For item types, items, missiles, monsters etc // This must be a hex byte delimited array if (Attributes.HasStats) { if (newStatsBuffer == null) { newStatsBuffer = new byte[dataTable.Rows.Count][]; } const char split = ','; string value = dataTable.Rows[row][col] as string; if (String.IsNullOrEmpty(value)) { Console.WriteLine("Error parsing stats string."); return false; } string[] stringArray = value.Split(split); byte[] byteArray = new byte[stringArray.Length]; for (int i = 0; i < byteArray.Length; i++) { byteArray[i] = Byte.Parse(stringArray[i]); } newStatsBuffer[row] = byteArray; } newRows.Add(rowInstance); } // Parsing Complete, assign new references. These arn't assigned before now incase of a parsing error. Rows = newRows; _stringBuffer = newStringBuffer; if (_stringBuffer != null) Array.Resize(ref _stringBuffer, newStringBufferOffset); _scriptBuffer = newScriptBuffer; if (_scriptBuffer != null) Array.Resize(ref _scriptBuffer, newScriptBufferOffset); StatsBuffer = newStatsBuffer; SecondaryStrings = newSecondaryStrings; // assign file header details (they are not all the same!) ExcelHeader excelHeader = (ExcelHeader)dataTable.ExtendedProperties["FileHeader"]; _excelFileHeader = excelHeader.DeepClone(); return true; }