Exemple #1
0
        void IterateHandler(ref SpanReader reader, IFieldHandler handler, bool skipping, HashSet <int>?knownInlineRefs)
        {
            if (handler is ODBDictionaryFieldHandler)
            {
                var dictId = reader.ReadVUInt64();
                if (!skipping)
                {
                    var kvHandlers = ((IFieldHandlerWithNestedFieldHandlers)handler).EnumerateNestedFieldHandlers().ToArray();
                    IterateDict(dictId, kvHandlers[0], kvHandlers[1]);
                }
            }
            else if (handler is ODBSetFieldHandler)
            {
                var dictId = reader.ReadVUInt64();
                if (!skipping)
                {
                    var keyHandler = ((IFieldHandlerWithNestedFieldHandlers)handler).EnumerateNestedFieldHandlers().First();
                    IterateSet(dictId, keyHandler);
                }
            }
            else if (handler is DBObjectFieldHandler)
            {
                var oid = reader.ReadVInt64();
                if (oid == 0)
                {
                    if (!skipping)
                    {
                        _visitor?.OidReference(0);
                    }
                }
                else if (oid <= int.MinValue || oid > 0)
                {
                    if (!skipping)
                    {
                        _visitor?.OidReference((ulong)oid);
                        IterateOid((ulong)oid);
                    }
                }
                else
                {
                    if (knownInlineRefs != null)
                    {
                        if (knownInlineRefs.Contains((int)oid))
                        {
                            if (!skipping)
                            {
                                _visitor?.InlineBackRef((int)oid);
                            }
                            return;
                        }
                        if (!skipping)
                        {
                            _visitor?.InlineRef((int)oid);
                        }
                        knownInlineRefs.Add((int)oid);
                    }
                    var tableId = reader.ReadVUInt32();
                    var version = reader.ReadVUInt32();
                    if (!skipping)
                    {
                        MarkTableIdVersionFieldInfo(tableId, version);
                    }
                    var skip = skipping ||
                               _visitor != null && !_visitor.StartInlineObject(tableId,
                                                                               _tableId2Name.TryGetValue(tableId, out var tableName) ? tableName : null, version);
                    var tvi = GetTableVersionInfo(tableId, version);
                    var knownInlineRefsNested = new HashSet <int>();
                    for (var i = 0; i < tvi.FieldCount; i++)
                    {
                        var fi        = tvi[i];
                        var skipField = skip || _visitor != null && !_visitor.StartField(fi.Name);
                        IterateHandler(ref reader, fi.Handler !, skipField, knownInlineRefsNested);
                        if (!skipField)
                        {
                            _visitor?.EndField();
                        }
                    }
                    if (!skip)
                    {
                        _visitor?.EndInlineObject();
                    }
                }
            }
            else if (handler is ListFieldHandler)
            {
                var oid = reader.ReadVInt64();
                if (oid == 0)
                {
                    if (!skipping)
                    {
                        _visitor?.OidReference(0);
                    }
                }
                else if (oid <= int.MinValue || oid > 0)
                {
                    if (!skipping)
                    {
                        _visitor?.OidReference((ulong)oid);
                        IterateOid((ulong)oid);
                    }
                }
                else
                {
                    var itemHandler = ((IFieldHandlerWithNestedFieldHandlers)handler).EnumerateNestedFieldHandlers().First();
                    IterateInlineList(ref reader, itemHandler, skipping, knownInlineRefs);
                }
            }
            else if (handler is DictionaryFieldHandler)
            {
                var oid = reader.ReadVInt64();
                if (oid == 0)
                {
                    if (!skipping)
                    {
                        _visitor?.OidReference(0);
                    }
                }
                else if (oid <= int.MinValue || oid > 0)
                {
                    if (!skipping)
                    {
                        _visitor?.OidReference((ulong)oid);
                        IterateOid((ulong)oid);
                    }
                }
                else
                {
                    var kvHandlers = ((IFieldHandlerWithNestedFieldHandlers)handler).EnumerateNestedFieldHandlers().ToArray();
                    IterateInlineDict(ref reader, kvHandlers[0], kvHandlers[1], skipping, knownInlineRefs);
                }
            }
            else if (handler is NullableFieldHandler)
            {
                var hasValue = reader.ReadBool();
                if (hasValue)
                {
                    var itemHandler = ((IFieldHandlerWithNestedFieldHandlers)handler).EnumerateNestedFieldHandlers().First();
                    IterateHandler(ref reader, itemHandler, skipping, null);
                }
            }
            else if (handler is OrderedEncryptedStringHandler)
            {
                var cipher = _tr.Owner.GetSymmetricCipher();
                if (cipher is InvalidSymmetricCipher)
                {
                    var length = reader.ReadVUInt32();
                    _visitor?.ScalarAsText($"Encrypted[{length}]");
                    if (length > 0)
                    {
                        reader.SkipBlock(length - 1);
                    }
                }
                else
                {
                    var enc  = reader.ReadByteArray();
                    var size = cipher.CalcOrderedPlainSizeFor(enc);
                    var dec  = new byte[size];
                    if (!cipher.OrderedDecrypt(enc, dec))
                    {
                        _visitor?.ScalarAsText($"Encrypted[{enc!.Length}] failed to decrypt");
                    }

                    var r = new SpanReader(dec);
                    _visitor?.ScalarAsText(r.ReadString() !);
                }
            }
            else if (handler is EncryptedStringHandler)
            {
                var cipher = _tr.Owner.GetSymmetricCipher();
                if (cipher is InvalidSymmetricCipher)
                {
                    var length = reader.ReadVUInt32();
                    _visitor?.ScalarAsText($"Encrypted[{length}]");
                    if (length > 0)
                    {
                        reader.SkipBlock(length - 1);
                    }
                }
                else
                {
                    var enc  = reader.ReadByteArray();
                    var size = cipher.CalcPlainSizeFor(enc);
                    var dec  = new byte[size];
                    if (!cipher.Decrypt(enc, dec))
                    {
                        _visitor?.ScalarAsText($"Encrypted[{enc!.Length}] failed to decrypt");
                    }

                    var r = new SpanReader(dec);
                    _visitor?.ScalarAsText(r.ReadString() !);
                }
            }
            else if (handler.NeedsCtx() || handler.HandledType() == null)
            {
                throw new BTDBException("Don't know how to iterate " + handler.Name);
            }
            else
            {
                if (skipping || _visitor == null)
                {
                    if (!_skippers.TryGetValue(handler, out var skipper))
                    {
                        var meth =
                            ILBuilder.Instance.NewMethod <SkipperFun>("Skip" + handler.Name);
                        var il = meth.Generator;
                        handler.Skip(il, il2 => il2.Ldarg(0), null);
                        il.Ret();
                        skipper = meth.Create();
                        _skippers.Add(handler, skipper);
                    }
                    skipper(ref reader);
                }
                else
                {
                    if (!_loaders.TryGetValue(handler, out var loader))
                    {
                        var meth =
                            ILBuilder.Instance.NewMethod <LoaderFun>("Load" + handler.Name);
                        var il = meth.Generator;
                        handler.Load(il, il2 => il2.Ldarg(0), null);
                        il.Box(handler.HandledType() !).Ret();
                        loader = meth.Create();
                        _loaders.Add(handler, loader);
                    }
                    var obj = loader(ref reader);
                    if (_visitor.NeedScalarAsObject())
                    {
                        _visitor.ScalarAsObject(obj);
                    }
                    if (_visitor.NeedScalarAsText())
                    {
                        _visitor.ScalarAsText(obj == null
                            ? "null"
                            : string.Format(CultureInfo.InvariantCulture, "{0}", obj));
                    }
                }
            }
        }