Пример #1
0
        internal static void Serialize(object instance, BitWriter writer)
        {
            FieldInfo[] sortedFields;
            MethodInfo  preMethod;

            if (cachedFields.ContainsKey(instance.GetType().FullName))
            {
                sortedFields = cachedFields[instance.GetType().FullName];
            }
            else
            {
                sortedFields = instance.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).OrderBy(x => x.Name).Where(x => !x.IsDefined(typeof(BinaryIgnore), true)).ToArray();
                cachedFields.Add(instance.GetType().FullName, sortedFields);
            }

            if (preSerialize.ContainsKey(instance.GetType().FullName))
            {
                preMethod = preSerialize[instance.GetType().FullName];
            }
            else
            {
                preMethod = instance.GetType().GetMethod("PreSerialize", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                preSerialize.Add(instance.GetType().FullName, preMethod);
            }

            if (preMethod != null)
            {
                preMethod.Invoke(instance, null);
            }

            for (int i = 0; i < sortedFields.Length; i++)
            {
                FieldTypeHelper.WriteFieldType(writer, sortedFields[i].GetValue(instance));
            }
        }
        internal static void HandleTargetRpc(uint clientId, BitReader reader, int channelId)
        {
            if (NetworkingManager.singleton.NetworkConfig.AttributeMessageMode == AttributeMessageMode.Disabled)
            {
                return;
            }

            uint               networkId    = reader.ReadUInt();
            ushort             orderId      = reader.ReadUShort();
            ulong              hash         = reader.ReadULong();
            NetworkedBehaviour behaviour    = SpawnManager.spawnedObjects[networkId].GetBehaviourAtOrderIndex(orderId);
            MethodInfo         targetMethod = null;

            if (behaviour.cachedMethods.ContainsKey(hash))
            {
                targetMethod = behaviour.cachedMethods[hash];
            }
            else
            {
                return;  //No method
            }
            ParameterInfo[] parameters   = targetMethod.GetParameters();
            object[]        methodParams = new object[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
            {
                methodParams[i] = FieldTypeHelper.ReadFieldType(reader, parameters[i].ParameterType);
            }
            targetMethod.Invoke(behaviour, methodParams);
        }
Пример #3
0
        /// <summary>
        /// Deserializes binary and turns it back into the original class
        /// </summary>
        /// <typeparam name="T">The type to return</typeparam>
        /// <param name="binary">The binary to deserialize</param>
        /// <returns>An instance of T</returns>
        public static T Deserialize <T>(byte[] binary) where T : new()
        {
            T instance = new T();

            FieldInfo[] sortedFields;

            if (cachedFields.ContainsKey(instance.GetType().FullName))
            {
                sortedFields = cachedFields[instance.GetType().FullName];
            }
            else
            {
                sortedFields = instance.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).OrderBy(x => x.Name).Where(x => !x.IsDefined(typeof(BinaryIgnore), true)).ToArray();
                cachedFields.Add(instance.GetType().FullName, sortedFields);
            }

            BitReader reader = new BitReader(binary);

            for (int i = 0; i < sortedFields.Length; i++)
            {
                FieldType fieldType = FieldTypeHelper.GetFieldType(sortedFields[i].FieldType);
                if (fieldType == FieldType.Invalid)
                {
                    Debug.LogWarning("MLAPI: The field " + sortedFields[i].Name + " will not be deserialized as it's not of a supported type. Add the BinaryIgnore attribute to prevent this message from shwoing up.");
                    continue;
                }
                sortedFields[i].SetValue(instance, FieldTypeHelper.ReadFieldType(reader, fieldType));
            }
            return(instance);
        }
