Autopsy  4.20.0
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  */
19 package org.sleuthkit.autopsy.integrationtesting;
20 
21 import com.github.difflib.DiffUtils;
22 import com.github.difflib.patch.AbstractDelta;
23 import com.github.difflib.patch.Chunk;
24 import com.github.difflib.patch.Patch;
25 import java.io.File;
26 import java.io.IOException;
27 import java.nio.file.Files;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
32 import org.apache.commons.io.FileUtils;
33 import org.apache.commons.lang3.StringUtils;
34 import org.apache.commons.lang3.exception.ExceptionUtils;
35 import org.apache.commons.lang3.tuple.Pair;
36 
40 public 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 }
List< String > getLinesDiff(Chunk< String > orig, Chunk< String > cur)
String getRelative(File rootDirectory, File file)
String getDiffLineNumString(Chunk<?> orig, Chunk<?> cur)
String getLinesDiffString(AbstractDelta< String > delta)
String getFileDiffs(File orig, File cur, String identifier)
String diffLines(List< String > orig, List< String > cur, String header)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.