public static void WriteDatabase(Stream s, RpDbTable[] tables) { //We'll rewind to the beginning of the stream and begin writing. https://docs.google.com/document/d/1PVuW3CshGg0BvQHSyrGBQhFceaTk92H3Fv8uKOkhpX8/edit //Write the name of this. WriterTools.WriteChars(s, new char[] { 'R', 'p', 'D', 'b' }); //Write the version. WriterTools.WriteUInt16(s, RpDbDatabase.RPDB_VERSION); //Skip 32 bytes. These'll be used later. s.Position += 32; //We're going to write each table's data now. MemoryStream[] streams = new MemoryStream[tables.Length]; Parallel.For(0, tables.Length, delegate(int i) { //Open MemoryStream for this table. MemoryStream stream = new MemoryStream(); RpDbTable table = tables[i]; //Write table. TableWriter.WriteTable(stream, table); //Save this stream. streams[i] = stream; }); //Now, we'll write the table TOC. //Write the number of entries. WriterTools.WriteUInt16(s, (UInt16)tables.Length); //Now, write all of the entries. UInt32 offset = 0; for (int i = 0; i < tables.Length; i++) { RpDbTable table = tables[i]; MemoryStream stream = streams[i]; //Write the offset and the name. WriterTools.WriteUInt32(s, offset); //Now, the name. WriterTools.WriteString(s, table.name); //Add the offset. offset += (UInt32)stream.Length; } //Now, write all of the streams in order. for (int i = 0; i < streams.Length; i++) { MemoryStream stream = streams[i]; stream.Position = 0; stream.CopyTo(s); //Clear stream.Close(); stream.Dispose(); } }
public static RpDbTableEntry ReadEntry(Stream s, RpDbTable table) { //Create object. RpDbTableEntry entry = new RpDbTableEntry(table, null); entry.offset = (UInt32)s.Position; //First, read in the UUID. UInt32 uuid = ReaderTools.ReadUInt32(s); entry.uuid = uuid; //Read in the lengths. UInt16[] lengths = new UInt16[table.typeOrder.Length]; for (int i = 0; i < table.typeOrder.Length; i++) { lengths[i] = ReaderTools.ReadUInt16(s); } //Now, read in the data object obj = Activator.CreateInstance(table.type); for (int i = 0; i < table.typeOrder.Length; i++) { Writer.PropIdPair pair = table.typeOrder[i]; //Skip this if the length is zero. (it's null) UInt16 length = lengths[i]; if (length != 0) { //Read in the data. byte[] buf = new byte[length]; s.Read(buf, 0, length); //Todo: Actually get the data from it. //For now, just read it in as a string object d = Encoding.UTF8.GetString(buf); //Now, set it inside the object. pair.prop.SetValue(obj, d, null); } } //Set the entry's object to this. entry.data = obj; //Return the entry. return(entry); }
public static RpDbTable ReadTable(Stream s, Type[] types, RpDbDatabase database) { //Read the table name. string name = ReaderTools.ReadString(s); //Read the type string typeName = ReaderTools.ReadString(s); //Determine the type. Type t = null; //Loop through types and find match. foreach (Type tt in types) { if (tt.ToString() == typeName) { t = tt; } } //Check if it was found. if (t == null) { throw new Exception("Failed to find type '" + typeName + "'."); } //Create the object. RpDbTable table = new RpDbTable(name, t, database); //Read the number of entries. UInt32 entryCount = ReaderTools.ReadUInt32(s); //Read number of types. UInt16 typeCount = ReaderTools.ReadUInt16(s); //Read the type table in. This'll give us the order. Writer.PropIdPair[] order = new Writer.PropIdPair[typeCount]; for (int i = 0; i < typeCount; i++) { //Read in. UInt16 typeId = ReaderTools.ReadUInt16(s); ClassAttrib attr = null; System.Reflection.PropertyInfo chosenProp = null; //Find this in the object. foreach (var prop in table.type.GetProperties()) { //Check the UUID. ClassAttrib propAttr = Writer.TableWriter.GetUuidFromProperty(prop); //If there is no UUID, skip this. if (propAttr == null) { continue; } //Add this to the order if it matches if (propAttr.uuid == typeId) { attr = propAttr; chosenProp = prop; } } if (attr != null && chosenProp != null) { order[i] = new Writer.PropIdPair(chosenProp, typeId); } else { Console.WriteLine("No attr found for ID " + typeId.ToString() + "."); } } table.typeOrder = order; //Now that we know the order of the types, we can read it in. //Skip 32 bytes of reserved data. s.Position += 32; //Read each of the offsets in. Add them to the dict as we go. for (int i = 0; i < entryCount; i++) { //Read offset UInt32 offset = ReaderTools.ReadUInt32(s); //Read UUID UInt32 uuid = ReaderTools.ReadUInt32(s); //Insert. table.uuidLookup.Add(uuid, offset); } //Now, the data begins. Add the flag. table.tableDataOffset = s.Position; //We can now continue to the next table. return(table); }
public static void WriteTable(Stream s, RpDbTable table) { //First, write the table name. WriterTools.WriteString(s, table.name); //Write the type name. WriterTools.WriteString(s, table.type.ToString()); //Now, write the number of entries. WriterTools.WriteUInt32(s, (UInt32)table.GetNumberOfEntries()); //Write the type table now. Go through each attribute in the type. //Determine the order. List <PropIdPair> order = new List <PropIdPair>(); foreach (var prop in table.type.GetProperties()) { //Check the UUID. ClassAttrib propAttr = GetUuidFromProperty(prop); //If there is no UUID, skip this. if (propAttr == null) { Console.WriteLine("(debug) Skipping because no attr."); continue; } //Add this to the order. order.Add(new PropIdPair(prop, propAttr.uuid)); } //Now, write number of types. WriterTools.WriteUInt16(s, (UInt16)order.Count); //Write the type table itself. foreach (PropIdPair o in order) { WriterTools.WriteUInt16(s, o.typeid); } //Skip 32 bytes of reserved space. s.Position += 32; //Now, we'll find all the entries and put them in a stream. //We'll create a stream for the actual data and copy it here later. MemoryStream dataStream = new MemoryStream(); //We'll now find and include data. //First, find new entries. List <UInt32> uuidsToSkip = new List <uint>(); //These are the UUIDs that we will skip when we copy directly from the unmodified enteries. foreach (RpDbTableEntry entry in table.modifyBuffer.Values) { //Check if this key exists in the uuid lookup. If it does, this is a UPDATED entry. If it doesn't, this is a NEW entry. bool existsBefore = table.uuidLookup.ContainsKey(entry.uuid); //Add this now. UInt32 offset = ValueWriter.WriteEntry(dataStream, s, entry, order); //Add this to the written dictonary, but also add it to the skipped list so we don't rewrite it. uuidsToSkip.Add(entry.uuid); entry.offset = offset; //Make sure we know the offset. if (!existsBefore) { //If this wasn't already in the lookup table, add it. table.uuidLookup.Add(entry.uuid, offset); } else { //Update the offset now. table.uuidLookup[entry.uuid] = offset; } } //Now, we'll add existing, untouched, files. foreach (var entry in table.uuidLookup) { //Check if this is in the "uuidstoskip" list. if (!uuidsToSkip.Contains(entry.Key)) { //We'll copy this to the new one. //TODO: COPY!!!!!!!!!!! throw new NotImplementedException(); } } //Now that that is done, we can copy the data stream to the main stream. dataStream.Position = 0; dataStream.CopyTo(s); }