19 package org.sleuthkit.autopsy.recentactivity;
 
   21 import java.io.DataInputStream;
 
   23 import java.io.FileInputStream;
 
   24 import java.io.FileNotFoundException;
 
   25 import java.io.IOException;
 
   26 import java.nio.ByteBuffer;
 
   27 import java.nio.ByteOrder;
 
   28 import java.util.Iterator;
 
   29 import java.util.NoSuchElementException;
 
   30 import java.util.logging.Level;
 
   43 final class BinaryCookieReader 
implements Iterable<Cookie> {
 
   46     private static final int MAGIC_SIZE = 4;
 
   47     private static final int SIZEOF_INT_BYTES = 4;
 
   48     private static final int PAGE_HEADER_VALUE = 256;
 
   50     private static final String COOKIE_MAGIC = 
"cook"; 
 
   52     private static final int MAC_EPOC_FIX = 978307200;
 
   54     private final int[] pageSizeArray;
 
   55     private final File cookieFile;
 
   62     private BinaryCookieReader(File cookieFile, 
int[] pageSizeArray) {
 
   63         this.cookieFile = cookieFile;
 
   64         this.pageSizeArray = pageSizeArray.clone();
 
   79     public static BinaryCookieReader initalizeReader(File cookieFile) 
throws FileNotFoundException, IOException {
 
   80         BinaryCookieReader reader = null;
 
   81         try (DataInputStream dataStream = 
new DataInputStream(
new FileInputStream(cookieFile))) {
 
   83             byte[] magic = 
new byte[MAGIC_SIZE];
 
   84             if (dataStream.read(magic) != MAGIC_SIZE) {
 
   85                 throw new IOException(
"Failed to read header, invalid file size (" + cookieFile.getName() + 
")"); 
 
   88             if (!(
new String(magic)).equals(COOKIE_MAGIC)) {
 
   89                 throw new IOException(cookieFile.getName() + 
" is not a cookie file"); 
 
   93             int pageCount = dataStream.readInt();
 
   95                 sizeArray = 
new int[pageCount];
 
   97                 for (
int cnt = 0; cnt < pageCount; cnt++) {
 
   98                     sizeArray[cnt] = dataStream.readInt();
 
  101                 LOG.log(Level.INFO, 
"No cookies found in {0}", cookieFile.getName()); 
 
  102                 sizeArray = 
new int[0];
 
  105             reader = 
new BinaryCookieReader(cookieFile, sizeArray);
 
  117     public Iterator<Cookie> iterator() {
 
  118         return new CookiePageIterator();
 
  128         Iterator<Cookie> currentIterator = null;
 
  129         DataInputStream dataStream = null;
 
  135             if (pageSizeArray == null || pageSizeArray.length == 0) {
 
  140                 dataStream = 
new DataInputStream(
new FileInputStream(cookieFile));
 
  142                 dataStream.skipBytes((2 * SIZEOF_INT_BYTES) + (pageSizeArray.length * SIZEOF_INT_BYTES));
 
  143             } 
catch (IOException ex) {
 
  145                 String errorMessage = String.format(
"An error occurred creating an input stream for %s", cookieFile.getName());
 
  146                 LOG.log(Level.WARNING, errorMessage, ex); 
 
  159             if (dataStream == null) {
 
  163             if (currentIterator == null || !currentIterator.hasNext()) {
 
  166                     if (pageIndex < pageSizeArray.length) {
 
  167                         byte[] nextPage = 
new byte[pageSizeArray[pageIndex]];
 
  168                         dataStream.read(nextPage);
 
  171                         currentIterator = currentPage.
iterator();
 
  178                 } 
catch (IOException ex) {
 
  180                     String errorMessage = String.format(
"A read error occured for file %s (pageIndex = %d)", cookieFile.getName(), pageIndex);
 
  181                     LOG.log(Level.WARNING, errorMessage, ex); 
 
  186             return currentIterator.hasNext();
 
  200                 throw new NoSuchElementException();
 
  202             return currentIterator.next();
 
  209             if (dataStream != null) {
 
  213                 } 
catch (IOException ex) {
 
  214                     String errorMessage = String.format(
"An error occurred trying to close stream for file %s", cookieFile.getName());
 
  215                     LOG.log(Level.WARNING, errorMessage, ex); 
 
  227         ByteBuffer pageBuffer;
 
  238             if (page == null || page.length == 0) {
 
  239                 throw new IllegalArgumentException(
"Invalid value for page passed to CookiePage constructor"); 
 
  242             pageBuffer = ByteBuffer.wrap(page);
 
  244             if (pageBuffer.getInt() != PAGE_HEADER_VALUE) {
 
  246                 throw new IOException(
"Invalid file format, bad page head value found"); 
 
  249             pageBuffer.order(ByteOrder.LITTLE_ENDIAN);
 
  250             int count = pageBuffer.getInt();
 
  251             cookieOffSets = 
new int[count];
 
  253             for (
int cnt = 0; cnt < count; cnt++) {
 
  254                 cookieOffSets[cnt] = pageBuffer.getInt();
 
  284                 if (pageBuffer == null) {
 
  288                 return index < cookieOffSets.length;
 
  299                     throw new NoSuchElementException();
 
  302                 int offset = cookieOffSets[index];
 
  303                 int size = pageBuffer.getInt(offset);
 
  304                 byte[] cookieBytes = 
new byte[size];
 
  305                 pageBuffer.get(cookieBytes, 0, size);
 
  308                 return new Cookie(cookieBytes);
 
  334             if (cookieBytes == null || cookieBytes.length == 0) {
 
  335                 throw new IllegalArgumentException(
"Invalid value for cookieBytes passed to Cookie constructor"); 
 
  338             ByteBuffer byteBuffer = ByteBuffer.wrap(cookieBytes);
 
  339             byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
 
  344             int urlOffset = byteBuffer.getInt();
 
  345             int nameOffset = byteBuffer.getInt();
 
  346             int pathOffset = byteBuffer.getInt();
 
  347             int valueOffset = byteBuffer.getInt();
 
  348             byteBuffer.getLong(); 
 
  350             expirationDate = byteBuffer.getDouble();
 
  351             creationDate = byteBuffer.getDouble();
 
  366             return ((
long) expirationDate) + MAC_EPOC_FIX;
 
  376             return ((
long) creationDate) + MAC_EPOC_FIX;
 
  425             byte[] stringBytes = 
new byte[byteArray.length - offset];
 
  426             for (
int index = 0; index < stringBytes.length; index++) {
 
  427                 byte nibble = byteArray[offset + index];
 
  428                 if (nibble != 
'\0') { 
 
  429                     stringBytes[index] = nibble;
 
  435             return new String(stringBytes);
 
Iterator< Cookie > iterator()
final Long getExpirationDate()
String decodeString(byte[] byteArray, int offset)
final Long getCreationDate()
Cookie(byte[] cookieBytes)
final double expirationDate
synchronized static Logger getLogger(String name)
static final int COOKIE_HEAD_SKIP
final double creationDate