示例#1
0
        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();
        }
示例#2
0
        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;
        }