/// <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); }