コード例 #1
0
 /// <inheritdoc />
 public virtual void Connect(IDatabase database, TableFlags flags, RowLayout layout) => BaseTable.Connect(database, flags, layout);
コード例 #2
0
 /// <inheritdoc />
 public virtual void UseLayout(RowLayout layout) => BaseTable.UseLayout(layout);
コード例 #3
0
 /// <inheritdoc />
 public override void Connect(IDatabase database, TableFlags flags, RowLayout layout) => BaseTable.Connect(database, flags, layout);
コード例 #4
0
 /// <inheritdoc />
 public abstract void Connect(IDatabase database, TableFlags flags, RowLayout layout);
コード例 #5
0
        /// <summary>Scans a Table for matches with the current search.</summary>
        /// <param name="preselected">The preselected ids.</param>
        /// <param name="layout">Layout of the table.</param>
        /// <param name="indices">FieldIndices or null.</param>
        /// <param name="table">The table to scan.</param>
        /// <returns>All rows matching this search.</returns>
        public IEnumerable <Row> Scan(IEnumerable <Row> preselected, RowLayout layout, IFieldIndex[] indices, ITable table)
        {
            if (table == null)
            {
                throw new ArgumentNullException(nameof(table));
            }
            if (layout == null)
            {
                throw new ArgumentNullException(nameof(layout));
            }

            LoadLayout(layout);
            switch (Mode)
            {
            case SearchMode.None:
            {
                if (Inverted)
                {
                    throw new InvalidOperationException("Cannot invert an empty search!");
                }

                return(table.GetRows() ?? preselected);
            }

            case SearchMode.And:
            {
                var resultA = SearchA.Scan(preselected, layout, indices, table);
                var result  = SearchB.Scan(resultA, layout, indices, table);
                return(!Inverted ? result : Invert(preselected ?? table.GetRows(), result));
            }

            case SearchMode.Or:
            {
                var result  = SearchA.Scan(preselected, layout, indices, table);
                var resultB = SearchB.Scan(preselected, layout, indices, table);
                result = result.Union(resultB).ToList();
                return(Inverted ? Invert(preselected ?? table.GetRows(), result) : result);
            }

            case SearchMode.In:
            {
                IEnumerable <Row> result = new List <Row>();
                foreach (var value in (Set <object>)FieldValue)
                {
                    result = result.Union(table.GetRows(FieldEquals(FieldName, value)));
                }

                return(Inverted ? Invert(preselected ?? table.GetRows(), result) : result);
            }

            case SearchMode.Smaller:
            case SearchMode.Greater:
            case SearchMode.SmallerOrEqual:
            case SearchMode.GreaterOrEqual:
            case SearchMode.Like:
            case SearchMode.Equals:
            {
                if (Mode == SearchMode.Equals)
                {
                    // check if we can do an index search
                    if ((indices != null) && (indices[FieldNumber] != null))
                    {
                        // field has an index
                        var result = indices[FieldNumber].Find(FieldValue).Select(r => new Row(Layout, r, true));
                        if (preselected != null)
                        {
                            result = result.Intersect(preselected);
                        }

                        return(Inverted ? Invert(preselected ?? table.GetRows(), result) : result);
                    }
#if DEBUG
                    // field has no index, need table scan
                    if ((preselected == null) && (table.RowCount > 1000))
                    {
                        Debug.WriteLine(
                            $"Warning: Doing slow memory search on Table {layout.Name} Field {FieldName}! You should consider adding an index!");
                    }
#endif
                }

                // scan without index
                {
                    var result = new List <Row>();
                    if (preselected != null)
                    {
                        foreach (var row in preselected)
                        {
                            if (Check(row))
                            {
                                result.Add(row);
                            }
                        }
                    }
                    else
                    {
                        foreach (var row in table.GetRows())
                        {
                            if (Check(row))
                            {
                                result.Add(row);
                            }
                        }
                    }

                    return(result);
                }
            }

            default: throw new NotImplementedException($"Mode {Mode} not implemented!");
            }
        }
