Autopsy  4.9.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
SqliteTextExtractor.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2018-2018 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.textreaders;
20 
21 import java.io.IOException;
22 import java.io.Reader;
23 import java.util.Iterator;
24 import java.util.Objects;
25 import java.util.function.Consumer;
26 import java.util.logging.Level;
30 import org.sleuthkit.datamodel.AbstractFile;
31 import org.sleuthkit.datamodel.Content;
32 
42 final class SqliteTextExtractor extends TextExtractor {
43 
44  private static final String SQLITE_MIMETYPE = "application/x-sqlite3";
45  private static final Logger logger = Logger.getLogger(SqliteTextExtractor.class.getName());
46  private final AbstractFile file;
47 
48  public SqliteTextExtractor(Content file) {
49  this.file = (AbstractFile) file;
50  }
59  @Override
60  public boolean isSupported(Content file, String detectedFormat) {
61  return SQLITE_MIMETYPE.equals(detectedFormat);
62  }
63 
73  @Override
74  public Reader getReader() throws ExtractionException {
75  return new SQLiteStreamReader(file);
76  }
77 
83  private class SQLiteStreamReader extends Reader {
84 
85  private final SQLiteTableReader reader;
86  private final AbstractFile file;
87 
88  private Iterator<String> tableNames;
89  private String currentTableName;
90 
91  private char[] buf;
93  private int totalColumns;
94 
95  private int bufIndex;
96 
105  public SQLiteStreamReader(AbstractFile file) {
106  this.file = file;
107  reader = new SQLiteTableReader.Builder(file)
110  }
111 
123  private Consumer<Object> getForAllTableValuesStrategy() {
124  return new Consumer<Object>() {
125  private int columnIndex = 0;
126 
127  @Override
128  public void accept(Object value) {
129  columnIndex++;
130  //Ignore blobs
131  String objectStr = (value instanceof byte[]) ? "" : Objects.toString(value, "");
132 
133  if (columnIndex > 1 && columnIndex < totalColumns) {
134  objectStr += " ";
135  }
136  if (columnIndex == 1) {
137  objectStr = "\t" + objectStr + " ";
138  }
139  if (columnIndex == totalColumns) {
140  objectStr += "\n";
141  }
142 
143  fillBuffer(objectStr);
144  columnIndex = columnIndex % totalColumns;
145  }
146  };
147  }
148 
161  private Consumer<String> getColumnNameStrategy() {
162  return new Consumer<String>() {
163  private int columnIndex = 0;
164 
165  @Override
166  public void accept(String columnName) {
167  if (columnIndex == 0) {
168  fillBuffer("\n" + currentTableName + "\n\n\t");
169  }
170  columnIndex++;
171 
172  fillBuffer(columnName + ((columnIndex == totalColumns) ? "\n" : " "));
173 
174  //Reset the columnCount to 0 for next table read
175  columnIndex = columnIndex % totalColumns;
176  }
177  };
178  }
179 
187  private void fillBuffer(String val) {
188  for (int i = 0; i < val.length(); i++) {
189  if (bufIndex != buf.length) {
190  buf[bufIndex++] = val.charAt(i);
191  } else {
192  leftOvers = new ExcessBytes(val, i);
193  break;
194  }
195  }
196  }
197 
206  @Override
207  public int read(char[] cbuf, int off, int len) throws IOException {
208  buf = cbuf;
209 
210  bufIndex = off;
211 
212  //Lazily wait to get table names until first call to read.
213  if (Objects.isNull(tableNames)) {
214  try {
215  tableNames = reader.getTableNames().iterator();
216  } catch (SQLiteTableReaderException ex) {
217  //Can't get table names so can't read the file!
218  return -1;
219  }
220  }
221 
222  //If there are excess bytes from last read, then copy thoses in.
223  if (Objects.nonNull(leftOvers) && !leftOvers.isFinished()) {
224  bufIndex += leftOvers.read(cbuf, off, len);
225  }
226 
227  //Keep grabbing table names from the queue and reading them until
228  //our buffer is full.
229  while (bufIndex != len) {
230  if (Objects.isNull(currentTableName) || reader.isFinished()) {
231  if (tableNames.hasNext()) {
232  currentTableName = tableNames.next();
233  try {
234  totalColumns = reader.getColumnCount(currentTableName);
235  reader.read(currentTableName, () -> bufIndex == len);
236  } catch (SQLiteTableReaderException ex) {
237  logger.log(Level.WARNING, String.format(
238  "Error attempting to read file table: [%s]" //NON-NLS
239  + " for file: [%s] (id=%d).", currentTableName, //NON-NLS
240  file.getName(), file.getId()), ex.getMessage());
241  }
242  } else {
243  if (bufIndex == off) {
244  return -1;
245  }
246  return bufIndex;
247  }
248  } else {
249  try {
250  reader.read(currentTableName, () -> bufIndex == len);
251  } catch (SQLiteTableReaderException ex) {
252  logger.log(Level.WARNING, String.format(
253  "Error attempting to read file table: [%s]" //NON-NLS
254  + " for file: [%s] (id=%d).", currentTableName, //NON-NLS
255  file.getName(), file.getId()), ex.getMessage());
256  }
257  }
258  }
259 
260  return bufIndex;
261  }
262 
263  @Override
264  public void close() throws IOException {
265  try {
266  reader.close();
267  } catch (SQLiteTableReaderException ex) {
268  logger.log(Level.WARNING, "Could not close SQliteTableReader.", ex.getMessage());
269  }
270  }
271 
276  private class ExcessBytes {
277 
278  private final String entity;
279  private Integer pointer;
280 
281  public ExcessBytes(String entity, Integer pointer) {
282  this.entity = entity;
283  this.pointer = pointer;
284  }
285 
286  public boolean isFinished() {
287  return entity.length() == pointer;
288  }
289 
300  public int read(char[] buf, int off, int len) {
301  for (int i = off; i < len; i++) {
302  if (isFinished()) {
303  return i - off;
304  }
305 
306  buf[i] = entity.charAt(pointer++);
307  }
308 
309  return len - off;
310  }
311  }
312  }
313 }

Copyright © 2012-2018 Basis Technology. Generated on: Tue Dec 18 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.