예제 #1
0
        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.");
        }