コード例 #6
0
        internal static RowLayout LoadFieldDefinition(DataReader reader, out int version)
        {
            var dateTimeKind   = DateTimeKind.Unspecified;
            var dateTimeType   = DateTimeType.Undefined;
            var stringEncoding = StringEncoding.UTF8;

            if (reader.ReadString(8) != "DatTable")
            {
                throw new FormatException();
            }

            version = reader.Read7BitEncodedInt32();
            if ((version < 1) || (version > 4))
            {
                throw new InvalidDataException("Unknown Table version!");
            }

            // read name and create layout
            var layoutName = reader.ReadString();
            var fieldCount = reader.Read7BitEncodedInt32();
            var fields     = new FieldProperties[fieldCount];

            for (var i = 0; i < fieldCount; i++)
            {
                var fieldName        = reader.ReadString();
                var dataType         = (DataType)reader.Read7BitEncodedInt32();
                var fieldFlags       = (FieldFlags)reader.Read7BitEncodedInt32();
                var databaseDataType = dataType;
                switch (dataType)
                {
                case DataType.Enum:
                    databaseDataType = DataType.Int64;
                    break;

                case DataType.User:
                case DataType.String:
                    databaseDataType = DataType.String;
                    if (version > 2)
                    {
                        stringEncoding = (StringEncoding)reader.Read7BitEncodedInt32();
                    }
                    else
                    {
                        stringEncoding = StringEncoding.UTF8;
                    }

                    break;

                case DataType.TimeSpan:
                    if (version > 3)
                    {
                        dateTimeType = (DateTimeType)reader.Read7BitEncodedInt32();
                    }

                    break;

                case DataType.DateTime:
                    if (version > 1)
                    {
                        dateTimeKind = (DateTimeKind)reader.Read7BitEncodedInt32();
                        dateTimeType = (DateTimeType)reader.Read7BitEncodedInt32();
                    }
                    else
                    {
                        dateTimeKind = DateTimeKind.Utc;
                        dateTimeType = DateTimeType.BigIntHumanReadable;
                    }

                    break;
                }

                Type valueType = null;
                if ((dataType & DataType.MaskRequireValueType) != 0)
                {
                    var typeName = reader.ReadString();
                    valueType = AppDom.FindType(typeName.BeforeFirst(','), typeName.AfterFirst(',').Trim());
                }

                var field = fields[i] = new FieldProperties
                {
                    Index          = i,
                    Flags          = fieldFlags,
                    DataType       = dataType,
                    ValueType      = valueType,
                    Name           = fieldName,
                    TypeAtDatabase = databaseDataType,
                    NameAtDatabase = fieldName,
                    DateTimeType   = dateTimeType,
                    DateTimeKind   = dateTimeKind,
                    StringEncoding = stringEncoding
                };
                field.Validate();
            }

            return(RowLayout.CreateUntyped(layoutName, fields));
        }
コード例 #7
0
 /// <summary>Builds the csharp code file containing the row layout structure.</summary>
 /// <param name="layout">The layout to use.</param>
 /// <param name="databaseName">The database name (only used for the structure name).</param>
 /// <param name="tableName">The table name (only used for the structure name).</param>
 /// <param name="className">The name of the class to generate.</param>
 /// <param name="structFile">The struct file name (defaults to classname.cs).</param>
 /// <param name="namingStrategy">Naming strategy for classes, properties, structures and fields.</param>
 /// <returns>The struct file name.</returns>
 public static GenerateTableCodeResult GenerateStructFile(this RowLayout layout, string databaseName = null, string tableName = null,
                                                          string className = null, string structFile = null, NamingStrategy namingStrategy = NamingStrategy.CamelCase)
 => GenerateStruct(layout, databaseName, tableName, className, namingStrategy).SaveStructFile(structFile);
コード例 #8
0
 /// <summary>Not supported.</summary>
 /// <param name="layout">Unused parameter.</param>
 public override void UseLayout(RowLayout layout) => throw new NotSupportedException();
コード例 #9
0
ファイル: CSVReader.cs プロジェクト: CaveSystems/cave-data
        /// <summary>
        /// Parses a single row of data from the specified string.
        /// </summary>
        /// <param name="properties">The csv properties.</param>
        /// <param name="layout">The row layout.</param>
        /// <param name="data">The buffer to parse.</param>
        /// <returns>Returns a new <see cref="Row"/> instance.</returns>
        public static Row ParseRow(CsvProperties properties, RowLayout layout, string data)
        {
            if (!properties.Valid)
            {
                throw new ArgumentException("CsvProperties invalid!", nameof(properties));
            }

            if (layout == null)
            {
                throw new ArgumentNullException(nameof(layout));
            }

            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            try
            {
                var fieldCount       = layout.FieldCount;
                var fieldNumber      = 0;
                var ident            = new Queue <char>();
                var identInARowCount = 0;
                var currentValue     = new List <char>();
                var i      = -1;
                var values = new object[fieldCount];
                while (fieldNumber < fieldCount)
                {
                    ++i;
                    if ((i == data.Length) && (fieldNumber == (fieldCount - 1)))
                    {
                        break;
                    }

                    if (i >= data.Length)
                    {
                        throw new InvalidDataException("Unexpected end of input!");
                    }

                    if (properties.Separator == data[i])
                    {
                        if (ident.Count == 0)
                        {
                            identInARowCount = 0;
                            if (properties.StringMarker.HasValue)
                            {
                                values[fieldNumber] = layout.ParseValue(fieldNumber, new string(currentValue.ToArray()).Unescape(),
                                                                        properties.StringMarker.Value.ToString(), properties.Format);
                            }
                            else
                            {
                                values[fieldNumber] = layout.ParseValue(fieldNumber, new string(currentValue.ToArray()).Unescape(), string.Empty,
                                                                        properties.Format);
                            }

                            fieldNumber++;
                            currentValue.Clear();
                            continue;
                        }
                    }

                    if (properties.StringMarker == data[i])
                    {
                        identInARowCount++;
                        if ((ident.Count > 0) && (ident.Peek() == data[i]))
                        {
                            ident.Dequeue();
                            if (identInARowCount > 1)
                            {
                                // escaped char
                                currentValue.Add(data[i]);
                            }
                        }
                        else
                        {
                            ident.Enqueue(data[i]);
                        }
                    }
                    else
                    {
                        identInARowCount = 0;
                        currentValue.Add(data[i]);
                    }
                }

                if (ident.Count > 0)
                {
                    throw new InvalidDataException("Invalid ident/escaping!");
                }

                if (properties.StringMarker.HasValue)
                {
                    values[fieldNumber] = layout.ParseValue(fieldNumber, new string(currentValue.ToArray()).Unescape(),
                                                            properties.StringMarker.Value.ToString(), properties.Format);
                }
                else
                {
                    values[fieldNumber] = layout.ParseValue(fieldNumber, new string(currentValue.ToArray()).Unescape(), string.Empty, properties.Format);
                }

                fieldNumber++;
                if (i < data.Length)
                {
                    if (properties.Separator == data[i])
                    {
                        i++;
                    }

                    if (i < data.Length)
                    {
                        throw new InvalidDataException("Additional data at end of line!");
                    }
                }

                return(new Row(layout, values, false));
            }
            catch (EndOfStreamException)
            {
                if (data.Length > 0)
                {
                    throw;
                }

                return(null);
            }
        }
