Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
DiffService.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2020 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.integrationtesting;
20
21import com.github.difflib.DiffUtils;
22import com.github.difflib.patch.AbstractDelta;
23import com.github.difflib.patch.Chunk;
24import com.github.difflib.patch.Patch;
25import java.io.File;
26import java.io.IOException;
27import java.nio.file.Files;
28import java.util.List;
29import java.util.Map;
30import java.util.stream.Collectors;
31import java.util.stream.Stream;
32import org.apache.commons.io.FileUtils;
33import org.apache.commons.lang3.StringUtils;
34import org.apache.commons.lang3.exception.ExceptionUtils;
35import org.apache.commons.lang3.tuple.Pair;
36
40public class DiffService {
41
45 public static class DiffServiceException extends Exception {
46
47 private static final long serialVersionUID = 1L;
48
54 DiffServiceException(String message) {
55 super(message);
56 }
57
64 DiffServiceException(String message, Throwable exception) {
65 super(message, exception);
66 }
67 }
68
69 private static final String ORIG_LINE_PREFIX = "< ";
70 private static final String CUR_LINE_PREFIX = "> ";
71 private static final String[] DIFF_BREAK = new String[]{"", "", ""};
72 private static final String[] FILE_DIFF_BREAK = new String[]{"", "", "", ""};
73 private static final String NEW_LINE = System.getProperty("line.separator");
74
86 String diffFilesOrDirs(File prevResult, File curResult) throws DiffServiceException {
87 if (prevResult.isDirectory() && curResult.isDirectory()) {
88 final Map<String, File> prevFiles = FileUtils.listFiles(prevResult, null, true).stream()
89 .collect(Collectors.toMap(f -> getRelative(prevResult, f), f -> f, (f1, f2) -> f1));
90
91 final Map<String, File> curFiles = FileUtils.listFiles(curResult, null, true).stream()
92 .collect(Collectors.toMap(f -> getRelative(curResult, f), f -> f, (f1, f2) -> f1));
93
94 Map<String, Pair<File, File>> prevCurMapping = Stream.of(prevFiles, curFiles)
95 .flatMap((map) -> map.keySet().stream())
96 .collect(Collectors.toMap(k -> k, k -> Pair.of(prevFiles.get(k), curFiles.get(k)), (v1, v2) -> v1));
97
98 String fullDiff = prevCurMapping.entrySet().stream()
99 .map((entry) -> getFileDiffs(entry.getValue().getLeft(), entry.getValue().getRight(), entry.getKey()))
100 .filter((val) -> val != null)
101 .collect(Collectors.joining(String.join(NEW_LINE, FILE_DIFF_BREAK)));
102
103 return fullDiff;
104
105 } else if (prevResult.isFile() && curResult.isFile()) {
106 return getFileDiffs(prevResult, curResult, prevResult.toString() + " / " + curResult.toString());
107
108 } else {
109 throw new DiffServiceException(String.format("%s and %s must be of same type (directory/file).", prevResult.toString(), curResult.toString()));
110 }
111 }
112
122 private String getFileDiffs(File orig, File cur, String identifier) {
123 boolean hasOrig = (orig != null && orig.exists());
124 boolean hasCur = (cur != null && cur.exists());
125 if (!hasOrig && !hasCur) {
126 return null;
127 } else if (!hasOrig && hasCur) {
128 return getHeaderWithDivider("ADDITIONAL FILE IN CURRENT: " + identifier);
129 } else if (hasOrig && !hasCur) {
130 return getHeaderWithDivider("MISSING FILE IN CURRENT: " + identifier);
131 } else {
132 try {
133 return diffLines(Files.readAllLines(orig.toPath()), Files.readAllLines(cur.toPath()), getHeaderWithDivider(identifier + ":"));
134 } catch (IOException ex) {
135 return getHeaderWithDivider(String.format("ERROR reading files at %s / %s %s%s",
136 orig.toString(), cur.toString(), NEW_LINE, ExceptionUtils.getStackTrace(ex)));
137 }
138 }
139 }
140
141 private String getChunkLineNumString(Chunk<?> chunk) {
142 return String.format("%d,%d", chunk.getPosition() + 1, chunk.getLines().size());
143 }
144
153 private String getDiffLineNumString(Chunk<?> orig, Chunk<?> cur) {
154 return String.format("-%s +%s", getChunkLineNumString(orig), getChunkLineNumString(cur));
155 }
156
166 private List<String> getLinesDiff(Chunk<String> orig, Chunk<String> cur) {
167 Stream<String> origPrefixed = orig.getLines().stream()
168 .map((line) -> ORIG_LINE_PREFIX + line);
169
170 Stream<String> curPrefixed = cur.getLines().stream()
171 .map((line) -> CUR_LINE_PREFIX + line);
172
173 return Stream.concat(origPrefixed, curPrefixed)
174 .collect(Collectors.toList());
175 }
176
177 private String getLinesDiffString(AbstractDelta<String> delta) {
178 String lineNums = getDiffLineNumString(delta.getSource(), delta.getTarget());
179 List<String> linesDiff = getLinesDiff(delta.getSource(), delta.getTarget());
180
181 return Stream.concat(Stream.of(lineNums), linesDiff.stream())
182 .collect(Collectors.joining(NEW_LINE)) + NEW_LINE;
183 }
184
195 private String diffLines(List<String> orig, List<String> cur, String header) {
196 //compute the patch: this is the diffutils part
197 Patch<String> patch = DiffUtils.diff(orig, cur);
198
199 String diff = patch.getDeltas().stream()
200 .map(delta -> getLinesDiffString(delta))
201 .collect(Collectors.joining(String.join(NEW_LINE, DIFF_BREAK)));
202
203 if (StringUtils.isBlank(diff)) {
204 return null;
205 }
206
207 return (header != null)
208 ? header + NEW_LINE + diff
209 : diff;
210 }
211
212 private String getHeaderWithDivider(String remark) {
213 String divider = "-----------------------------------------------------------";
214 return String.join(NEW_LINE, divider, remark, divider);
215 }
216
217 private String getRelative(File rootDirectory, File file) {
218 return rootDirectory.toURI().relativize(file.toURI()).getPath();
219 }
220}
String diffLines(List< String > orig, List< String > cur, String header)
String getRelative(File rootDirectory, File file)
String getLinesDiffString(AbstractDelta< String > delta)
String getFileDiffs(File orig, File cur, String identifier)
String getDiffLineNumString(Chunk<?> orig, Chunk<?> cur)
List< String > getLinesDiff(Chunk< String > orig, Chunk< String > cur)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.