private void ExtractPage(PageOptions options, JsonMapNode root) { Stopwatch w = Stopwatch.StartNew(); Console.WriteLine($"Extracting {options.Count:n0} results from index {options.Index:n0}\r\n from \"{options.InputFilePath}\"\r\n into \"{options.OutputFilePath}\"..."); JsonMapNode runs, run, results; // Get 'runs' node from map. If log was too small, page using the object model if (root == null || root.Nodes == null || root.Nodes.TryGetValue("runs", out runs) == false) { PageViaOm(options); return; } // Verify RunIndex in range if (options.RunIndex >= runs.Count) { throw new ArgumentOutOfRangeException($"Page requested for RunIndex {options.RunIndex}, but Log had only {runs.Count} runs."); } // Get 'results' from map. If log was too small, page using the object model if (!runs.Nodes.TryGetValue(options.RunIndex.ToString(), out run) || run.Nodes == null || run.Nodes.TryGetValue("results", out results) == false || results.ArrayStarts == null) { // Log too small; convert via OM PageViaOm(options); return; } if (options.Index + options.Count > results.Count) { throw new ArgumentOutOfRangeException($"Page requested from Result {options.Index} to {options.Index + options.Count}, but Run has only {results.Count} results."); } Console.WriteLine($"Run {options.RunIndex} in \"{options.InputFilePath}\" has {results.Count:n0} results."); Func <Stream> inputStreamProvider = () => _fileSystem.OpenRead(options.InputFilePath); long firstResultStart = results.FindArrayStart(options.Index, inputStreamProvider); long lastResultEnd = results.FindArrayStart(options.Index + options.Count, inputStreamProvider) - 1; // Ensure output directory exists string outputFolder = Path.GetDirectoryName(Path.GetFullPath(options.OutputFilePath)); Directory.CreateDirectory(outputFolder); // Build the Sarif Log subset long lengthWritten = 0; byte[] buffer = new byte[64 * 1024]; using (Stream output = _fileSystem.Create(options.OutputFilePath)) using (Stream source = _fileSystem.OpenRead(options.InputFilePath)) { // Copy everything up to 'runs' (includes the '[') JsonMapNode.CopyStreamBytes(source, output, 0, runs.Start, buffer); // In the run, copy everything to 'results' (includes the '[') JsonMapNode.CopyStreamBytes(source, output, run.Start, results.Start, buffer); // Find and copy the desired range of results, excluding the last ',' JsonMapNode.CopyStreamBytes(source, output, firstResultStart, lastResultEnd, buffer, omitFromLast: (byte)','); // Copy everything after the results array to the end of the run (includes the '}') JsonMapNode.CopyStreamBytes(source, output, results.End, run.End, buffer); // Omit all subsequent runs // Copy everything after all runs (includes runs ']' and log '}') JsonMapNode.CopyStreamBytes(source, output, runs.End, root.End, buffer); lengthWritten = output.Length; } w.Stop(); Console.WriteLine($"Done; wrote {(lengthWritten / (double)(1024 * 1024)):n2} MB in {w.Elapsed.TotalSeconds:n1}s."); }