コード例 #10
0
 /// <inheritdoc />
 public ITable GetTable(RowLayout layout, TableFlags flags = default) => database.GetTable(layout, flags);
コード例 #11
0
ファイル: CSVReader.cs プロジェクト: CaveSystems/cave-data
        /// <summary>
        /// Initializes a new instance of the <see cref="CsvReader"/> class.
        /// </summary>
        /// <param name="properties">Properties to apply to the reader.</param>
        /// <param name="layout">Layout to use when reading the csv data.</param>
        /// <param name="stream">Stream to read data from.</param>
        /// <param name="closeBaseStream">if set to <c>true</c> [close base stream on close].</param>
        public CsvReader(RowLayout layout, Stream stream, CsvProperties properties = default, bool closeBaseStream = false)
        {
            Layout          = layout;
            BaseStream      = stream ?? throw new ArgumentNullException(nameof(stream));
            Properties      = properties.Valid ? properties : CsvProperties.Default;
            CloseBaseStream = closeBaseStream;
            reader          = new DataReader(stream, Properties.Encoding, Properties.NewLineMode);
            if (!Properties.NoHeader)
            {
                var header = reader.ReadLine();
                currentRowNumber++;
                var fields = header.Split(Properties.Separator);
                if (!Properties.AllowFieldMatching)
                {
                    if (fields.Length != Layout.FieldCount)
                    {
                        if ((fields.Length - 1) != Layout.FieldCount)
                        {
                            throw new InvalidDataException($"Invalid header fieldcount (expected '{Layout.FieldCount}' got '{fields.Length}')!");
                        }
                    }
                }
                else
                {
                    if (fields.Length != Layout.FieldCount)
                    {
                        fieldNumberMatching = new int[Layout.FieldCount];
                    }
                }

                var count = Math.Min(Layout.FieldCount, fields.Length);
                for (var i = 0; i < count; i++)
                {
                    var fieldName  = fields[i].UnboxText(false);
                    var fieldIndex = Layout.GetFieldIndex(fieldName, false);
                    if (fieldIndex < 0)
                    {
                        throw new InvalidDataException(
                                  $"Error loading CSV Header! Got field name '{fieldName}' instead of '{Layout[i].Name}' at type '{Layout.Name}'");
                    }

                    if (!Properties.AllowFieldMatching)
                    {
                        if (fieldIndex != i)
                        {
                            throw new InvalidDataException($"Fieldposition of Field '{fieldName}' does not match!");
                        }

                        if (!string.Equals(Layout[fieldIndex].Name, fieldName, StringComparison.Ordinal))
                        {
                            throw new InvalidDataException(
                                      $"Invalid header value at field number '{i}' name '{fieldName}' expected '{Layout[fieldIndex].Name}'!");
                        }
                    }
                    else
                    {
                        if ((fieldNumberMatching == null) && (fieldIndex != i))
                        {
                            fieldNumberMatching = new int[Layout.FieldCount];
                        }
                    }
                }

                if (fieldNumberMatching != null)
                {
                    var i = 0;
                    for (; i < count; i++)
                    {
                        var fieldName = fields[i].UnboxText(false);
                        fieldNumberMatching[i] = Layout.GetFieldIndex(fieldName, false);
                    }

                    for (; i < Layout.FieldCount; i++)
                    {
                        fieldNumberMatching[i] = -1;
                    }
                }
            }
        }
コード例 #12
0
ファイル: CSVReader.cs プロジェクト: CaveSystems/cave-data
 /// <summary>
 /// Initializes a new instance of the <see cref="CsvReader"/> class.
 /// </summary>
 /// <param name="properties">Properties to apply to the reader.</param>
 /// <param name="layout">Layout to use when reading from the csv file.</param>
 /// <param name="fileName">Filename to write to.</param>
 public CsvReader(RowLayout layout, string fileName, CsvProperties properties = default)
     : this(layout, File.OpenRead(fileName), properties, true)
 {
 }
コード例 #13
0
 /// <inheritdoc />
 public abstract void UseLayout(RowLayout layout);
