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)); } } } }