Пример #4
0
        public static IfdEntry ParseFromByte(byte[] imageData, int startIndex, ByteOrder byteOrder)
        {
            var typeValue =
                BitConverterExtension.ToUInt16(imageData, startIndex + 2, byteOrder, BitConverterExtension.SystemByteOrder);

            if (!typeof(FieldType).IsEnumDefined(typeValue))
            {
                throw new ArgumentOutOfRangeException("Invalid field type value");
            }

            var tag   = BitConverterExtension.ToUInt16(imageData, startIndex, byteOrder, BitConverterExtension.SystemByteOrder);
            var count = BitConverterExtension.ToUInt32(imageData, startIndex + 4, byteOrder,
                                                       BitConverterExtension.SystemByteOrder);
            var value = BitConverterExtension.CopyArrayEndianness(imageData, startIndex + 8, byteOrder,
                                                                  BitConverterExtension.SystemByteOrder,
                                                                  IfdEntryValueByteLength);
            var valueLength = FieldTypeHelper.GetFieldTypeByteLength((FieldType)typeValue) * (int)count;

            if (valueLength > IfdEntryValueByteLength)
            {
                var valueOffset = BitConverterExtension.ToUInt32(value, 0, byteOrder, BitConverterExtension.SystemByteOrder);
                value = BitConverterExtension.CopyArrayEndianness(imageData, (int)valueOffset, byteOrder,
                                                                  BitConverterExtension.SystemByteOrder,
                                                                  valueLength);
            }

            return(new IfdEntry(tag, typeValue, count, value));
        }
Пример #5
0
        public void TestForReferenceTypes()
        {
            object o = (int)2; //Boxed to ref type. But the type of the value is a value type.

            Assert.That(FieldTypeHelper.IsRefType(o.GetType()), Is.False);
            int i = 3; //Value type

            Assert.That(FieldTypeHelper.IsRefType(i.GetType()), Is.False);
            string s = "123"; //Actually ref type. But it's immutable so the method should return true.

            Assert.That(FieldTypeHelper.IsRefType(s.GetType()), Is.False);
            byte[] bs = new byte[5];
            Assert.That(FieldTypeHelper.IsRefType(bs.GetType()), Is.True);
        }
Пример #6
0
 //Writes SyncedVar data in a formatted way so that the SetFormattedSyncedVarData method can read it.
 //The format doesn't NECCECARLY correspond with the "general syncedVar message layout"
 //as this should only be used for reading SyncedVar data that is to be read by the SetFormattedData method
 //*
 //The data contains every syncedvar on every behaviour that belongs to this object
 internal void WriteFormattedSyncedVarData(BitWriter writer)
 {
     for (int i = 0; i < childNetworkedBehaviours.Count; i++)
     {
         childNetworkedBehaviours[i].SyncVarInit();
         if (childNetworkedBehaviours[i].syncedVarFields.Count == 0)
         {
             continue;
         }
         writer.WriteUShort(GetOrderIndex(childNetworkedBehaviours[i])); //Write the behaviourId
         for (int j = 0; j < childNetworkedBehaviours[i].syncedVarFields.Count; j++)
         {
             FieldTypeHelper.WriteFieldType(writer, childNetworkedBehaviours[i].syncedVarFields[j].FieldValue);
         }
     }
 }
Пример #7
0
        internal static void HandleTargetRpc(uint clientId, byte[] incommingData, int channelId)
        {
            BitReader          reader       = new BitReader(incommingData);
            uint               networkId    = reader.ReadUInt();
            ushort             orderId      = reader.ReadUShort();
            ulong              hash         = reader.ReadULong();
            NetworkedBehaviour behaviour    = SpawnManager.spawnedObjects[networkId].GetBehaviourAtOrderIndex(orderId);
            MethodInfo         targetMethod = null;

            if (behaviour.cachedMethods.ContainsKey(Data.Cache.GetAttributeMethodName(hash)))
            {
                targetMethod = behaviour.cachedMethods[Data.Cache.GetAttributeMethodName(hash)];
            }
            byte paramCount = reader.ReadBits(5);

            object[] methodParams = FieldTypeHelper.ReadObjects(reader, paramCount);
            targetMethod.Invoke(behaviour, methodParams);
        }
