Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
TranslatedTextViewer.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.texttranslation.ui;
20
21import com.google.common.collect.Lists;
22import com.google.common.util.concurrent.ThreadFactoryBuilder;
23import java.awt.Component;
24import java.awt.ComponentOrientation;
25import java.awt.Font;
26import java.awt.event.ActionEvent;
27import java.awt.event.ActionListener;
28import java.io.IOException;
29import java.io.Reader;
30import java.util.Arrays;
31import java.util.concurrent.ExecutorService;
32import java.util.concurrent.Executors;
33import java.util.concurrent.ThreadFactory;
34import org.openide.nodes.Node;
35import org.openide.util.lookup.ServiceProvider;
36import org.sleuthkit.autopsy.corecomponentinterfaces.TextViewer;
37import org.sleuthkit.datamodel.AbstractFile;
38import org.openide.util.Lookup;
39import org.openide.util.NbBundle;
40import org.openide.util.lookup.Lookups;
41import org.sleuthkit.autopsy.coreutils.ExecUtil.ProcessTerminator;
42import org.sleuthkit.autopsy.textextractors.TextExtractor;
43import org.sleuthkit.autopsy.textextractors.TextExtractorFactory;
44import org.sleuthkit.autopsy.textextractors.configs.ImageConfig;
45import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
46import java.util.List;
47import java.util.logging.Level;
48import javax.swing.SwingUtilities;
49import org.sleuthkit.autopsy.contentviewers.utils.ViewerPriority;
50import org.sleuthkit.autopsy.core.UserPreferences;
51import org.sleuthkit.autopsy.coreutils.Logger;
52import org.sleuthkit.autopsy.coreutils.PlatformUtil;
53import org.sleuthkit.autopsy.texttranslation.ui.TranslationContentPanel.DisplayDropdownOptions;
54
58@ServiceProvider(service = TextViewer.class, position = 4)
59public final class TranslatedTextViewer implements TextViewer {
60
61 private static final Logger logger = Logger.getLogger(TranslatedTextViewer.class.getName());
62
63 private static final int MAX_EXTRACT_SIZE_BYTES = 25600;
64 private static final List<String> INSTALLED_LANGUAGE_PACKS = PlatformUtil.getOcrLanguagePacks();
66
67 private volatile Node node;
69 private final ThreadFactory translationThreadFactory
70 = new ThreadFactoryBuilder().setNameFormat("translation-content-viewer-%d").build();
71 private final ExecutorService executorService = Executors.newSingleThreadExecutor(translationThreadFactory);
72
73 @NbBundle.Messages({
74 "TranslatedTextViewer.maxPayloadSize=Up to the first %dKB of text will be translated"
75 })
76 @Override
77 public void setNode(final Node node) {
78 this.node = node;
79 SelectionChangeListener displayDropDownListener = new DisplayDropDownChangeListener();
80 panel.addDisplayTextActionListener(displayDropDownListener);
81 panel.addOcrDropDownActionListener(new OCRDropdownChangeListener());
83 panel.addLanguagePackNames(INSTALLED_LANGUAGE_PACKS);
84 }
85 panel.enableOCRSelection(UserPreferences.getUseOcrInTranslation());
86
87 int payloadMaxInKB = TextTranslationService.getInstance().getMaxTextChars() / 1000;
88 panel.setWarningLabelMsg(String.format(Bundle.TranslatedTextViewer_maxPayloadSize(), payloadMaxInKB));
89
90 //Force a background task.
91 displayDropDownListener.actionPerformed(null);
92 }
93
94 @NbBundle.Messages({"TranslatedTextViewer.title=Translation"})
95 @Override
96 public String getTitle() {
97 return Bundle.TranslatedTextViewer_title();
98 }
99
100 @NbBundle.Messages({"TranslatedTextViewer.toolTip=Displays translated file text."})
101 @Override
102 public String getToolTip() {
103 return Bundle.TranslatedTextViewer_toolTip();
104 }
105
106 @Override
108 return new TranslatedTextViewer();
109 }
110
111 @Override
112 public Component getComponent() {
113 return panel;
114 }
115
116 @Override
117 public void resetComponent() {
118 panel.reset();
119 this.node = null;
120 if (backgroundTask != null) {
121 backgroundTask.cancel(true);
122 }
123 backgroundTask = null;
124 }
125
126 @Override
127 public boolean isSupported(Node node) {
128 if (null == node) {
129 return false;
130 }
131
133 return false;
134 }
135
136 AbstractFile file = node.getLookup().lookup(AbstractFile.class);
137 return file != null;
138 }
139
140 @Override
141 public int isPreferred(Node node) {
142 // Returning zero makes it unlikely this object will be the preferred content viewer,
143 // i.e., the active tab, when the content viewers are first displayed.
144 return ViewerPriority.viewerPriority.LevelZero.getFlag();
145 }
146
151
152 private final AbstractFile file;
153
154 private ExtractAndTranslateTextTask(AbstractFile file, boolean translateText) {
155 super(translateText, String.format("%s (objId=%d)", file.getName(), file.getId()));
156 this.file = file;
157 }
158
166 @NbBundle.Messages({
167 "TranslatedContentViewer.extractingText=Extracting text, please wait...",
168 "# {0} - exception message", "TranslatedContentViewer.errorExtractingText=An error occurred while extracting the text ({0}).",
169 })
170 protected String retrieveText() throws IOException, InterruptedException, IllegalStateException {
171 SwingUtilities.invokeLater(() -> {
172 onProgressDisplay(Bundle.TranslatedContentViewer_extractingText(), ComponentOrientation.LEFT_TO_RIGHT, Font.ITALIC);
173 });
174
175 try {
176 return getFileText(file);
177 } catch (IOException | TextExtractor.InitReaderException ex) {
178 logger.log(Level.WARNING, String.format("Error extracting text for file %s (objId=%d)", file.getName(), file.getId()), ex);
179 // throw new exception with message to be displayed to user
180 throw new IllegalStateException(Bundle.TranslatedContentViewer_errorExtractingText(ex.getMessage()), ex);
181 }
182 }
183
184
197 @NbBundle.Messages({
198 "TranslatedContentViewer.ocrNotEnabled=OCR is not enabled. To change, go to Tools->Options->Machine Translation",
199 })
200 private String getFileText(AbstractFile file) throws IOException, InterruptedException, TextExtractor.InitReaderException {
201 final boolean isImage = file.getMIMEType().toLowerCase().startsWith("image/"); // NON-NLS
202 if (isImage && ! UserPreferences.getUseOcrInTranslation()) {
203 return Bundle.TranslatedContentViewer_ocrNotEnabled();
204 }
205
207
208 //Correct for UTF-8
209 byte[] resultInUTF8Bytes = result.getBytes("UTF8");
210 byte[] trimToArraySize = Arrays.copyOfRange(resultInUTF8Bytes, 0,
211 Math.min(resultInUTF8Bytes.length, MAX_EXTRACT_SIZE_BYTES));
212 return new String(trimToArraySize, "UTF-8");
213 }
214
228 private String extractText(AbstractFile source, boolean ocrEnabled) throws IOException, InterruptedException, TextExtractor.InitReaderException {
229 Reader textExtractor = getTextExtractor(source, ocrEnabled);
230
231 char[] cbuf = new char[8096];
232 StringBuilder textBuilder = new StringBuilder();
233
234 //bytesRead can be an int so long as the max file size
235 //is sufficiently small
236 int bytesRead = 0;
237 int read;
238
239 while ((read = textExtractor.read(cbuf)) != -1) {
240 if (this.isCancelled()) {
241 throw new InterruptedException();
242 }
243
244 //Short-circuit the read if its greater than our max
245 //translatable size
246 int bytesLeft = MAX_EXTRACT_SIZE_BYTES - bytesRead;
247
248 if (bytesLeft < read) {
249 textBuilder.append(cbuf, 0, bytesLeft);
250 return textBuilder.toString();
251 }
252
253 textBuilder.append(cbuf, 0, read);
254 bytesRead += read;
255 }
256
257 return textBuilder.toString();
258 }
259
273 private Reader getTextExtractor(AbstractFile file, boolean ocrEnabled) throws IOException,
275 Lookup context = null;
276
277 if (ocrEnabled) {
278 ImageConfig imageConfig = new ImageConfig();
279 imageConfig.setOCREnabled(true);
280
281 String ocrSelection = panel.getSelectedOcrLanguagePack();
282 if (!ocrSelection.isEmpty()) {
283 imageConfig.setOCRLanguages(Lists.newArrayList(ocrSelection));
284 }
285
286 //Terminate any OS process running in the extractor if this
287 //SwingWorker has been cancelled.
288 ProcessTerminator terminator = () -> isCancelled();
289 context = Lookups.fixed(imageConfig, terminator);
290 }
291
292 try {
295 //Fall-back onto the strings extractor
297 }
298 }
299
300
301 @Override
302 protected void onTextDisplay(String text, ComponentOrientation orientation, int font) {
303 panel.display(text, orientation, font);
304 }
305 }
306
307
312 private abstract class SelectionChangeListener implements ActionListener {
313
314 private String currentSelection;
315
316 abstract String getSelection();
317
318 @Override
319 public final void actionPerformed(ActionEvent e) {
320 String selection = getSelection();
321 if (!selection.equals(currentSelection)) {
322 currentSelection = selection;
323
324 if (backgroundTask != null && !backgroundTask.isDone()) {
325 backgroundTask.cancel(true);
326 }
327
328 AbstractFile file = node.getLookup().lookup(AbstractFile.class);
329 String textDisplaySelection = panel.getDisplayDropDownSelection();
330 boolean translateText = !textDisplaySelection.equals(DisplayDropdownOptions.ORIGINAL_TEXT.toString());
331 backgroundTask = new ExtractAndTranslateTextTask(file, translateText);
332
333 //Pass the background task to a single threaded pool to keep
334 //the number of jobs running to one.
336 }
337 }
338 }
339
344
345 @Override
346 String getSelection() {
347 return panel.getDisplayDropDownSelection();
348 }
349 }
350
355
356 @Override
357 String getSelection() {
358 return panel.getSelectedOcrLanguagePack();
359 }
360 }
361}
synchronized static Logger getLogger(String name)
Definition Logger.java:124
static TextExtractor getExtractor(Content content, Lookup context)
static TextExtractor getStringsExtractor(Content content, Lookup context)
TranslateTextTask(boolean translateText, String fileDescriptor)
void onProgressDisplay(String text, ComponentOrientation orientation, int font)

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