コード例 #14
0
        static void SerializeData(DataWriter writer, RowLayout layout, Row row)
        {
            for (var i = 0; i < layout.FieldCount; i++)
            {
                var dataType = layout[i].DataType;
                switch (dataType)
                {
                case DataType.Binary:
                {
                    var data = (byte[])row[i];
                    if (data == null)
                    {
                        data = new byte[0];
                    }

                    writer.Write7BitEncoded32(data.Length);
                    writer.Write(data);
                    break;
                }

                case DataType.Bool:
                    writer.Write((bool)row[i]);
                    break;

                case DataType.TimeSpan:
                    writer.Write((TimeSpan)row[i]);
                    break;

                case DataType.DateTime:
                    writer.Write((DateTime)row[i]);
                    break;

                case DataType.Single:
                    writer.Write((float)row[i]);
                    break;

                case DataType.Double:
                    writer.Write((double)row[i]);
                    break;

                case DataType.Int8:
                    writer.Write((sbyte)row[i]);
                    break;

                case DataType.Int16:
                    writer.Write((short)row[i]);
                    break;

                case DataType.UInt8:
                    writer.Write((byte)row[i]);
                    break;

                case DataType.UInt16:
                    writer.Write((ushort)row[i]);
                    break;

                case DataType.Int32:
                    writer.Write7BitEncoded32((int)row[i]);
                    break;

                case DataType.Int64:
                    writer.Write7BitEncoded64((long)row[i]);
                    break;

                case DataType.UInt32:
                    writer.Write7BitEncoded32((uint)row[i]);
                    break;

                case DataType.UInt64:
                    writer.Write7BitEncoded64((ulong)row[i]);
                    break;

                case DataType.Char:
                    writer.Write((char)row[i]);
                    break;

                case DataType.Decimal:
                    writer.Write((decimal)row[i]);
                    break;

                case DataType.String:
                case DataType.User:
                {
                    var data = row[i];
                    var str  = data?.ToString();
                    writer.WritePrefixed(str);
                    break;
                }

                case DataType.Enum:
                {
                    var value = Convert.ToInt64(row[i], CultureInfo.InvariantCulture);
                    writer.Write7BitEncoded64(value);
                    break;
                }

                default:
                    throw new NotImplementedException($"Datatype {dataType} not implemented!");
                }
            }
        }
コード例 #15
0
ファイル: Row.cs プロジェクト: elfen20/clone-cave-data
        /// <summary>Obtains a row value as string using the string format defined at the rowlayout.</summary>
        /// <param name="layout">The layout.</param>
        /// <param name="index">The field index.</param>
        /// <returns>The string to display.</returns>
        public string GetDisplayString(RowLayout layout, int index)
        {
            var value = Values[index];

            return(value == null ? string.Empty : layout.GetDisplayString(index, value));
        }
コード例 #16
0
        static Row DeserializeData(DataReader reader, RowLayout layout)
        {
            var values = new object[layout.FieldCount];

            for (var i = 0; i < layout.FieldCount; i++)
            {
                var dataType = layout[i].DataType;
                switch (dataType)
                {
                case DataType.Binary:
                    var size = reader.Read7BitEncodedInt32();
                    values[i] = reader.ReadBytes(size);
                    break;

                case DataType.Bool:
                    values[i] = reader.ReadBool();
                    break;

                case DataType.DateTime:
                    values[i] = reader.ReadDateTime();
                    break;

                case DataType.TimeSpan:
                    values[i] = reader.ReadTimeSpan();
                    break;

                case DataType.Int8:
                    values[i] = reader.ReadInt8();
                    break;

                case DataType.Int16:
                    values[i] = reader.ReadInt16();
                    break;

                case DataType.Int32:
                    values[i] = reader.Read7BitEncodedInt32();
                    break;

                case DataType.Int64:
                    values[i] = reader.Read7BitEncodedInt64();
                    break;

                case DataType.UInt32:
                    values[i] = reader.Read7BitEncodedUInt32();
                    break;

                case DataType.UInt64:
                    values[i] = reader.Read7BitEncodedUInt64();
                    break;

                case DataType.UInt8:
                    values[i] = reader.ReadUInt8();
                    break;

                case DataType.UInt16:
                    values[i] = reader.ReadUInt16();
                    break;

                case DataType.Char:
                    values[i] = reader.ReadChar();
                    break;

                case DataType.Single:
                    values[i] = reader.ReadSingle();
                    break;

                case DataType.Double:
                    values[i] = reader.ReadDouble();
                    break;

                case DataType.Decimal:
                    values[i] = reader.ReadDecimal();
                    break;

                case DataType.String:
                    values[i] = reader.ReadString();
                    break;

                case DataType.Enum:
                    values[i] = reader.Read7BitEncodedInt64();
                    break;

                case DataType.User:
                    values[i] = reader.ReadString();
                    break;

                default: throw new NotImplementedException($"Datatype {dataType} not implemented!");
                }
            }

            return(new Row(layout, values, false));
        }