Пример #8
0
        public void TestSequenceEquals()
        {
            Random rnd = new Random(0);

            byte[] byteArray = new byte[50];
            rnd.NextBytes(byteArray);
            Assert.That(FieldTypeHelper.SequenceEquals(byteArray, null), Is.False);
            Assert.That(FieldTypeHelper.SequenceEquals(null, byteArray), Is.False);

            Random rnd1 = new Random(0);

            for (int i = 0; i < 500; i++)
            {
                rnd = new Random(0);
                int length = rnd1.Next(100);
                if (length == 50)
                {
                    length++;
                }
                byte[] diffLengthArray = new byte[length];
                rnd.NextBytes(diffLengthArray);
                Assert.That(FieldTypeHelper.SequenceEquals(diffLengthArray, byteArray), Is.False);
                Assert.That(FieldTypeHelper.SequenceEquals(byteArray, diffLengthArray), Is.False);
            }

            rnd1 = new Random(0);
            for (int i = 0; i < 500; i++)
            {
                rnd = new Random(0);
                byte[] sameLengthDiffValues = new byte[50];
                rnd.NextBytes(byteArray);

                sameLengthDiffValues[rnd1.Next(50)] = (byte)rnd.Next(255);
                Assert.That(FieldTypeHelper.SequenceEquals(sameLengthDiffValues, byteArray), Is.False);
                Assert.That(FieldTypeHelper.SequenceEquals(byteArray, sameLengthDiffValues), Is.False);
            }

            rnd = new Random(0);
            byte[] copyOfTheArray = new byte[50];
            rnd.NextBytes(copyOfTheArray);

            Assert.That(FieldTypeHelper.SequenceEquals(copyOfTheArray, byteArray), Is.True);
            Assert.That(FieldTypeHelper.SequenceEquals(byteArray, copyOfTheArray), Is.True);
        }
Пример #9
0
        /// <summary>
        /// Deserializes binary and turns it back into the original class
        /// </summary>
        /// <typeparam name="T">The type to return</typeparam>
        /// <param name="binary">The binary to deserialize</param>
        /// <returns>An instance of T</returns>
        public static T Deserialize <T>(byte[] binary) where T : new()
        {
            T instance = new T();

            FieldInfo[] sortedFields;
            MethodInfo  postMethod;

            if (cachedFields.ContainsKey(instance.GetType().FullName))
            {
                sortedFields = cachedFields[instance.GetType().FullName];
            }
            else
            {
                sortedFields = instance.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).OrderBy(x => x.Name).Where(x => !x.IsDefined(typeof(BinaryIgnore), true)).ToArray();
                cachedFields.Add(instance.GetType().FullName, sortedFields);
            }

            if (postDeserialize.ContainsKey(instance.GetType().FullName))
            {
                postMethod = postDeserialize[instance.GetType().FullName];
            }
            else
            {
                postMethod = instance.GetType().GetMethod("PostDeserialize", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                postDeserialize.Add(instance.GetType().FullName, postMethod);
            }

            using (BitReader reader = BitReader.Get(binary))
            {
                for (int i = 0; i < sortedFields.Length; i++)
                {
                    sortedFields[i].SetValue(instance, FieldTypeHelper.ReadFieldType(reader, sortedFields[i].FieldType));
                }

                if (postMethod != null)
                {
                    postMethod.Invoke(instance, null);
                }

                return(instance);
            }
        }
Пример #10
0
        internal static object Deserialize(BitReader reader, Type type)
        {
            object instance = Activator.CreateInstance(type);

            FieldInfo[] sortedFields;
            MethodInfo  postMethod;

            if (cachedFields.ContainsKey(type.FullName))
            {
                sortedFields = cachedFields[instance.GetType().FullName];
            }
            else
            {
                sortedFields = instance.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).OrderBy(x => x.Name).Where(x => !x.IsDefined(typeof(BinaryIgnore), true)).ToArray();
                cachedFields.Add(instance.GetType().FullName, sortedFields);
            }

            if (postDeserialize.ContainsKey(instance.GetType().FullName))
            {
                postMethod = postDeserialize[instance.GetType().FullName];
            }
            else
            {
                postMethod = instance.GetType().GetMethod("PostDeserialize", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                postDeserialize.Add(instance.GetType().FullName, postMethod);
            }

            for (int i = 0; i < sortedFields.Length; i++)
            {
                sortedFields[i].SetValue(instance, FieldTypeHelper.ReadFieldType(reader, sortedFields[i].FieldType));
            }

            if (postMethod != null)
            {
                postMethod.Invoke(instance, null);
            }

            return(instance);
        }
