Exemple #1
0
        /// <summary>
        /// Write object as a predefined type if possible.
        /// </summary>
        /// <param name="hdr">Header.</param>
        /// <param name="inStream">Input stream.</param>
        /// <param name="outStream">Output stream.</param>
        /// <param name="ctx">Context.</param>
        /// <returns><c>True</c> if was written.</returns>
        private bool WriteAsPredefined(byte hdr, PortableHeapStream inStream, IPortableStream outStream,
                                       Context ctx)
        {
            switch (hdr)
            {
            case PortableUtils.TypeByte:
                TransferBytes(inStream, outStream, 1);

                break;

            case PortableUtils.TypeShort:
                TransferBytes(inStream, outStream, 2);

                break;

            case PortableUtils.TypeInt:
                TransferBytes(inStream, outStream, 4);

                break;

            case PortableUtils.TypeLong:
                TransferBytes(inStream, outStream, 8);

                break;

            case PortableUtils.TypeFloat:
                TransferBytes(inStream, outStream, 4);

                break;

            case PortableUtils.TypeDouble:
                TransferBytes(inStream, outStream, 8);

                break;

            case PortableUtils.TypeChar:
                TransferBytes(inStream, outStream, 2);

                break;

            case PortableUtils.TypeBool:
                TransferBytes(inStream, outStream, 1);

                break;

            case PortableUtils.TypeDecimal:
                TransferBytes(inStream, outStream, 4); // Transfer scale

                int magLen = inStream.ReadInt();       // Transfer magnitude length.

                outStream.WriteInt(magLen);

                TransferBytes(inStream, outStream, magLen);     // Transfer magnitude.

                break;

            case PortableUtils.TypeString:
                PortableUtils.WriteString(PortableUtils.ReadString(inStream), outStream);

                break;

            case PortableUtils.TypeGuid:
                TransferBytes(inStream, outStream, 16);

                break;

            case PortableUtils.TypeDate:
                TransferBytes(inStream, outStream, 12);

                break;

            case PortableUtils.TypeArrayByte:
                TransferArray(inStream, outStream, 1);

                break;

            case PortableUtils.TypeArrayShort:
                TransferArray(inStream, outStream, 2);

                break;

            case PortableUtils.TypeArrayInt:
                TransferArray(inStream, outStream, 4);

                break;

            case PortableUtils.TypeArrayLong:
                TransferArray(inStream, outStream, 8);

                break;

            case PortableUtils.TypeArrayFloat:
                TransferArray(inStream, outStream, 4);

                break;

            case PortableUtils.TypeArrayDouble:
                TransferArray(inStream, outStream, 8);

                break;

            case PortableUtils.TypeArrayChar:
                TransferArray(inStream, outStream, 2);

                break;

            case PortableUtils.TypeArrayBool:
                TransferArray(inStream, outStream, 1);

                break;

            case PortableUtils.TypeArrayDecimal:
            case PortableUtils.TypeArrayString:
            case PortableUtils.TypeArrayGuid:
            case PortableUtils.TypeArrayDate:
            case PortableUtils.TypeArrayEnum:
            case PortableUtils.TypeArray:
                int arrLen = inStream.ReadInt();

                outStream.WriteInt(arrLen);

                for (int i = 0; i < arrLen; i++)
                {
                    Mutate0(ctx, inStream, outStream, false, 0, null);
                }

                break;

            case PortableUtils.TypeCollection:
                int colLen = inStream.ReadInt();

                outStream.WriteInt(colLen);

                outStream.WriteByte(inStream.ReadByte());

                for (int i = 0; i < colLen; i++)
                {
                    Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
                }

                break;

            case PortableUtils.TypeDictionary:
                int dictLen = inStream.ReadInt();

                outStream.WriteInt(dictLen);

                outStream.WriteByte(inStream.ReadByte());

                for (int i = 0; i < dictLen; i++)
                {
                    Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
                    Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
                }

                break;

            case PortableUtils.TypeMapEntry:
                Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
                Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);

                break;

            case PortableUtils.TypePortable:
                TransferArray(inStream, outStream, 1);     // Data array.
                TransferBytes(inStream, outStream, 4);     // Offset in array.

                break;

            case PortableUtils.TypeEnum:
                TransferBytes(inStream, outStream, 4);     // Integer ordinal.

                break;

            default:
                return(false);
            }

            return(true);
        }