コード例 #17
0
ファイル: DatWriter.cs プロジェクト: elfen20/clone-cave-data
        void WriteFieldDefinition(DataWriter writer, RowLayout layout, int version)
        {
            if (version < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(version));
            }

            if (version > 4)
            {
                throw new NotSupportedException("Version not supported!");
            }

            try
            {
                writer.Write("DatTable");
                writer.Write7BitEncoded32(version);
                writer.WritePrefixed(layout.Name);
                writer.Write7BitEncoded32(layout.FieldCount);
                for (var i = 0; i < layout.FieldCount; i++)
                {
                    var field = layout[i];
                    writer.WritePrefixed(field.Name);
                    writer.Write7BitEncoded32((int)field.DataType);
                    writer.Write7BitEncoded32((int)field.Flags);
                    switch (field.DataType)
                    {
                    case DataType.User:
                    case DataType.String:
                        if (version > 2)
                        {
                            writer.Write7BitEncoded32((int)field.StringEncoding);
                        }

                        break;

                    case DataType.DateTime:
                        if (version > 1)
                        {
                            writer.Write7BitEncoded32((int)field.DateTimeKind);
                            writer.Write7BitEncoded32((int)field.DateTimeType);
                        }

                        break;

                    case DataType.TimeSpan:
                        if (version > 3)
                        {
                            writer.Write7BitEncoded32((int)field.DateTimeType);
                        }

                        break;
                    }

                    if ((field.DataType & DataType.MaskRequireValueType) != 0)
                    {
                        var typeName = field.ValueType.AssemblyQualifiedName;
                        var parts    = typeName.Split(',');
                        typeName = $"{parts[0]},{parts[1]}";
                        writer.WritePrefixed(typeName);
                    }
                }

                writer.Flush();
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("Could not write field definition!", ex);
            }
        }
コード例 #18
0
 /// <inheritdoc />
 public abstract ITable CreateTable(RowLayout layout, TableFlags flags = default);
コード例 #19
0
ファイル: DatWriter.cs プロジェクト: elfen20/clone-cave-data
 /// <summary>Initializes a new instance of the <see cref="DatWriter" /> class.</summary>
 /// <param name="layout">Table layout.</param>
 /// <param name="fileName">Filename to write to.</param>
 public DatWriter(RowLayout layout, string fileName)
     : this(layout, File.Create(fileName))
 {
 }