Пример #11
0
        private bool ParseRowData(Unmarshal context, BinaryReader source)
        {
            var objex = Header as PyObjectEx;

            if (objex == null)
            {
                return(false);
            }

            var header = objex.Header as PyTuple;

            if (header == null || header.Items.Count < 2)
            {
                return(false);
            }

            var columns = header.Items[1] as PyTuple;

            if (columns == null)
            {
                return(false);
            }

            columns = columns.Items[0] as PyTuple;
            if (columns == null)
            {
                return(false);
            }

            Columns = new List <Column>(columns.Items.Count);

            foreach (var obj in columns.Items)
            {
                var fieldData = obj as PyTuple;
                if (fieldData == null || fieldData.Items.Count < 2)
                {
                    continue;
                }

                var name = fieldData.Items[0] as PyString;
                if (name == null)
                {
                    continue;
                }

                Columns.Add(new Column(name.Value, (FieldType)fieldData.Items[1].IntValue));
            }

            var sizeList = Columns.OrderByDescending(c => FieldTypeHelper.GetTypeBits(c.Type));
            var sizeSum  = sizeList.Sum(c => FieldTypeHelper.GetTypeBits(c.Type));

            // align
            sizeSum = (sizeSum + 7) >> 3;
            var rawStream = new MemoryStream();

            // fill up
            rawStream.Write(RawData, 0, RawData.Length);
            for (int i = 0; i < (sizeSum - RawData.Length); i++)
            {
                rawStream.WriteByte(0);
            }
            rawStream.Seek(0, SeekOrigin.Begin);
            var reader = new BinaryReader(rawStream);

            int bitOffset = 0;

            foreach (var column in sizeList)
            {
                switch (column.Type)
                {
                case FieldType.I8:
                case FieldType.UI8:
                case FieldType.CY:
                case FieldType.FileTime:
                    column.Value = new PyLongLong(reader.ReadInt64());
                    break;

                case FieldType.I4:
                case FieldType.UI4:
                    column.Value = new PyInt(reader.ReadInt32());
                    break;

                case FieldType.I2:
                case FieldType.UI2:
                    column.Value = new PyInt(reader.ReadInt16());
                    break;

                case FieldType.I1:
                case FieldType.UI1:
                    column.Value = new PyInt(reader.ReadByte());
                    break;

                case FieldType.R8:
                    column.Value = new PyFloat(reader.ReadDouble());
                    break;

                case FieldType.R4:
                    column.Value = new PyFloat(reader.ReadSingle());
                    break;

                case FieldType.Bytes:
                case FieldType.Str:
                case FieldType.WStr:
                    column.Value = context.ReadObject(source);
                    break;

                case FieldType.Bool:
                {
                    if (7 < bitOffset)
                    {
                        bitOffset = 0;
                        reader.ReadByte();
                    }

                    var b = reader.ReadByte();
                    reader.BaseStream.Seek(-1, SeekOrigin.Current);
                    column.Value = new PyInt((b >> bitOffset++) & 0x01);
                    break;
                }

                default:
                    throw new Exception("No support for " + column.Type);
                }
            }

            return(true);
        }
        internal static void HandleSyncVarUpdate(uint clientId, BitReader reader, int channelId)
        {
            uint   netId      = reader.ReadUInt();
            ushort orderIndex = reader.ReadUShort();

            if (!SpawnManager.spawnedObjects.ContainsKey(netId))
            {
                if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                {
                    LogHelper.LogWarning("Sync message recieved for a non existant object with id: " + netId);
                }
                return;
            }
            else if (SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex) == null)
            {
                if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                {
                    LogHelper.LogWarning("Sync message recieved for a non existant behaviour");
                }
                return;
            }

            for (int i = 0; i < SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).syncedVarFields.Count; i++)
            {
                if (!reader.ReadBool())
                {
                    continue;
                }
                SyncedVarField field = SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).syncedVarFields[i];
                SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate(FieldTypeHelper.ReadFieldType(reader,
                                                                                                                                      field.FieldInfo.FieldType, field.FieldValue), i);
            }
            SpawnManager.spawnedObjects[netId].GetBehaviourAtOrderIndex(orderIndex).OnSyncVarUpdate();
        }
