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

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