コード例 #20
0
        /// <summary>Builds the csharp code containing the row layout structure.</summary>
        /// <param name="layout">The layout to use.</param>
        /// <param name="databaseName">The database name (only used for the structure name).</param>
        /// <param name="tableName">The table name (only used for the structure name).</param>
        /// <param name="className">The name of the class to generate.</param>
        /// <param name="nameSpace">The namespace to use for the class (defaults to "Database").</param>
        /// <param name="namingStrategy">Naming strategy for classes, properties, structures and fields.</param>
        /// <returns>Returns a string containing csharp code.</returns>
        public static GenerateTableCodeResult GenerateStruct(this RowLayout layout, string databaseName, string tableName = null, string className = null,
                                                             string nameSpace = null, NamingStrategy namingStrategy = NamingStrategy.CamelCase)
        {
            if (layout == null)
            {
                throw new ArgumentNullException(nameof(layout));
            }

            #region GetName()

            string[] GetNameParts(string text) => text.ReplaceInvalidChars(ASCII.Strings.Letters + ASCII.Strings.Digits, "_").Split('_').SelectMany(s => s.SplitCamelCase()).ToArray();

            string GetName(string text) =>
            namingStrategy switch
            {
                NamingStrategy.CamelCase => GetNameParts(text).JoinCamelCase(),
                NamingStrategy.SnakeCase => GetNameParts(text).JoinSnakeCase(),
                NamingStrategy.Exact => text,
                _ => throw new NotImplementedException($"Unknown NamingStrategy {namingStrategy}.")
            };

            #endregion

            if (nameSpace == null)
            {
                nameSpace = "Database";
            }

            if (databaseName == null)
            {
                throw new ArgumentNullException(nameof(databaseName));
            }

            if (tableName == null)
            {
                tableName = layout.Name;
            }

            var fieldNameLookup = new Dictionary <int, string>();
            var idCount         = layout.Identifier.Count();
            var idFields        = (idCount == 0 ? layout : layout.Identifier).ToList();
            var code            = new StringBuilder();
            code.AppendLine("//-----------------------------------------------------------------------");
            code.AppendLine("// <summary>");
            code.AppendLine("// Autogenerated table class");
            code.AppendLine($"// Using {typeof(ITableExtensions).Assembly.FullName}");
            code.AppendLine("// </summary>");
            code.AppendLine("// <auto-generated />");
            code.AppendLine("//-----------------------------------------------------------------------");
            code.AppendLine();
            code.AppendLine("using System;");
            code.AppendLine("using System.Globalization;");
            code.AppendLine("using Cave.Data;");

            #region Build lookup tables

            void BuildLookupTables()
            {
                var uniqueFieldNames = new IndexedSet <string>();

                foreach (var field in layout)
                {
                    var sharpName = GetName(field.Name);
                    var i         = 0;
                    while (uniqueFieldNames.Contains(sharpName))
                    {
                        sharpName = GetName(field.Name) + ++i;
                    }

                    uniqueFieldNames.Add(sharpName);
                    fieldNameLookup[field.Index] = sharpName;
                }
            }

            BuildLookupTables();

            #endregion

            if (className == null)
            {
                className = GetName(databaseName) + GetName(tableName) + "Row";
            }

            code.AppendLine();
            code.AppendLine($"namespace {nameSpace}");
            code.AppendLine("{");
            code.AppendLine($"\t/// <summary>Table structure for {layout.Name}.</summary>");
            code.AppendLine($"\t[Table(\"{layout.Name}\")]");
            code.AppendLine($"\tpublic partial struct {className} : IEquatable<{className}>");
            code.AppendLine("\t{");

            #region static Parse()

            code.AppendLine($"\t\t/// <summary>Converts the string representation of a row to its {className} equivalent.</summary>");
            code.AppendLine("\t\t/// <param name=\"data\">A string that contains a row to convert.</param>");
            code.AppendLine($"\t\t/// <returns>A new {className} instance.</returns>");
            code.AppendLine($"\t\tpublic static {className} Parse(string data) => Parse(data, CultureInfo.InvariantCulture);");
            code.AppendLine();
            code.AppendLine($"\t\t/// <summary>Converts the string representation of a row to its {className} equivalent.</summary>");
            code.AppendLine("\t\t/// <param name=\"data\">A string that contains a row to convert.</param>");
            code.AppendLine("\t\t/// <param name=\"provider\">The format provider (optional).</param>");
            code.AppendLine($"\t\t/// <returns>A new {className} instance.</returns>");
            code.AppendLine($"\t\tpublic static {className} Parse(string data, IFormatProvider provider) => CsvReader.ParseRow<{className}>(data, provider);");

            #endregion

            #region Add fields

            foreach (var field in layout)
            {
                code.AppendLine();
                code.AppendLine($"\t\t/// <summary>{field} {field.Description}.</summary>");
                if (!string.IsNullOrEmpty(field.Description))
                {
                    code.AppendLine($"\t\t[Description(\"{field} {field.Description}\")]");
                }

                code.Append("\t\t[Field(");
                var i = 0;

                void AddAttribute <T>(T value, Func <string> content)
                {
                    if (Equals(value, default))
                    {
                        return;
                    }

                    if (i++ > 0)
                    {
                        code.Append(", ");
                    }

                    code.Append(content());
                }

                if (field.Flags != 0)
                {
                    code.Append("Flags = ");
                    var flagCount = 0;
                    foreach (var flag in field.Flags.GetFlags())
                    {
                        if (flagCount++ > 0)
                        {
                            code.Append(" | ");
                        }

                        code.Append("FieldFlags.");
                        code.Append(flag);
                    }

                    code.Append(", ");
                }

                var sharpName = fieldNameLookup[field.Index];
                if (sharpName != field.Name)
                {
                    AddAttribute(field.Name, () => $"Name = \"{field.Name}\"");
                }

                if (field.MaximumLength < int.MaxValue)
                {
                    AddAttribute(field.MaximumLength, () => $"Length = {(int)field.MaximumLength}");
                }

                AddAttribute(field.AlternativeNames, () => $"AlternativeNames = \"{field.AlternativeNames.Join(", ")}\"");
                AddAttribute(field.DisplayFormat, () => $"DisplayFormat = \"{field.DisplayFormat.EscapeUtf8()}\"");
                code.AppendLine(")]");
                if ((field.DateTimeKind != DateTimeKind.Unspecified) || (field.DateTimeType != DateTimeType.Undefined))
                {
                    code.AppendLine($"\t\t[DateTimeFormat({field.DateTimeKind}, {field.DateTimeType})]");
                }

                if (field.StringEncoding != 0)
                {
                    code.AppendLine($"\t\t[Cave.IO.StringFormat(Cave.IO.StringEncoding.{field.StringEncoding})]");
                }

                code.AppendLine($"\t\tpublic {field.DotNetTypeName} {sharpName};");
            }

            #endregion

            #region ToString()

            {
                code.AppendLine();
                code.AppendLine("\t\t/// <summary>Gets a string representation of this row.</summary>");
                code.AppendLine("\t\t/// <returns>Returns a string that can be parsed by <see cref=\"Parse(string)\"/>.</returns>");
                code.AppendLine("\t\tpublic override string ToString() => ToString(CultureInfo.InvariantCulture);");
                code.AppendLine();
                code.AppendLine("\t\t/// <summary>Gets a string representation of this row.</summary>");
                code.AppendLine("\t\t/// <returns>Returns a string that can be parsed by <see cref=\"Parse(string, IFormatProvider)\"/>.</returns>");
                code.AppendLine("\t\tpublic string ToString(IFormatProvider provider) => CsvWriter.RowToString(this, provider);");
            }

            #endregion

            #region GetHashCode()

            {
                code.AppendLine();
                if (idCount == 1)
                {
                    var idField     = layout.Identifier.First();
                    var idFieldName = fieldNameLookup[idField.Index];
                    code.AppendLine($"\t\t/// <summary>Gets the hash code for the identifier of this row (field {idFieldName}).</summary>");
                    code.AppendLine("\t\t/// <returns>A hash code for the identifier of this row.</returns>");
                    code.Append("\t\tpublic override int GetHashCode() => ");
                    code.Append(idFieldName);
                    code.AppendLine(".GetHashCode();");
                }
                else
                {
                    if (idCount == 0)
                    {
                        code.AppendLine("\t\t/// <summary>Gets the hash code based on all values of this row (no identififer defined).</summary>");
                    }
                    else
                    {
                        var names = idFields.Select(field => fieldNameLookup[field.Index]).Join(", ");
                        code.AppendLine($"\t\t/// <summary>Gets the hash code for the identifier of this row (fields {names}).</summary>");
                    }

                    code.AppendLine("\t\t/// <returns>A hash code for the identifier of this row.</returns>");
                    code.AppendLine("\t\tpublic override int GetHashCode() =>");
                    var first = true;
                    foreach (var idField in idFields)
                    {
                        if (first)
                        {
                            first = false;
                        }
                        else
                        {
                            code.AppendLine(" ^");
                        }

                        code.Append($"\t\t\t{fieldNameLookup[idField.Index]}.GetHashCode()");
                    }

                    code.AppendLine(";");
                }
            }

            #endregion

            #region Equals()

            {
                code.AppendLine();
                code.AppendLine("\t\t/// <inheritdoc/>");
                code.AppendLine($"\t\tpublic override bool Equals(object other) => other is {className} row && Equals(row);");
                code.AppendLine();
                code.AppendLine("\t\t/// <inheritdoc/>");
                code.AppendLine($"\t\tpublic bool Equals({className} other)");
                code.AppendLine("\t\t{");
                code.AppendLine("\t\t\treturn");
                {
                    var first = true;
                    foreach (var field in layout)
                    {
                        if (first)
                        {
                            first = false;
                        }
                        else
                        {
                            code.AppendLine(" &&");
                        }

                        var name = fieldNameLookup[field.Index];
                        code.Append($"\t\t\t\tEquals(other.{name}, {name})");
                    }

                    code.AppendLine(";");
                }
                code.AppendLine("\t\t}");
            }

            #endregion

            code.AppendLine("\t}");
            code.AppendLine("}");
            code.Replace("\t", "    ");
            return(new()
            {
                ClassName = className,
                TableName = tableName,
                DatabaseName = databaseName,
                Code = code.ToString()
            });
        }