Пример #13
0
 //Reads formatted data that the "WriteFormattedSyncedVarData" has written and applies the values to SyncedVar fields
 internal void SetFormattedSyncedVarData(BitReader reader)
 {
     for (int i = 0; i < childNetworkedBehaviours.Count; i++)
     {
         childNetworkedBehaviours[i].SyncVarInit();
         if (childNetworkedBehaviours[i].syncedVarFields.Count == 0)
         {
             continue;
         }
         NetworkedBehaviour behaviour = GetBehaviourAtOrderIndex(reader.ReadUShort());
         for (int j = 0; j < childNetworkedBehaviours[i].syncedVarFields.Count; j++)
         {
             childNetworkedBehaviours[i].syncedVarFields[j].FieldInfo.SetValue(behaviour,
                                                                               FieldTypeHelper.ReadFieldType(reader, childNetworkedBehaviours[i].syncedVarFields[j].FieldInfo.FieldType));
         }
         behaviour.OnSyncVarUpdate();
     }
 }
Пример #14
0
        protected override void EncodeInternal(BinaryWriter output)
        {
            output.Write((byte)MarshalOpcode.PackedRow);
            Header.Encode(output);

            int cc = Columns.Count;

            var rawStream = new MemoryStream();
            var writer    = new BinaryWriter(rawStream);
            var reader    = new BinaryReader(rawStream);

            var sizeList = Columns.OrderByDescending(c => FieldTypeHelper.GetTypeBits(c.Type));

            foreach (Column col in sizeList)
            {
                switch (col.Type)
                {
                case FieldType.I8:
                case FieldType.UI8:
                case FieldType.CY:
                case FieldType.FileTime:
                    writer.Write(col.Value.IntValue);
                    break;

                case FieldType.I4:
                case FieldType.UI4:
                    writer.Write((int)(col.Value.IntValue));
                    break;

                case FieldType.I2:
                case FieldType.UI2:
                    writer.Write((short)(col.Value.IntValue));
                    break;

                case FieldType.I1:
                case FieldType.UI1:
                    writer.Write((byte)(col.Value.IntValue));
                    break;

                case FieldType.R8:
                    writer.Write((double)(col.Value.FloatValue));
                    break;

                case FieldType.R4:
                    writer.Write((float)(col.Value.FloatValue));
                    break;

                case FieldType.Bool:
                    writer.Write((byte)(col.Value.IntValue));
                    break;

                case FieldType.Bytes:
                    writer.Write((col.Value as PyBuffer).Data);
                    break;

                case FieldType.Str:
                case FieldType.WStr:
                    col.Value.Encode(output);
                    break;

                default:
                    throw new Exception("Unsupported FieldType");
                }
            }

            long bitByte   = 0;
            byte bitOffset = 0;

            byte[] unpacked = rawStream.ToArray();
            rawStream.Close();

            foreach (Column col in Columns)
            {
                if (FieldTypeHelper.GetTypeBits(col.Type) != 1)
                {
                    continue;
                }

                PyBool value = col.Value as PyBool;

                if (bitOffset > 7)
                {
                    bitOffset = 0;
                }

                if (bitOffset == 0)
                {
                    bitByte = unpacked.Length + 1;
                    Array.Resize <byte>(ref unpacked, (int)(bitByte));
                }

                unpacked[bitByte] |= (byte)(((value.Value == true) ? 1 : 0) << bitOffset++);
            }

            rawStream = new MemoryStream(unpacked);
            reader    = new BinaryReader(rawStream);

            ZeroCompress(reader, rawStream, output);

            foreach (Column col in Columns)
            {
                col.Value.Encode(output);
            }

            reader.Close();
        }
