/// <summary> /// Deserialise an API call from JSON /// </summary> /// <param name="apiArr">The serialised call data</param> /// <param name="trace">The trace the call belongs to</param> /// <param name="apiObj">The resulting API object</param> /// <returns></returns> public static bool TryDeserialise(JArray apiArr, TraceRecord trace, out APICALL?apiObj) { apiObj = null; if (apiArr[0].Type is not JTokenType.Date) { return(false); } DateTime graphConstructed = apiArr[0].ToObject <DateTime>(); ProtoGraph?graph = trace.GetProtoGraphByTime(graphConstructed); if (graph is null) { return(false); } apiObj = new APICALL(graph) { Node = graph.NodeList[apiArr[1].ToObject <int>()], Index = apiArr[2].ToObject <int>(), Repeats = apiArr[3].ToObject <ulong>(), UniqID = apiArr[4].ToObject <uint>() }; if (apiArr[5] is not null) { if (!DeserialiseEffects(apiArr[5], apiObj)) { return(false); } } return(true); }
/// <summary> /// Deserialise a timeline event from JSON /// </summary> /// <param name="jsnReader">A JsonReader for the trace file</param> /// <param name="serializer">A JsonSerializer</param> /// <param name="trace">The trace assocated with the timeline event</param> public TIMELINE_EVENT(JsonReader jsnReader, JsonSerializer serializer, TraceRecord trace) : base(eLogFilterBaseType.TimeLine) { jsnReader.Read(); JArray?itemMeta = serializer.Deserialize <JArray>(jsnReader); if (itemMeta is null || itemMeta.Count != 3) { return; } _eventType = itemMeta[0].ToObject <eTimelineEvent>(); JToken idTok = itemMeta[1]; JToken pIdTok = itemMeta[2]; //_item = item; switch (_eventType) { case eTimelineEvent.ProcessStart: case eTimelineEvent.ProcessEnd: SetIDs(ID: idTok.ToObject <ulong>(), parentID: pIdTok.ToObject <ulong>()); _item = trace.GetTraceByID(ID) !; Inited = true; break; case eTimelineEvent.ThreadStart: case eTimelineEvent.ThreadEnd: Debug.Assert(trace.ParentTrace == null || idTok.ToObject <ulong>() == trace.ParentTrace.PID); SetIDs(ID: idTok.ToObject <ulong>()); _item = trace.GetProtoGraphByTID(ID) !; Inited = true; break; case eTimelineEvent.APICall: jsnReader.Read(); JArray?apiArr = serializer.Deserialize <JArray>(jsnReader); if (apiArr is null) { Logging.RecordError("No APICALL data in timeline api event"); return; } if (!APICALL.TryDeserialise(apiArr, trace, out APICALL? apiObj) || apiObj is null) { Logging.RecordError("Bad APICALL data in timeline api event"); return; } SetIDs(ID: idTok.ToObject <ulong>(), parentID: pIdTok.ToObject <ulong>()); _item = apiObj; Inited = true; break; default: Debug.Assert(false, "Bad timeline event"); break; } }
/// <summary> /// Serialise the timeline event to JSON /// </summary> public void Serialise(Newtonsoft.Json.JsonWriter writer, Newtonsoft.Json.JsonSerializer serializer) { Debug.Assert(_item is not null); JArray meta = new JArray { TimelineEventType, ID, Parent }; meta.WriteTo(writer); if (TimelineEventType == eTimelineEvent.APICall) { APICALL apic = (Logging.APICALL)_item; apic.Serialise(writer, serializer); } }
/// <summary> /// Implementing effects as derived classes means safe deserialisation is quite clunky /// </summary> /// <param name="deTok">JToken of the APICALL details</param> /// <param name="apiObj">APICALL being deserialised</param> /// <returns>success</returns> private static bool DeserialiseEffects(JToken deTok, APICALL apiObj) { try { JObject?deJObj = deTok.ToObject <JObject>(); if (deJObj is null) { return(false); } apiObj.APIDetails = deTok.ToObject <APIDetailsWin.API_ENTRY>(); if (apiObj.APIDetails is not null && deJObj.TryGetValue("Effects", out JToken? effTok) && apiObj.APIDetails.Value.Effects is not null && effTok.Type is JTokenType.Array) { JArray?effArray = effTok.ToObject <JArray>(); for (int effecti = 0; effecti < effArray?.Count; effecti++) { JToken effItem = effArray[effecti]; JObject?effectObj = effItem.ToObject <JObject>(); if (effectObj is null) { return(false); } if (effectObj.TryGetValue("TypeName", out JToken? nameTok) && nameTok is not null) { switch (nameTok.ToString()) { case "Link": { JToken?entityIdx = effectObj["EntityIndex"]; JToken?refIdx = effectObj["ReferenceIndex"]; if (entityIdx is null || refIdx is null) { return(false); } int entityIndex = entityIdx.ToObject <int>(); int referenceIndex = refIdx.ToObject <int>(); APIDetailsWin.LinkReferenceEffect linkEff = new APIDetailsWin.LinkReferenceEffect(entityIndex, referenceIndex); apiObj.APIDetails.Value.Effects[effecti] = linkEff; break; } case "Use": { JToken?refIdx = effectObj["ReferenceIndex"]; if (refIdx is null) { return(false); } apiObj.APIDetails.Value.Effects[effecti] = new APIDetailsWin.UseReferenceEffect(refIdx.ToObject <int>()); break; } case "Destroy": { JToken?refIdx = effectObj["ReferenceIndex"]; if (refIdx is null) { return(false); } apiObj.APIDetails.Value.Effects[effecti] = new APIDetailsWin.DestroyReferenceEffect(refIdx.ToObject <int>()); break; } } } } } return(true); } catch (Exception e) { Logging.RecordException($"Failed to load API call details: {e.Message}", e); return(false); } }