コード例 #21
0
ファイル: CSVWriter.cs プロジェクト: elfen20/clone-cave-data
        /// <summary>Creates a string representation of the specified row.</summary>
        /// <param name="properties">The csv properties.</param>
        /// <param name="layout">The row layout.</param>
        /// <param name="row">The row.</param>
        /// <returns>Returns a new string representing the row.</returns>
        public static string RowToString(CsvProperties properties, RowLayout layout, Row row)
        {
            var result = new StringBuilder();
            var values = row.Values;

            for (var i = 0; i < layout.FieldCount; i++)
            {
                if (i > 0)
                {
                    result.Append(properties.Separator);
                }

                if ((values != null) && (values[i] != null))
                {
                    var field = layout[i];
                    switch (field.DataType)
                    {
                    case DataType.Binary:
                    {
                        var str = Base64.NoPadding.Encode((byte[])values[i]);
                        result.Append(str);
                        break;
                    }

                    case DataType.Bool:
                    case DataType.Int8:
                    case DataType.Int16:
                    case DataType.Int32:
                    case DataType.Int64:
                    case DataType.UInt8:
                    case DataType.UInt16:
                    case DataType.UInt32:
                    case DataType.UInt64:
                    {
                        if (!properties.SaveDefaultValues && values[i].Equals(0))
                        {
                            break;
                        }

                        var str = values[i].ToString();
                        result.Append(str);
                        break;
                    }

                    case DataType.Char:
                    {
                        if (!properties.SaveDefaultValues && values[i].Equals((char)0))
                        {
                            break;
                        }

                        var str = values[i].ToString();
                        result.Append(str);
                        break;
                    }

                    case DataType.Decimal:
                    {
                        if (!properties.SaveDefaultValues && values[i].Equals(0m))
                        {
                            break;
                        }

                        var value = (decimal)values[i];
                        result.Append(value.ToString(properties.Format));
                        break;
                    }

                    case DataType.Single:
                    {
                        if (!properties.SaveDefaultValues && values[i].Equals(0f))
                        {
                            break;
                        }

                        var value = (float)values[i];
                        result.Append(value.ToString("R", properties.Format));
                        break;
                    }

                    case DataType.Double:
                    {
                        if (!properties.SaveDefaultValues && values[i].Equals(0d))
                        {
                            break;
                        }

                        var value = (double)values[i];
                        result.Append(value.ToString("R", properties.Format));
                        break;
                    }

                    case DataType.TimeSpan:
                    {
                        if (!properties.SaveDefaultValues && values[i].Equals(TimeSpan.Zero))
                        {
                            break;
                        }

                        var str = field.GetString(values[i], $"{properties.StringMarker}", properties.Format);
                        result.Append(str);
                        break;
                    }

                    case DataType.DateTime:
                    {
                        if (!properties.SaveDefaultValues && values[i].Equals(new DateTime(0)))
                        {
                            break;
                        }

                        string str;
                        if (properties.DateTimeFormat != null)
                        {
                            str = ((DateTime)values[i]).ToString(properties.DateTimeFormat, properties.Format);
                        }
                        else
                        {
                            str = field.GetString(values[i], $"{properties.StringMarker}", properties.Format);
                        }

                        result.Append(str);
                        break;
                    }

                    case DataType.User:
                    case DataType.String:
                    {
                        if (!properties.SaveDefaultValues && values[i].Equals(string.Empty))
                        {
                            break;
                        }

                        var str = values[i] == null ? string.Empty : values[i].ToString();
                        str = str.EscapeUtf8();
                        if (properties.StringMarker.HasValue)
                        {
                            str = str.Replace($"{properties.StringMarker}", $"{properties.StringMarker}{properties.StringMarker}");
                            result.Append(properties.StringMarker);
                        }

                        if (str.Length == 0)
                        {
                            result.Append(" ");
                        }
                        else
                        {
                            if (properties.StringMarker.HasValue)
                            {
                                if (str.StartsWith(properties.StringMarker.ToString()))
                                {
                                    result.Append(" ");
                                }
                            }

                            result.Append(str);
                            if (properties.StringMarker.HasValue)
                            {
                                if (str.EndsWith(properties.StringMarker.ToString()))
                                {
                                    result.Append(" ");
                                }
                            }
                        }

                        if (properties.StringMarker.HasValue)
                        {
                            result.Append(properties.StringMarker);
                        }

                        break;
                    }

                    case DataType.Enum:
                    {
                        if (!properties.SaveDefaultValues && Convert.ToInt32(values[i]).Equals(0))
                        {
                            break;
                        }

                        var str = values[i].ToString();
                        result.Append(str);
                        break;
                    }

                    default:
                        throw new NotImplementedException($"DataType {layout[i].DataType} is not implemented!");
                    }
                }
            }

            return(result.ToString());
        }
