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 UInt32 WriteEntry(Stream dataStream, Stream tableStream, RpDbTableEntry entry, List <PropIdPair> order) { //Add the data and return the offset. UInt32 offset = (UInt32)dataStream.Position; //Write the offset and uuid to the table. WriterTools.WriteUInt32(tableStream, offset); WriterTools.WriteUInt32(tableStream, entry.uuid); //Now, we'll write the data. //Get the serialized data for this class, following the order offered. byte[][] serData = new byte[order.Count][]; //Data to be serialized. for (int i = 0; i < order.Count; i++) { //This is run for each property in this. Serialize it. var pair = order[i]; var prop = pair.prop; //Get the value from this using the property found earlier. object value = prop.GetValue(entry.data, null); Type type = value.GetType(); //Convert this to bytes. byte[] data = GetSerializedData(value, type); //Add it. serData[i] = data; } //Write UUID WriterTools.WriteUInt32(dataStream, entry.uuid); //Write the lengths foreach (byte[] d in serData) { WriterTools.WriteUInt16(dataStream, (ushort)d.Length); } //Now, write all the data. foreach (byte[] d in serData) { dataStream.Write(d, 0, d.Length); } //Return offset. return(offset); }
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); }