예제 #1
0
        /// <summary>
        /// Serializes this storage object into a byte array
        /// </summary>
        /// <param name="IncludeHeader">Whether or not to include the storage header in the output</param>
        /// <returns>A serialized byte array representation of all stored value entries</returns>
        public byte[] Serialize(bool IncludeHeader = true)
        {
            // Lock our dictionary to prevent race conditions
            lock (Entries)
            {
                // Begin by creating an empty output buffer
                byte[] Output = new byte[0];

                // Write header to output buffer if specified
                if (IncludeHeader)
                {
                    // Add signatures and version
                    Output = Output.AppendBytes(STORAGE_SIGNATURE_A);
                    Output = Output.AppendBytes(STORAGE_SIGNATURE_B);
                    Output = Output.AppendBytes(STORAGE_VERSION);
                }

                // Add the number of entries our entry dictionary contains as a varint
                Output = Output.AppendBytes(PackP2pVarInt(Entries.Count));

                // Iterate over and serialize each entry into our output buffer
                foreach (var Entry in Entries)
                {
                    // Serialize entry object
                    byte[] ObjectBytes = SerializeObject(Entry);

                    // Append to output buffer
                    Output = Output.AppendBytes(ObjectBytes);
                }

                // Return output array
                return(Output);
            }
        }
예제 #2
0
        // Deserialized a storage entry from a byte buffer
        private byte[] DeserializeEntry(byte[] Data)
        {
            // Buffer is empty
            if (Data.Length == 0)
            {
                return(Data);
            }

            // Get entry name
            int NameLength = ByteArrayToInteger <byte>(Data, 0);

            if (NameLength < 1 || NameLength > MAX_STRING_LENGTH)
            {
                throw new Exception("Name size exceeds allowed string bounds");
            }
            string Name = System.Text.Encoding.UTF8.GetString(Data, 1, NameLength);

            Data = Data.SubBytes(NameLength + 1, Data.Length - NameLength - 1);

            // Get object type
            int ValueType = Data.SubBytes(0, 1)[0];

            // Type is a serializable type
            if (ValueType > 0 || ValueType < 14)
            {
                // Get serialization type
                SerializationType Type = (SerializationType)ValueType;
                Data = Data.SubBytes(1, Data.Length - 1);

                // Deserialize object based on type
                switch (Type)
                {
                    #region Integers

                case SerializationType.LONG:
                    Entries.Add(Name, ByteArrayToInteger <long>(Data));
                    return(Data.SubBytes(8, Data.Length - 8));

                case SerializationType.INT:
                    Entries.Add(Name, ByteArrayToInteger <int>(Data));
                    return(Data.SubBytes(4, Data.Length - 4));

                case SerializationType.SHORT:
                    Entries.Add(Name, ByteArrayToInteger <short>(Data));
                    return(Data.SubBytes(2, Data.Length - 2));

                case SerializationType.SBYTE:
                    Entries.Add(Name, ByteArrayToInteger <sbyte>(Data));
                    return(Data.SubBytes(1, Data.Length - 1));

                case SerializationType.ULONG:
                    Entries.Add(Name, ByteArrayToInteger <ulong>(Data));
                    return(Data.SubBytes(8, Data.Length - 8));

                case SerializationType.UINT:
                    Entries.Add(Name, ByteArrayToInteger <uint>(Data));
                    return(Data.SubBytes(4, Data.Length - 4));

                case SerializationType.USHORT:
                    Entries.Add(Name, ByteArrayToInteger <ushort>(Data));
                    return(Data.SubBytes(2, Data.Length - 2));

                case SerializationType.BYTE:
                    Entries.Add(Name, ByteArrayToInteger <byte>(Data));
                    return(Data.SubBytes(1, Data.Length - 1));

                case SerializationType.DOUBLE:
                    Entries.Add(Name, ByteArrayToInteger <double>(Data));
                    return(Data.SubBytes(8, Data.Length - 8));

                case SerializationType.BOOL:
                    Entries.Add(Name, Convert.ToBoolean(ByteArrayToInteger <byte>(Data)));
                    return(Data.SubBytes(1, Data.Length - 1));

                    #endregion

                    #region Miscellaneous

                case SerializationType.STRING:
                    int Length = UnpackP2pVarInt <int>(Data, 0, out int Offset);
                    Entries.Add(Name, ByteArrayToHexString(Data.SubBytes(Offset, Length)));
                    return(Data.SubBytes(Offset + Length, Data.Length - Offset - Length));

                    #endregion

                    #region Not Implemented

                case SerializationType.OBJECT:
                    PortableStorage Storage = new PortableStorage(Data, out Data, false);
                    Entries.Add(Name, Storage.Entries);
                    return(Data);

                case SerializationType.OBJECTARRAY:
                    return(new byte[0]);

                default:
                    return(new byte[0]);

                    #endregion
                }
            }

            // Non-serializable type, treat as a single long hex string
            else
            {
                // TODO - This isn't final, I still need to explore how other things are serialized
                Entries.Add(Name, ByteArrayToHexString(Data));
                return(new byte[0]);
            }
        }