コード例 #22
0
        internal static Row ReadCurrentRow(DataReader reader, int version, RowLayout layout)
        {
            if (version < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(version));
            }

            if (version > 4)
            {
                throw new NotSupportedException("Version not supported!");
            }

            var dataStart = reader.BaseStream.Position;
            var dataSize  = reader.Read7BitEncodedInt32();

            if (dataSize == 0)
            {
                return(null);
            }

            var values = new object[layout.FieldCount];

            for (var i = 0; i < layout.FieldCount; i++)
            {
                var field    = layout[i];
                var dataType = field.DataType;
                switch (dataType)
                {
                case DataType.Binary:
                    if (version >= 3)
                    {
                        values[i] = reader.ReadBytes();
                    }
                    else
                    {
                        var size = reader.ReadInt32();
                        values[i] = reader.ReadBytes(size);
                    }

                    break;

                case DataType.Bool:
                    values[i] = reader.ReadBool();
                    break;

                case DataType.DateTime:
                    values[i] = new DateTime(reader.ReadInt64(), field.DateTimeKind);
                    break;

                case DataType.TimeSpan:
                    values[i] = new TimeSpan(reader.ReadInt64());
                    break;

                case DataType.Int8:
                    values[i] = reader.ReadInt8();
                    break;

                case DataType.Int16:
                    values[i] = reader.ReadInt16();
                    break;

                case DataType.Int32:
                    if (version == 1)
                    {
                        values[i] = reader.ReadInt32();
                        break;
                    }

                    values[i] = reader.Read7BitEncodedInt32();
                    break;

                case DataType.Int64:
                    if (version == 1)
                    {
                        values[i] = reader.ReadInt64();
                        break;
                    }

                    values[i] = reader.Read7BitEncodedInt64();
                    break;

                case DataType.UInt32:
                    if (version == 1)
                    {
                        values[i] = reader.ReadUInt32();
                        break;
                    }

                    values[i] = reader.Read7BitEncodedUInt32();
                    break;

                case DataType.UInt64:
                    if (version == 1)
                    {
                        values[i] = reader.ReadUInt64();
                        break;
                    }

                    values[i] = reader.Read7BitEncodedUInt64();
                    break;

                case DataType.UInt8:
                    values[i] = reader.ReadUInt8();
                    break;

                case DataType.UInt16:
                    values[i] = reader.ReadUInt16();
                    break;

                case DataType.Char:
                    values[i] = reader.ReadChar();
                    break;

                case DataType.Single:
                    values[i] = reader.ReadSingle();
                    break;

                case DataType.Double:
                    values[i] = reader.ReadDouble();
                    break;

                case DataType.Decimal:
                    values[i] = reader.ReadDecimal();
                    break;

                case DataType.String:
                    values[i] = reader.ReadString();
                    break;

                case DataType.Enum:
                    values[i] = layout.EnumValue(i, reader.Read7BitEncodedInt64());
                    break;

                case DataType.User:
                    values[i] = layout.ParseValue(i, reader.ReadString(), null);
                    break;

                default: throw new NotImplementedException($"Datatype {dataType} not implemented!");
                }
            }

            var skip = (dataStart + dataSize) - reader.BaseStream.Position;

            if (skip < 0)
            {
                throw new FormatException();
            }

            if (skip > 0)
            {
                reader.BaseStream.Seek(skip, SeekOrigin.Current);
            }

            return(new Row(layout, values, false));
        }
コード例 #23
0
ファイル: CSVWriter.cs プロジェクト: elfen20/clone-cave-data
 /// <summary>Initializes a new instance of the <see cref="CsvWriter" /> class.</summary>
 /// <param name="layout">The table layout.</param>
 /// <param name="fileName">Filename to write to.</param>
 /// <param name="properties">Extended properties.</param>
 public CsvWriter(RowLayout layout, string fileName, CsvProperties properties = default)
     : this(layout, File.Create(fileName), properties, true)
 {
 }
コード例 #24
0
 /// <summary>Not supported.</summary>
 /// <param name="layout">Unused parameter.</param>
 public override void UseLayout(RowLayout layout) => RowLayout.CheckLayout(Layout, layout);
コード例 #25
0
 /// <inheritdoc />
 public virtual void UseLayout(RowLayout layout)
 {
     Storage.CheckLayout(Layout, layout);
     Layout = layout;
 }