Exemple #2
0
        /// <summary>
        /// Internal mutation routine.
        /// </summary>
        /// <param name="inStream">Input stream.</param>
        /// <param name="outStream">Output stream.</param>
        /// <param name="ctx">Context.</param>
        /// <param name="changeHash">WHether hash should be changed.</param>
        /// <param name="hash">New hash.</param>
        /// <param name="vals">Values to be replaced.</param>
        /// <returns>Mutated object.</returns>
        private void Mutate0(Context ctx, PortableHeapStream inStream, IPortableStream outStream,
                             bool changeHash, int hash, IDictionary <int, object> vals)
        {
            int inStartPos  = inStream.Position;
            int outStartPos = outStream.Position;

            byte inHdr = inStream.ReadByte();

            if (inHdr == PortableUtils.HdrNull)
            {
                outStream.WriteByte(PortableUtils.HdrNull);
            }
            else if (inHdr == PortableUtils.HdrHnd)
            {
                int inHnd = inStream.ReadInt();

                int oldPos = inStartPos - inHnd;
                int newPos;

                if (ctx.OldToNew(oldPos, out newPos))
                {
                    // Handle is still valid.
                    outStream.WriteByte(PortableUtils.HdrHnd);
                    outStream.WriteInt(outStartPos - newPos);
                }
                else
                {
                    // Handle is invalid, write full object.
                    int inRetPos = inStream.Position;

                    inStream.Seek(oldPos, SeekOrigin.Begin);

                    Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);

                    inStream.Seek(inRetPos, SeekOrigin.Begin);
                }
            }
            else if (inHdr == PortableUtils.HdrFull)
            {
                byte inUsrFlag = inStream.ReadByte();
                int  inTypeId  = inStream.ReadInt();
                int  inHash    = inStream.ReadInt();
                int  inLen     = inStream.ReadInt();
                int  inRawOff  = inStream.ReadInt();

                int hndPos;

                if (ctx.AddOldToNew(inStartPos, outStartPos, out hndPos))
                {
                    // Object could be cached in parent builder.
                    object cachedVal;

                    if (_parent._cache != null && _parent._cache.TryGetValue(inStartPos, out cachedVal))
                    {
                        ctx.Writer.Write(cachedVal, null);
                    }
                    else
                    {
                        // New object, write in full form.
                        outStream.WriteByte(PortableUtils.HdrFull);
                        outStream.WriteByte(inUsrFlag);
                        outStream.WriteInt(inTypeId);
                        outStream.WriteInt(changeHash ? hash : inHash);

                        // Skip length and raw offset as they are not known at this point.
                        outStream.Seek(8, SeekOrigin.Current);

                        // Write regular fields.
                        while (inStream.Position < inStartPos + inRawOff)
                        {
                            int inFieldId      = inStream.ReadInt();
                            int inFieldLen     = inStream.ReadInt();
                            int inFieldDataPos = inStream.Position;

                            object fieldVal;

                            bool fieldFound = vals.TryGetValue(inFieldId, out fieldVal);

                            if (!fieldFound || fieldVal != PortableBuilderField.RmvMarkerObj)
                            {
                                outStream.WriteInt(inFieldId);

                                int fieldLenPos = outStream.Position; // Here we will write length later.

                                outStream.Seek(4, SeekOrigin.Current);

                                if (fieldFound)
                                {
                                    // Replace field with new value.
                                    if (fieldVal != PortableBuilderField.RmvMarkerObj)
                                    {
                                        ctx.Writer.Write(fieldVal, null);
                                    }

                                    vals.Remove(inFieldId);
                                }
                                else
                                {
                                    // If field was requested earlier, then we must write tracked value
                                    if (_parent._cache != null && _parent._cache.TryGetValue(inFieldDataPos, out fieldVal))
                                    {
                                        ctx.Writer.Write(fieldVal, null);
                                    }
                                    else
                                    {
                                        // Filed is not tracked, re-write as is.
                                        Mutate0(ctx, inStream, outStream, false, 0, EmptyVals);
                                    }
                                }

                                int fieldEndPos = outStream.Position;

                                outStream.Seek(fieldLenPos, SeekOrigin.Begin);
                                outStream.WriteInt(fieldEndPos - fieldLenPos - 4);
                                outStream.Seek(fieldEndPos, SeekOrigin.Begin);
                            }

                            // Position intput stream pointer after the field.
                            inStream.Seek(inFieldDataPos + inFieldLen, SeekOrigin.Begin);
                        }

                        // Write remaining new fields.
                        foreach (KeyValuePair <int, object> valEntry in vals)
                        {
                            if (valEntry.Value != PortableBuilderField.RmvMarkerObj)
                            {
                                outStream.WriteInt(valEntry.Key);

                                int fieldLenPos = outStream.Position; // Here we will write length later.

                                outStream.Seek(4, SeekOrigin.Current);

                                ctx.Writer.Write(valEntry.Value, null);

                                int fieldEndPos = outStream.Position;

                                outStream.Seek(fieldLenPos, SeekOrigin.Begin);
                                outStream.WriteInt(fieldEndPos - fieldLenPos - 4);
                                outStream.Seek(fieldEndPos, SeekOrigin.Begin);
                            }
                        }

                        // Write raw data.
                        int rawPos = outStream.Position;

                        outStream.Write(inStream.InternalArray, inStartPos + inRawOff, inLen - inRawOff);

                        // Write length and raw data offset.
                        int outResPos = outStream.Position;

                        outStream.Seek(outStartPos + OffsetLen, SeekOrigin.Begin);

                        outStream.WriteInt(outResPos - outStartPos); // Length.
                        outStream.WriteInt(rawPos - outStartPos);    // Raw offset.

                        outStream.Seek(outResPos, SeekOrigin.Begin);
                    }
                }
                else
                {
                    // Object has already been written, write as handle.
                    outStream.WriteByte(PortableUtils.HdrHnd);
                    outStream.WriteInt(outStartPos - hndPos);
                }

                // Synchronize input stream position.
                inStream.Seek(inStartPos + inLen, SeekOrigin.Begin);
            }
            else
            {
                // Try writing as well-known type with fixed size.
                outStream.WriteByte(inHdr);

                if (!WriteAsPredefined(inHdr, inStream, outStream, ctx))
                {
                    throw new IgniteException("Unexpected header [position=" + (inStream.Position - 1) +
                                              ", header=" + inHdr + ']');
                }
            }
        }