예제 #3
0
        // Serializes an object to a byte array
        private static byte[] SerializeObject(dynamic Entry)
        {
            // Append entry name
            byte[] Output = new[] { (byte)Entry.Key.Length };
            Output = Output.AppendString((string)Entry.Key);

            // Get entry value
            var Value = Entry.Value;

            // Get object's type
            var Type = GetType(Value);

            if (Type != SerializationType.BYTEARRAY)
            {
                Output = Output.AppendBytes(new[] { (byte)Type });
            }
            else
            {
                Output = Output.AppendBytes(new[] { (byte)SerializationType.STRING });
            }

            // Serialize object based on type
            switch (Type)
            {
                #region Integers

            case SerializationType.LONG:
                Output = Output.AppendInteger((long)Value);
                break;

            case SerializationType.INT:
                Output = Output.AppendInteger((int)Value);
                break;

            case SerializationType.SHORT:
                Output = Output.AppendInteger((short)Value);
                break;

            case SerializationType.SBYTE:
                Output = Output.AppendInteger((sbyte)Value);
                break;

            case SerializationType.ULONG:
                Output = Output.AppendInteger((ulong)Value);
                break;

            case SerializationType.UINT:
                Output = Output.AppendInteger((uint)Value);
                break;

            case SerializationType.USHORT:
                Output = Output.AppendInteger((ushort)Value);
                break;

            case SerializationType.BYTE:
                Output = Output.AppendInteger((byte)Value);
                break;

            case SerializationType.DOUBLE:
                Output = Output.AppendInteger((double)Value);
                break;

            case SerializationType.BOOL:
                Output = Output.AppendInteger((bool)Value ? (byte)0x01 : (byte)0x00);
                break;

                #endregion

                #region Others

            case SerializationType.STRING:
                // String size exceeds maximum length, default to nothing
                if (((string)Value).Length > MAX_STRING_LENGTH)
                {
                    throw new ArgumentOutOfRangeException("Entry string was too long to serialize");
                }

                // Append string length as a varint
                Output = Output.AppendBytes(PackP2pVarInt(((string)Value).Length));

                // Append string bytes
                Output = Output.AppendString((string)Value);
                break;

            case SerializationType.BYTEARRAY:
                // Byte size exceeds maximum length, default to nothing
                if (((byte[])Value).Length > MAX_STRING_LENGTH)
                {
                    throw new ArgumentOutOfRangeException("Entry byte array was too long to serialize");
                }

                // Append string length as a varint
                Output = Output.AppendBytes(PackP2pVarInt(((byte[])Value).Length));

                // Append string bytes
                Output = Output.AppendBytes((byte[])Value);
                break;

                #endregion

                #region Not Implemented

            case SerializationType.OBJECT:
                // Object is a dictionary
                Type ValueType = Value.GetType();
                if (ValueType.IsGenericType && ValueType.GetGenericTypeDefinition() == typeof(Dictionary <,>))
                {
                    // Create a portable storage from dictionary
                    PortableStorage Storage = (Dictionary <string, dynamic>)Value;

                    // Append bytes
                    Output = Output.AppendBytes(Storage.Serialize(false));
                    break;
                }
                else
                {
                    throw new NotImplementedException();
                }

            case SerializationType.OBJECTARRAY:
                throw new NotImplementedException();

            default:
                return(new byte[0]);

                #endregion
            }

            // Return resulting output buffer
            return(Output);
        }