Пример #15
0
        private bool ParseRowData(Unmarshal context, BinaryReader source)
        {
            if (Descriptor == null)
            {
                return(false);
            }

            values = new PyRep[Descriptor.Columns.Count];
            var sizeList = Descriptor.Columns.OrderByDescending(c => FieldTypeHelper.GetTypeBits(c.Type));
            var sizeSum  = sizeList.Sum(c => FieldTypeHelper.GetTypeBits(c.Type));

            // align
            sizeSum = (sizeSum + 7) >> 3;
            var rawStream = new MemoryStream();

            // fill up
            rawStream.Write(RawData, 0, RawData.Length);
            for (int i = 0; i < (sizeSum - RawData.Length); i++)
            {
                rawStream.WriteByte(0);
            }
            rawStream.Seek(0, SeekOrigin.Begin);
            var reader = new BinaryReader(rawStream);

            int bitOffset = 0;

            foreach (var column in sizeList)
            {
                PyRep value = null;
                switch (column.Type)
                {
                case FieldType.I8:
                case FieldType.UI8:
                case FieldType.CY:
                case FieldType.FileTime:
                    value = new PyLongLong(reader.ReadInt64());
                    break;

                case FieldType.I4:
                case FieldType.UI4:
                    value = new PyInt(reader.ReadInt32());
                    break;

                case FieldType.I2:
                case FieldType.UI2:
                    value = new PyInt(reader.ReadInt16());
                    break;

                case FieldType.I1:
                case FieldType.UI1:
                    value = new PyInt(reader.ReadByte());
                    break;

                case FieldType.R8:
                    value = new PyFloat(reader.ReadDouble());
                    break;

                case FieldType.R4:
                    value = new PyFloat(reader.ReadSingle());
                    break;

                case FieldType.Bytes:
                case FieldType.Str:
                case FieldType.WStr:
                    value = context.ReadObject(source);
                    break;

                case FieldType.Bool:
                {
                    if (7 < bitOffset)
                    {
                        bitOffset = 0;
                        reader.ReadByte();
                    }

                    var b = reader.ReadByte();
                    reader.BaseStream.Seek(-1, SeekOrigin.Current);
                    value = new PyInt((b >> bitOffset++) & 0x01);
                    break;
                }

                case FieldType.Token:
                    value = new PyToken(column.Token);
                    break;

                default:
                    throw new Exception("No support for " + column.Type);
                }
                int index = Descriptor.Columns.FindIndex(x => x.Name == column.Name);
                values[index] = value;
            }

            return(true);
        }
Пример #16
0
            public static ModelData Create(CacheFile file)
            {
                var ret = new ModelData {
                    Name = ShortenName(file.Name)
                };
                var rows = file.GetRows();

                ret.Rows = rows;
                if (rows.Count() == 0)
                {
                    throw new InvalidDataException("Cache is empty");
                }
                var singleRow = rows.First();

                ret.SingleRow = singleRow;

                // we need to go through all rows to find the maximum size type of all columns
                var fieldTypes = new FieldType[singleRow.Columns.Count];

                for (int i = 0; i < singleRow.Columns.Count; i++)
                {
                    fieldTypes[i] = singleRow.Columns[i].Type;
                }
                foreach (var row in rows)
                {
                    for (int i = 0; i < row.Columns.Count; i++)
                    {
                        if (FieldTypeHelper.GetTypeBits(row.Columns[i].Type) > FieldTypeHelper.GetTypeBits(fieldTypes[i]))
                        {
                            fieldTypes[i] = row.Columns[i].Type;
                        }
                    }
                }
                ret.FieldTypes = fieldTypes;

                // now build the creation query - fields, primary key, indices, cleanup
                var query = new StringBuilder();

                query.AppendLine("DROP TABLE IF EXISTS " + ret.Name + ";");
                query.AppendLine("CREATE TABLE " + ret.Name + " (");

                bool   createAutoIncrement = !IsColumnUnique(rows, 0);
                string autoIncrementName   = createAutoIncrement ? (singleRow.Columns.Any(c => c.Name == "id") ? "index" : "id") : "";

                if (createAutoIncrement)
                {
                    query.AppendLine(Indention + autoIncrementName + " INT AUTO_INCREMENT,");
                }

                for (int i = 0; i < singleRow.Columns.Count; i++)
                {
                    query.AppendLine(Indention + singleRow.Columns[i].Name + " " + GetSQLType(fieldTypes[i]) + ",");
                }

                if (createAutoIncrement)
                {
                    query.AppendLine(Indention + "PRIMARY KEY (" + autoIncrementName + "),");
                }
                else
                {
                    query.AppendLine(Indention + "PRIMARY KEY (" + singleRow.Columns[0].Name + "),");
                }

                for (int i = 1; i < singleRow.Columns.Count; i++)
                {
                    if (singleRow.Columns[i].Name.EndsWith("ID"))
                    {
                        query.AppendLine(Indention + "INDEX " + singleRow.Columns[i].Name + " (" + singleRow.Columns[i].Name + "),");
                    }
                }

                if (query[query.Length - 1] == '\n' && query[query.Length - 2] == '\r' && query[query.Length - 3] == ',')
                {
                    query.Remove(query.Length - 3, 1);
                }
                query.AppendLine(");");

                ret.CreationQuery = query.ToString();
                return(ret);
            }