예제 #1
0
파일: DataDogFile.cs 프로젝트: xyfc/DataDog
        /// <summary>
        /// Reads file from given stream and returns it.
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static DataDogFile Read(Stream stream)
        {
            var result = new DataDogFile();

            if (stream.Length < 40)
            {
                throw new ArgumentException("Not a data dog file.");
            }

            using (var br = new BinaryReader(stream))
            {
                var signature = Encoding.UTF8.GetString(br.ReadBytes(16));
                var version   = signature.Substring(9).Replace("  ", " ").Replace(" ", ".");

                if (!signature.StartsWith("DDBINFILE"))
                {
                    throw new ArgumentException("Incorrect header.");
                }

                var stringsOffset = br.ReadInt32();
                var stringsLength = br.ReadInt32();
                var dataSize      = br.ReadInt32();
                var typesLength   = br.ReadInt32();
                var fieldsLength  = br.ReadInt32();
                var listsLength   = br.ReadInt32();

                var typeDefinitions  = Encoding.UTF8.GetString(br.ReadBytes(typesLength)).TrimEnd('\0');
                var fieldDefinitions = Encoding.UTF8.GetString(br.ReadBytes(fieldsLength)).TrimEnd('\0');
                var listDefinitions  = Encoding.UTF8.GetString(br.ReadBytes(listsLength)).TrimEnd('\0');
                var stringBlock      = br.ReadBytes(stringsLength);
                var data             = br.ReadBytes(dataSize);

                var dataDogInfo   = Encoding.GetEncoding("EUC-KR").GetString(br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position))).TrimEnd('\0');
                var fieldVarTypes = FindVarTypes(dataDogInfo);

                result.DataDogInfo = dataDogInfo;

                var typeMatches = TypesRegex.Matches(typeDefinitions);

                foreach (Match match in typeMatches)
                {
                    var name = match.Groups["name"].Value;
                    var size = Convert.ToInt32(match.Groups["size"].Value);

                    var strct = new DataTypeDefinition(name, size);
                    result.Types[name] = strct;
                }

                var fieldMatches = FieldsRegex.Matches(fieldDefinitions);
                if (fieldMatches.Count != fieldDefinitions.Count(a => a == '|'))
                {
                    throw new FormatException("Invalid number of fields.");
                }

                foreach (Match match in fieldMatches)
                {
                    var typeName = match.Groups["typeName"].Value;
                    if (!result.Types.TryGetValue(typeName, out var type))
                    {
                        throw new TypeAccessException($"Type '{typeName}' not found for field.");
                    }

                    var fieldName = match.Groups["fieldName"].Value;
                    var offset    = Convert.ToInt32(match.Groups["offset"].Value);
                    var size      = Convert.ToInt32(match.Groups["size"].Value);

                    var typeStr       = match.Groups["type"].Value;
                    var fieldReadType = GetReadType(typeStr);

                    var fullFieldName = (typeName + "." + fieldName).ToLowerInvariant();
                    if (!fieldVarTypes.TryGetValue(fullFieldName, out var varType))
                    {
                        throw new TypeAccessException($"Type not found for '{fullFieldName}'.");
                    }

                    var field = new DataFieldDefinition(fieldName, offset, fieldReadType, size, varType);
                    type.Fields[fieldName] = field;
                }

                using (var dataStream = new MemoryStream(data))
                    using (var br2 = new BinaryReader(dataStream))
                    {
                        var listMatches = ListRegex.Matches(listDefinitions);
                        var read        = 0;

                        for (var i = 0; i < listMatches.Count; ++i)
                        {
                            var listMatch = listMatches[i];

                            var listName     = listMatch.Groups["name"].Value;
                            var listTypeName = listMatch.Groups["typeName"].Value;
                            var listCount    = Convert.ToInt32(listMatch.Groups["count"].Value);

                            if (!result.Types.TryGetValue(listTypeName, out var type))
                            {
                                throw new TypeAccessException($"Type '{listTypeName}' not found for data.");
                            }

                            var list = new DataObjectList(listName, type);

                            for (var j = 0; j < listCount; ++j)
                            {
                                var match = listMatches[++i];

                                var objName  = match.Groups["name"].Value;
                                var typeName = match.Groups["typeName"].Value;
                                var count    = Convert.ToInt32(match.Groups["count"].Value);
                                var offset   = Convert.ToInt32(match.Groups["offset"].Value);

                                dataStream.Seek(offset, SeekOrigin.Begin);
                                var bytes = br2.ReadBytes(type.Size);

                                var obj = new DataObject(objName, type);

                                read += bytes.Length;

                                foreach (var field in type.Fields.Values.OrderBy(a => a.Offset))
                                {
                                    var objField = new DataField(field.Name, field.VarType);

                                    switch (field.VarType)
                                    {
                                    case DataVarType.Byte:
                                        objField.Value = bytes[field.Offset];
                                        break;

                                    case DataVarType.Bool:
                                        objField.Value = (bytes[field.Offset] != 0);
                                        break;

                                    case DataVarType.Integer:
                                        objField.Value = BitConverter.ToInt32(bytes, field.Offset);
                                        break;

                                    case DataVarType.Color:
                                        objField.Value = BitConverter.ToUInt32(bytes, field.Offset);
                                        break;

                                    case DataVarType.Float:
                                        objField.Value = BitConverter.ToSingle(bytes, field.Offset);
                                        break;

                                    case DataVarType.String:
                                    case DataVarType.Reference:
                                        var stringOffset = BitConverter.ToInt32(bytes, field.Offset);

                                        try
                                        {
                                            var nullIndex = Array.IndexOf(stringBlock, (byte)0, stringOffset);
                                            var str       = Encoding.GetEncoding("EUC-KR").GetString(stringBlock, stringOffset, nullIndex - stringOffset);

                                            objField.Value = str;
                                        }
                                        catch (ArgumentOutOfRangeException)
                                        {
                                            Console.Write("Error: String not found.");
                                        }
                                        break;

                                    default:
                                        throw new InvalidDataException($"Unknown type '{field.VarType}'.");
                                    }

                                    obj.Fields[field.Name] = objField;
                                }

                                list.Objects.Add(obj);
                            }

                            result.Lists[list.Name] = list;
                        }

                        if (read != dataStream.Length)
                        {
                            throw new FormatException("Data wasn't read completely.");
                        }
                    }
            }

            return(result);
        }
예제 #2
0
 /// <summary>
 /// Creates new instance.
 /// </summary>
 /// <param name="name"></param>
 /// <param name="type"></param>
 public DataObject(string name, DataTypeDefinition type)
 {
     this.Name = name;
     this.Type = type;
 }