/// <summary> /// Parses a database row. /// </summary> /// <returns></returns> SType ParseDBRow() { var header = GetObject() as SObjectType; if (header == null) { throw new ParserException("DBRow header not found"); } if (!header.IsDBRowDescriptor) { throw new ParserException("Bad DBRow descriptor name"); } var fields = header.Members.First().Members.First( member => member is STupleType).Members.First().Members.Cast <STupleType>().ToList(); if (!fields.Any()) { return(new SNoneType()); } // Check for double marker in stream (usually found in a file with one DBRow) var length = m_reader.ReadLength(); if (m_reader.IsDoubleMarker(length)) { length = m_reader.ReadLength(); } var unpackedDataSize = GetUnpackedDataSize(fields); var compressedData = m_reader.ReadBytes(length); var uncompressedData = Rle_Unpack(compressedData, unpackedDataSize); var reader = new CachedFileReader(uncompressedData, false); // Find the maximum number of elements for each field member var maxElements = fields.Select(field => field.Members.Count).Concat(new[] { 0 }).Max(); // The size of SDict must be the ammount of entries stored, // multiplied by the max elements of each field member var dict = new SDictType((uint)(fields.Count() * maxElements)); var pass = 1; while (pass < 7) { // The pattern for what data to read on each pass is: // 1: 64 bit (Int64, Double) // 2: 32 bit (Int32, Single) // 3: 16 bit (Int16) // 4: 8 bit (Byte) // 5: 1 bit (Boolean) // 6: strings foreach (var field in fields) { var fieldName = field.Members.First(); var fieldType = (SLongType)field.Members.Last(); var dbType = (DbTypes)fieldType.Value; byte boolCount = 0; var boolBuffer = false; SType obj = null; switch (dbType) { case DbTypes.Short: case DbTypes.UShort: if (pass == 3) { obj = new SShortType(reader.ReadShort()); } break; case DbTypes.Int: case DbTypes.UInt: if (pass == 2) { obj = new SIntType(reader.ReadInt()); } break; case DbTypes.Float: if (pass == 2) { obj = new SDoubleType(reader.ReadFloat()); } break; case DbTypes.Double: if (pass == 1) { obj = new SDoubleType(reader.ReadDouble()); } break; case DbTypes.Currency: if (pass == 1) { obj = new SDoubleType(reader.ReadLong() / 10000.0); } break; case DbTypes.Long: case DbTypes.ULong: case DbTypes.Filetime: // Timestamp case DbTypes.DBTimestamp: if (pass == 1) { obj = new SLongType(reader.ReadLong()); } break; case DbTypes.Bool: if (pass == 5) { if (boolCount == 0) { boolBuffer = Convert.ToBoolean(reader.ReadByte()); boolCount++; } obj = boolBuffer && boolCount != 0 ? new SBooleanType(1) : new SBooleanType(0); } break; case DbTypes.Byte: case DbTypes.UByte: if (pass == 4) { obj = new SByteType(reader.ReadByte()); } break; case DbTypes.Bytes: // String types case DbTypes.String: case DbTypes.WideString: if (pass == 6) { obj = GetObject(); } break; default: throw new ParserException("Unhandled db column type: " + dbType); } if (obj == null) { continue; } dict.AddMember(obj); dict.AddMember(fieldName.Clone()); } pass++; } var parsedDBRow = new STupleType(2); parsedDBRow.AddMember(header); parsedDBRow.AddMember(dict); return(parsedDBRow); }
/// <summary> /// Gets an object from the data. /// </summary> /// <returns></returns> SType GetObject() { SType sObject = null; var type = m_reader.ReadByte(); var checkType = (StreamType)(type & ~(byte)StreamType.SharedFlag); var shared = Convert.ToBoolean(type & (byte)StreamType.SharedFlag); switch (checkType) { case 0: case StreamType.StreamStart: break; case StreamType.Marker: break; case StreamType.None: sObject = new SNoneType(); break; case StreamType.Utf8: sObject = new SStringType(m_reader.ReadUtf8String(m_reader.ReadLength())); break; case StreamType.String: case StreamType.StringLong: sObject = new SStringType(m_reader.ReadString(m_reader.ReadLength())); break; case StreamType.StringGlobal: sObject = new SStringType(m_reader.ReadString(m_reader.ReadLength())); CheckShared(shared, sObject); break; case StreamType.StringUnicode: sObject = new SStringType(m_reader.ReadUnicodeString(m_reader.ReadLength() * 2)); break; case StreamType.Long: sObject = new SLongType(m_reader.ReadLong()); break; case StreamType.Int: sObject = new SIntType(m_reader.ReadInt()); break; case StreamType.Short: sObject = new SShortType(m_reader.ReadShort()); break; case StreamType.Byte: sObject = new SByteType(m_reader.ReadByte()); break; case StreamType.IntNegOne: sObject = new SIntType(-1); break; case StreamType.IntZero: sObject = new SIntType(0); break; case StreamType.IntOne: sObject = new SIntType(1); break; case StreamType.Double: sObject = new SDoubleType(m_reader.ReadDouble()); break; case StreamType.DoubleZero: sObject = new SDoubleType(0); break; case StreamType.StringEmpty: sObject = new SStringType(null); break; case StreamType.StringOne: sObject = new SStringType(m_reader.ReadString(1)); break; case StreamType.StringRef: var id = m_reader.ReadByte(); sObject = new SReferenceType(id, StringsTable.GetStringByID(id)); break; case StreamType.StringIdent: sObject = new SIdentType(m_reader.ReadString(m_reader.ReadLength())); CheckShared(shared, sObject); break; case StreamType.Tuple: { var length = m_reader.ReadLength(); sObject = new STupleType((uint)length); CheckShared(shared, sObject); Parse(sObject, length); break; } case StreamType.List: { var length = m_reader.ReadLength(); sObject = new SListType((uint)length); CheckShared(shared, sObject); Parse(sObject, length); break; } case StreamType.Dict: { var length = (m_reader.ReadLength() * 2); sObject = new SDictType((uint)length); CheckShared(shared, sObject); Parse(sObject, length); break; } case StreamType.SharedObj: sObject = m_reader.GetSharedObj(m_reader.ReadLength() - 1); break; case StreamType.Checksum: sObject = new SStringType("checksum"); m_reader.ReadInt(); break; case StreamType.BoolTrue: sObject = new SBooleanType(1); break; case StreamType.BoolFalse: sObject = new SBooleanType(0); break; case StreamType.ClassObject: case StreamType.NewObj: case StreamType.Object: { var storedId = m_reader.ReserveSlot(shared); sObject = ParseObject(); m_reader.UpdateSlot(storedId, sObject); } break; case StreamType.TupleEmpty: sObject = new STupleType(0); break; case StreamType.TupleOne: sObject = new STupleType(1); CheckShared(shared, sObject); Parse(sObject); break; case StreamType.ListEmpty: sObject = new SListType(0); CheckShared(shared, sObject); break; case StreamType.ListOne: sObject = new SListType(1); CheckShared(shared, sObject); Parse(sObject); break; case StreamType.StringUnicodeEmpty: sObject = new SStringType(String.Empty); break; case StreamType.StringUnicodeOne: sObject = new SStringType(m_reader.ReadString(2)); break; case StreamType.CompressedDBRow: sObject = ParseDBRow(); break; case StreamType.SubStream: sObject = ParseSubStream(); CheckShared(shared, sObject); break; case StreamType.TupleTwo: sObject = new STupleType(2); CheckShared(shared, sObject); Parse(sObject, 2); break; case StreamType.BigInt: sObject = new SLongType(m_reader.ReadBigInt()); CheckShared(shared, sObject); break; default: throw new ParserException( String.Format(CultureInfo.InvariantCulture, "Can't identify type {0:x2} at position {1:x2} [{1}] and length {2}", type, m_reader.Position, m_reader.Length)); } if (sObject == null && type != (byte)StreamType.Marker) { throw new ParserException("An object could not be created"); } return(sObject); }