diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..a0cbe33 --- /dev/null +++ b/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..42ac320 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + java-libpst + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/PropertyNames.txt b/PropertyNames.txt index 572a87f..16e6278 100644 --- a/PropertyNames.txt +++ b/PropertyNames.txt @@ -135,6 +135,7 @@ 3FDE=PidTagInternetCodepage 3FF1=PidTagMessageLocaleId 3FFD=PidTagMessageCodepage +3ff9=PidTagCreatorName 4019=PidTagSenderFlags 401A=PidTagSentRepresentingFlags 401B=PidTagReceivedByFlags @@ -170,6 +171,8 @@ 7FFD=PidTagAttachmentFlags 7FFE=PidTagAttachmentHidden 7FFF=PidTagAttachmentContactPhoto +3FFA=PidTagLastModifiedName_W +3FFB=PidTagLastModifierEntryId 00000001=PidLidAttendeeCriticalChange 00000002=PidLidWhere 00000003=PidLidGlobalObjectId diff --git a/com/pff/LZFu.java b/com/pff/LZFu.java deleted file mode 100644 index c5a573b..0000000 --- a/com/pff/LZFu.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2010 Richard Johnson & Orin Eman - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * --- - * - * This file is part of java-libpst. - * - * java-libpst is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * java-libpst is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with java-libpst. If not, see . - * - */ - -package com.pff; - -import java.io.UnsupportedEncodingException; - -/** - * An implementation of the LZFu algorithm to decompress RTF content - * @author Richard Johnson - */ -public class LZFu { - - public static final String LZFU_HEADER = "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscript \\fdecor MS Sans SerifSymbolArialTimes New RomanCourier{\\colortbl\\red0\\green0\\blue0\n\r\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx"; - - public static String decode(byte[] data) - throws PSTException - { - - @SuppressWarnings("unused") - int compressedSize = (int)PSTObject.convertLittleEndianBytesToLong(data, 0, 4); - int uncompressedSize = (int)PSTObject.convertLittleEndianBytesToLong(data, 4, 8); - int compressionSig = (int)PSTObject.convertLittleEndianBytesToLong(data, 8, 12); - @SuppressWarnings("unused") - int compressedCRC = (int)PSTObject.convertLittleEndianBytesToLong(data, 12, 16); - - if (compressionSig == 0x75465a4c) { - // we are compressed... - byte[] output = new byte[uncompressedSize]; - int outputPosition = 0; - byte[] lzBuffer = new byte[4096]; - // preload our buffer. - try { - byte[] bytes = LZFU_HEADER.getBytes("US-ASCII"); - System.arraycopy(bytes, 0, lzBuffer, 0, LZFU_HEADER.length()); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - int bufferPosition = LZFU_HEADER.length(); - int currentDataPosition = 16; - - // next byte is the flags, - while (currentDataPosition < data.length - 2 && outputPosition < output.length) { - int flags = data[currentDataPosition++] & 0xFF; - for (int x = 0; x < 8 && outputPosition < output.length; x++) { - boolean isRef = ((flags & 1) == 1); - flags >>= 1; - if (isRef) { - // get the starting point for the buffer and the - // length to read - int refOffsetOrig = data[currentDataPosition++] & 0xFF; - int refSizeOrig = data[currentDataPosition++] & 0xFF; - int refOffset = (refOffsetOrig << 4) | (refSizeOrig >>> 4); - int refSize = (refSizeOrig & 0xF) + 2; - //refOffset &= 0xFFF; - try { - // copy the data from the buffer - int index = refOffset; - for (int y = 0; y < refSize && outputPosition < output.length; y++) { - output[outputPosition++] = lzBuffer[index]; - lzBuffer[bufferPosition] = lzBuffer[index]; - bufferPosition++; - bufferPosition %= 4096; - ++index; - index %= 4096; - } - } catch ( Exception e ) { - e.printStackTrace(); - } - - } else { - // copy the byte over - lzBuffer[bufferPosition] = data[currentDataPosition]; - bufferPosition++; - bufferPosition %= 4096; - output[outputPosition++] = data[currentDataPosition++]; - } - } - } - - if ( outputPosition != uncompressedSize ) { - throw new PSTException(String.format("Error decompressing RTF! Expected %d bytes, got %d bytes\n", uncompressedSize, outputPosition)); - } - return new String(output).trim(); - - } else if (compressionSig == 0x414c454d) { - // we are not compressed! - // just return the rest of the contents as a string - byte[] output = new byte[data.length-16]; - System.arraycopy(data, 16, output, 0, data.length-16); - return new String(output).trim(); - } - - return ""; - } -} diff --git a/com/pff/PSTUtils.java b/com/pff/PSTUtils.java new file mode 100644 index 0000000..402b223 --- /dev/null +++ b/com/pff/PSTUtils.java @@ -0,0 +1,376 @@ +package com.pff; + +import java.io.UnsupportedEncodingException; +import java.util.Calendar; +import java.util.Date; + +import com.pff.exceptions.PSTException; +import com.pff.objects.sub.PSTTimeZone; + +public abstract class PSTUtils { + + public static final String LZFU_HEADER = "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscript \\fdecor MS Sans SerifSymbolArialTimes New RomanCourier{\\colortbl\\red0\\green0\\blue0\n\r\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx"; + + + // substitution table for the compressible encryption type. + static int[] compEnc = { + 0x47, 0xf1, 0xb4, 0xe6, 0x0b, 0x6a, 0x72, 0x48, 0x85, 0x4e, 0x9e, 0xeb, 0xe2, 0xf8, 0x94, 0x53, + 0xe0, 0xbb, 0xa0, 0x02, 0xe8, 0x5a, 0x09, 0xab, 0xdb, 0xe3, 0xba, 0xc6, 0x7c, 0xc3, 0x10, 0xdd, + 0x39, 0x05, 0x96, 0x30, 0xf5, 0x37, 0x60, 0x82, 0x8c, 0xc9, 0x13, 0x4a, 0x6b, 0x1d, 0xf3, 0xfb, + 0x8f, 0x26, 0x97, 0xca, 0x91, 0x17, 0x01, 0xc4, 0x32, 0x2d, 0x6e, 0x31, 0x95, 0xff, 0xd9, 0x23, + 0xd1, 0x00, 0x5e, 0x79, 0xdc, 0x44, 0x3b, 0x1a, 0x28, 0xc5, 0x61, 0x57, 0x20, 0x90, 0x3d, 0x83, + 0xb9, 0x43, 0xbe, 0x67, 0xd2, 0x46, 0x42, 0x76, 0xc0, 0x6d, 0x5b, 0x7e, 0xb2, 0x0f, 0x16, 0x29, + 0x3c, 0xa9, 0x03, 0x54, 0x0d, 0xda, 0x5d, 0xdf, 0xf6, 0xb7, 0xc7, 0x62, 0xcd, 0x8d, 0x06, 0xd3, + 0x69, 0x5c, 0x86, 0xd6, 0x14, 0xf7, 0xa5, 0x66, 0x75, 0xac, 0xb1, 0xe9, 0x45, 0x21, 0x70, 0x0c, + 0x87, 0x9f, 0x74, 0xa4, 0x22, 0x4c, 0x6f, 0xbf, 0x1f, 0x56, 0xaa, 0x2e, 0xb3, 0x78, 0x33, 0x50, + 0xb0, 0xa3, 0x92, 0xbc, 0xcf, 0x19, 0x1c, 0xa7, 0x63, 0xcb, 0x1e, 0x4d, 0x3e, 0x4b, 0x1b, 0x9b, + 0x4f, 0xe7, 0xf0, 0xee, 0xad, 0x3a, 0xb5, 0x59, 0x04, 0xea, 0x40, 0x55, 0x25, 0x51, 0xe5, 0x7a, + 0x89, 0x38, 0x68, 0x52, 0x7b, 0xfc, 0x27, 0xae, 0xd7, 0xbd, 0xfa, 0x07, 0xf4, 0xcc, 0x8e, 0x5f, + 0xef, 0x35, 0x9c, 0x84, 0x2b, 0x15, 0xd5, 0x77, 0x34, 0x49, 0xb6, 0x12, 0x0a, 0x7f, 0x71, 0x88, + 0xfd, 0x9d, 0x18, 0x41, 0x7d, 0x93, 0xd8, 0x58, 0x2c, 0xce, 0xfe, 0x24, 0xaf, 0xde, 0xb8, 0x36, + 0xc8, 0xa1, 0x80, 0xa6, 0x99, 0x98, 0xa8, 0x2f, 0x0e, 0x81, 0x65, 0x73, 0xe4, 0xc2, 0xa2, 0x8a, + 0xd4, 0xe1, 0x11, 0xd0, 0x08, 0x8b, 0x2a, 0xf2, 0xed, 0x9a, 0x64, 0x3f, 0xc1, 0x6c, 0xf9, 0xec + }; + + /** + * Output a dump of data in hex format in the order it was read in + * @param data + * @param pretty + */ + public static void printHexFormatted(byte[] data, boolean pretty) { + printHexFormatted(data,pretty, new int[0]); + } + protected static void printHexFormatted(byte[] data, boolean pretty, int[] indexes) { + // groups of two + if (pretty) { System.out.println("---"); } + long tmpLongValue; + String line = ""; + int nextIndex = 0; + int indexIndex = 0; + if (indexes.length > 0) { + nextIndex = indexes[0]; + indexIndex++; + } + for (int x = 0; x < data.length; x++) { + tmpLongValue = (long)data[x] & 0xff; + + if (indexes.length > 0 && + x == nextIndex && + nextIndex < data.length) + { + System.out.print("+"); + line += "+"; + while (indexIndex < indexes.length-1 && indexes[indexIndex] <= nextIndex) + { + indexIndex++; + } + nextIndex = indexes[indexIndex]; + //indexIndex++; + } + + if (Character.isLetterOrDigit((char)tmpLongValue)) { + line += (char)tmpLongValue; + } + else + { + line += "."; + } + + if (Long.toHexString(tmpLongValue).length() < 2) { + System.out.print("0"); + } + System.out.print(Long.toHexString(tmpLongValue)); + if (x % 2 == 1 && pretty) { + System.out.print(" "); + } + if (x % 16 == 15 && pretty) { + System.out.print(" "+line); + System.out.println(""); + line = ""; + } + } + if (pretty) { System.out.println(" "+line); System.out.println("---"); System.out.println(data.length); } else { } + } + + + + /** + * decode a lump of data that has been encrypted with the compressible encryption + * @param data + * @return decoded data + */ + public static byte[] decode(byte[] data) { + int temp; + for (int x = 0; x < data.length; x++) { + temp = data[x] & 0xff; + data[x] = (byte)compEnc[temp]; + } + return data; + } + + + public static byte[] encode(byte[] data) { + // create the encoding array... + int[] enc = new int[compEnc.length]; + for (int x = 0; x < enc.length; x++) { + enc[compEnc[x]] = x; + } + + // now it's just the same as decode... + int temp; + for (int x = 0; x < data.length; x++) { + temp = data[x] & 0xff; + data[x] = (byte)enc[temp]; + } + return data; + } + + + /** + * Utility function for converting little endian bytes into a usable java long + * @param data + * @return long version of the data + */ + public static long convertLittleEndianBytesToLong(byte[] data) { + return convertLittleEndianBytesToLong(data, 0, data.length); + } + /** + * Utility function for converting little endian bytes into a usable java long + * @param data + * @param start + * @param end + * @return long version of the data + */ + public static long convertLittleEndianBytesToLong(byte[] data, int start, int end) { + + long offset = data[end-1] & 0xff; + long tmpLongValue; + for (int x = end-2; x >= start; x--) { + offset = offset << 8; + tmpLongValue = (long)data[x] & 0xff; + offset |= tmpLongValue; + } + + return offset; + } + + /** + * Utility function for converting big endian bytes into a usable java long + * @param data + * @param start + * @param end + * @return long version of the data + */ + public static long convertBigEndianBytesToLong(byte[] data, int start, int end) { + + long offset = 0; + for ( int x = start; x < end; ++x ) { + offset = offset << 8; + offset |= ((long)data[x] & 0xFFL); + } + + return offset; + } +/* + protected static boolean isPSTArray(byte[] data) { + return (data[0] == 1 && data[1] == 1); + } +/**/ +/* + protected static int[] getBlockOffsets(RandomAccessFile in, byte[] data) + throws IOException, PSTException + { + // is the data an array? + if (!(data[0] == 1 && data[1] == 1)) + { + throw new PSTException("Unable to process array, does not appear to be one!"); + } + + // we are an array! + // get the array items and merge them together + int numberOfEntries = (int)PSTObject.convertLittleEndianBytesToLong(data, 2, 4); + int[] output = new int[numberOfEntries]; + int tableOffset = 8; + int blockOffset = 0; + for (int y = 0; y < numberOfEntries; y++) { + // get the offset identifier + long tableOffsetIdentifierIndex = PSTObject.convertLittleEndianBytesToLong(data, tableOffset, tableOffset+8); + // clear the last bit of the identifier. Why so hard? + tableOffsetIdentifierIndex = (tableOffsetIdentifierIndex & 0xfffffffe); + OffsetIndexItem tableOffsetIdentifier = PSTObject.getOffsetIndexNode(in, tableOffsetIdentifierIndex); + blockOffset += tableOffsetIdentifier.size; + output[y] = blockOffset; + tableOffset += 8; + } + + // replace the item data with the stuff from the array... + return output; + } +/**/ + + + + + + /** + * the code below was taken from a random apache project + * http://www.koders.com/java/fidA9D4930E7443F69F32571905DD4CA01E4D46908C.aspx + * my bit-shifting isn't that 1337 + */ + + /** + *

The difference between the Windows epoch (1601-01-01 + * 00:00:00) and the Unix epoch (1970-01-01 00:00:00) in + * milliseconds: 11644473600000L. (Use your favorite spreadsheet + * program to verify the correctness of this value. By the way, + * did you notice that you can tell from the epochs which + * operating system is the modern one? :-))

+ */ + private static final long EPOCH_DIFF = 11644473600000L; + + /** + *

Converts a Windows FILETIME into a {@link Date}. The Windows + * FILETIME structure holds a date and time associated with a + * file. The structure identifies a 64-bit integer specifying the + * number of 100-nanosecond intervals which have passed since + * January 1, 1601. This 64-bit value is split into the two double + * words stored in the structure.

+ * + * @param high The higher double word of the FILETIME structure. + * @param low The lower double word of the FILETIME structure. + * @return The Windows FILETIME as a {@link Date}. + */ + public static Date filetimeToDate(final int high, final int low) { + final long filetime = ((long) high) << 32 | (low & 0xffffffffL); + //System.out.printf("0x%X\n", filetime); + final long ms_since_16010101 = filetime / (1000 * 10); + final long ms_since_19700101 = ms_since_16010101 - EPOCH_DIFF; + return new Date(ms_since_19700101); + } + + public static Calendar apptTimeToCalendar(int minutes) { + final long ms_since_16010101 = minutes * (60*1000L); + final long ms_since_19700101 = ms_since_16010101 - EPOCH_DIFF; + Calendar c = Calendar.getInstance(PSTTimeZone.utcTimeZone); + c.setTimeInMillis(ms_since_19700101); + return c; + } + + public static Calendar apptTimeToUTC(int minutes, PSTTimeZone tz) { + // Must convert minutes since 1/1/1601 in local time to UTC + // There's got to be a better way of doing this... + // First get a UTC calendar object that contains _local time_ + Calendar cUTC = apptTimeToCalendar(minutes); + if ( tz != null ) { + // Create an empty Calendar object with the required time zone + Calendar cLocal = Calendar.getInstance(tz.getSimpleTimeZone()); + cLocal.clear(); + + // Now transfer the local date/time from the UTC calendar object + // to the object that knows about the time zone... + cLocal.set(cUTC.get(Calendar.YEAR), + cUTC.get(Calendar.MONTH), + cUTC.get(Calendar.DATE), + cUTC.get(Calendar.HOUR_OF_DAY), + cUTC.get(Calendar.MINUTE), + cUTC.get(Calendar.SECOND)); + + // Get the true UTC from the local time calendar object. + // Drop any milliseconds, they won't be printed anyway! + long utcs = cLocal.getTimeInMillis() / 1000; + + // Finally, set the true UTC in the UTC calendar object + cUTC.setTimeInMillis(utcs * 1000); + } // else hope for the best! + + return cUTC; + } + + + + + public static int getCompEnc(int value) { + return compEnc[value]; + } + + + public static String decodeLZFU(byte[] data) throws PSTException { + + @SuppressWarnings("unused") + int compressedSize = (int)PSTUtils.convertLittleEndianBytesToLong(data, 0, 4); + int uncompressedSize = (int)PSTUtils.convertLittleEndianBytesToLong(data, 4, 8); + int compressionSig = (int)PSTUtils.convertLittleEndianBytesToLong(data, 8, 12); + @SuppressWarnings("unused") + int compressedCRC = (int)PSTUtils.convertLittleEndianBytesToLong(data, 12, 16); + + if (compressionSig == 0x75465a4c) { + // we are compressed... + byte[] output = new byte[uncompressedSize]; + int outputPosition = 0; + byte[] lzBuffer = new byte[4096]; + // preload our buffer. + try { + byte[] bytes = LZFU_HEADER.getBytes("US-ASCII"); + System.arraycopy(bytes, 0, lzBuffer, 0, LZFU_HEADER.length()); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + int bufferPosition = LZFU_HEADER.length(); + int currentDataPosition = 16; + + // next byte is the flags, + while (currentDataPosition < data.length - 2 && outputPosition < output.length) { + int flags = data[currentDataPosition++] & 0xFF; + for (int x = 0; x < 8 && outputPosition < output.length; x++) { + boolean isRef = ((flags & 1) == 1); + flags >>= 1; + if (isRef) { + // get the starting point for the buffer and the + // length to read + int refOffsetOrig = data[currentDataPosition++] & 0xFF; + int refSizeOrig = data[currentDataPosition++] & 0xFF; + int refOffset = (refOffsetOrig << 4) | (refSizeOrig >>> 4); + int refSize = (refSizeOrig & 0xF) + 2; + //refOffset &= 0xFFF; + try { + // copy the data from the buffer + int index = refOffset; + for (int y = 0; y < refSize && outputPosition < output.length; y++) { + output[outputPosition++] = lzBuffer[index]; + lzBuffer[bufferPosition] = lzBuffer[index]; + bufferPosition++; + bufferPosition %= 4096; + ++index; + index %= 4096; + } + } catch ( Exception e ) { + e.printStackTrace(); + } + + } else { + // copy the byte over + lzBuffer[bufferPosition] = data[currentDataPosition]; + bufferPosition++; + bufferPosition %= 4096; + output[outputPosition++] = data[currentDataPosition++]; + } + } + } + + if ( outputPosition != uncompressedSize ) { + throw new PSTException(String.format("Error decompressing RTF! Expected %d bytes, got %d bytes\n", uncompressedSize, outputPosition)); + } + return new String(output).trim(); + + } else if (compressionSig == 0x414c454d) { + // we are not compressed! + // just return the rest of the contents as a string + byte[] output = new byte[data.length-16]; + System.arraycopy(data, 16, output, 0, data.length-16); + return new String(output).trim(); + } + + return ""; + } + +} diff --git a/com/pff/PSTAppointmentException.java b/com/pff/exceptions/PSTAppointmentException.java similarity index 60% rename from com/pff/PSTAppointmentException.java rename to com/pff/exceptions/PSTAppointmentException.java index 9230070..8e88ba1 100644 --- a/com/pff/PSTAppointmentException.java +++ b/com/pff/exceptions/PSTAppointmentException.java @@ -32,12 +32,16 @@ * */ -package com.pff; +package com.pff.exceptions; import java.io.UnsupportedEncodingException; import java.util.Calendar; import java.util.Date; +import com.pff.PSTUtils; +import com.pff.objects.PSTAppointment; +import com.pff.objects.sub.PSTTimeZone; + /** * Class containing information on exceptions to a recurring appointment * @author Orin Eman @@ -49,9 +53,9 @@ public class PSTAppointmentException { // Access methods - return the value from the exception if // OverrideFlags say it's present, otherwise the value from the appointment. public String getSubject() { - if ( (OverrideFlags & 0x0001) != 0 ) { + if ( (overrideFlags & 0x0001) != 0 ) { try { - return new String(WideCharSubject, "UTF-16LE"); + return new String(wideCharSubject, "UTF-16LE"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } @@ -63,8 +67,8 @@ public String getSubject() { public int getMeetingType() { - if ( (OverrideFlags & 0x0002) != 0 ) { - return MeetingType; + if ( (overrideFlags & 0x0002) != 0 ) { + return meetingType; } return appt.getMeetingStatus(); @@ -72,7 +76,7 @@ public int getMeetingType() public int getReminderDelta() { - if ( (OverrideFlags & 0x0004) != 0 ) { + if ( (overrideFlags & 0x0004) != 0 ) { return ReminderDelta; } @@ -81,7 +85,7 @@ public int getReminderDelta() { public boolean getReminderSet() { - if ( (OverrideFlags & 0x0008) != 0 ) { + if ( (overrideFlags & 0x0008) != 0 ) { return ReminderSet; } @@ -90,9 +94,9 @@ public boolean getReminderSet() { public String getLocation() { - if ( (OverrideFlags & 0x0010) != 0 ) { + if ( (overrideFlags & 0x0010) != 0 ) { try { - return new String(WideCharLocation, "UTF-16LE"); + return new String(wideCharLocation, "UTF-16LE"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } @@ -103,8 +107,8 @@ public String getLocation() { public int getBusyStatus() { - if ( (OverrideFlags & 0x0020) != 0 ) { - return BusyStatus; + if ( (overrideFlags & 0x0020) != 0 ) { + return busyStatus; } return appt.getBusyStatus(); @@ -112,8 +116,8 @@ public int getBusyStatus() { public boolean getSubType() { - if ( (OverrideFlags & 0x0080) != 0 ) { - return SubType; + if ( (overrideFlags & 0x0080) != 0 ) { + return subType; } return appt.getSubType(); @@ -144,15 +148,15 @@ public Date getDTStamp() { } public int getStartDateTime() { - return StartDateTime; + return startDateTime; } public int getEndDateTime() { - return EndDateTime; + return endDateTime; } public int getOriginalStartDate() { - return OriginalStartDate; + return originalStartDate; } public int getAppointmentSequence(int def) { @@ -170,28 +174,23 @@ public int getImportance(int def) { } public byte[] getSubjectBytes() { - if ( (OverrideFlags & 0x0010) != 0 ) { + if ( (overrideFlags & 0x0010) != 0 ) { return Subject; } - return null; } public byte[] getLocationBytes() { - if ( (OverrideFlags & 0x0010) != 0 ) { - return Location; + if ( (overrideFlags & 0x0010) != 0 ) { + return location; } - return null; } public boolean attachmentsPresent() { - if ( (OverrideFlags & 0x0040) != 0 && - Attachment == 0x00000001 ) - { + if ( (overrideFlags & 0x0040) != 0 && attachment == 0x00000001 ) { return true; } - return false; } @@ -207,109 +206,106 @@ public PSTAppointment getEmbeddedMessage() { return embeddedMessage; } - PSTAppointmentException(byte[] recurrencePattern, - int offset, - int writerVersion2, - PSTAppointment appt) { + public PSTAppointmentException(byte[] recurrencePattern, int offset, int writerVersion2, PSTAppointment appt) { this.writerVersion2 = writerVersion2; int initialOffset = offset; this.appt = appt; embeddedMessage = null; - StartDateTime = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + startDateTime = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - EndDateTime = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + endDateTime = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - OriginalStartDate = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + originalStartDate = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - OverrideFlags = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); + overrideFlags = (short)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); offset += 2; - if ( (OverrideFlags & ARO_SUBJECT) != 0 ) { + if ( (overrideFlags & ARO_SUBJECT) != 0 ) { //@SuppressWarnings("unused") //short SubjectLength = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); offset += 2; - short SubjectLength2 = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); + short SubjectLength2 = (short)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); offset += 2; Subject = new byte[SubjectLength2]; System.arraycopy(recurrencePattern, offset, Subject, 0, SubjectLength2); offset += SubjectLength2; } - if ( (OverrideFlags & ARO_MEETINGTYPE) != 0 ) { - MeetingType = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + if ( (overrideFlags & ARO_MEETINGTYPE) != 0 ) { + meetingType = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; } - if ( (OverrideFlags & ARO_REMINDERDELTA) != 0 ) { - ReminderDelta = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + if ( (overrideFlags & ARO_REMINDERDELTA) != 0 ) { + ReminderDelta = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; } - if ( (OverrideFlags & ARO_REMINDER) != 0 ) { - ReminderSet = ((int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4) != 0); + if ( (overrideFlags & ARO_REMINDER) != 0 ) { + ReminderSet = ((int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4) != 0); offset += 4; } - if ( (OverrideFlags & ARO_LOCATION) != 0 ) { + if ( (overrideFlags & ARO_LOCATION) != 0 ) { //@SuppressWarnings("unused") //short LocationLength = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); offset += 2; - short LocationLength2 = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); + short LocationLength2 = (short)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); offset += 2; - Location = new byte[LocationLength2]; - System.arraycopy(recurrencePattern, offset, Location, 0, LocationLength2); + location = new byte[LocationLength2]; + System.arraycopy(recurrencePattern, offset, location, 0, LocationLength2); offset += LocationLength2; } - if ( (OverrideFlags & ARO_BUSYSTATUS) != 0 ) { - BusyStatus = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + if ( (overrideFlags & ARO_BUSYSTATUS) != 0 ) { + busyStatus = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; } - if ( (OverrideFlags & ARO_ATTACHMENT) != 0 ) { - Attachment = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + if ( (overrideFlags & ARO_ATTACHMENT) != 0 ) { + attachment = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; } - if ( (OverrideFlags & ARO_SUBTYPE) != 0 ) { - SubType = ((int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4) != 0); + if ( (overrideFlags & ARO_SUBTYPE) != 0 ) { + subType = ((int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4) != 0); offset += 4; } length = offset - initialOffset; } - void ExtendedException(byte[] recurrencePattern, int offset) { + public void buildExtendedException(byte[] recurrencePattern, int offset) { int initialOffset = offset; if ( writerVersion2 >= 0x00003009 ) { - int ChangeHighlightSize = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + int ChangeHighlightSize = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - ChangeHighlightValue = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + changeHighlightValue = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += ChangeHighlightSize; } - int ReservedBlockEESize = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + int ReservedBlockEESize = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4 + ReservedBlockEESize; // See http://msdn.microsoft.com/en-us/library/cc979209(office.12).aspx - if ( (OverrideFlags & (ARO_SUBJECT|ARO_LOCATION)) != 0 ) { + if ( (overrideFlags & (ARO_SUBJECT|ARO_LOCATION)) != 0 ) { // Same as regular Exception structure? - StartDateTime = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + startDateTime = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - EndDateTime = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + endDateTime = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - OriginalStartDate = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + originalStartDate = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; } - if ( (OverrideFlags & ARO_SUBJECT) != 0 ) { - WideCharSubjectLength = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); + if ( (overrideFlags & ARO_SUBJECT) != 0 ) { + wideCharSubjectLength = (short)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); offset += 2; - WideCharSubject = new byte[WideCharSubjectLength * 2]; - System.arraycopy(recurrencePattern, offset, WideCharSubject, 0, WideCharSubject.length); - offset += WideCharSubject.length; + wideCharSubject = new byte[wideCharSubjectLength * 2]; + System.arraycopy(recurrencePattern, offset, wideCharSubject, 0, wideCharSubject.length); + offset += wideCharSubject.length; /* try { String subject = new String(WideCharSubject, "UTF-16LE"); @@ -320,47 +316,47 @@ void ExtendedException(byte[] recurrencePattern, int offset) { /**/ } - if ( (OverrideFlags & ARO_LOCATION) != 0 ) { - WideCharLocationLength = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); + if ( (overrideFlags & ARO_LOCATION) != 0 ) { + wideCharLocationLength = (short)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); offset += 2; - WideCharLocation = new byte[WideCharLocationLength*2]; - System.arraycopy(recurrencePattern, offset, WideCharLocation, 0, WideCharLocation.length); - offset += WideCharLocation.length; + wideCharLocation = new byte[wideCharLocationLength*2]; + System.arraycopy(recurrencePattern, offset, wideCharLocation, 0, wideCharLocation.length); + offset += wideCharLocation.length; } // See http://msdn.microsoft.com/en-us/library/cc979209(office.12).aspx - if ( (OverrideFlags & (ARO_SUBJECT|ARO_LOCATION)) != 0 ) { - ReservedBlockEESize = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + if ( (overrideFlags & (ARO_SUBJECT|ARO_LOCATION)) != 0 ) { + ReservedBlockEESize = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4 + ReservedBlockEESize; } extendedLength = offset - initialOffset; } - void setEmbeddedMessage(PSTAppointment embeddedMessage) { + public void setEmbeddedMessage(PSTAppointment embeddedMessage) { this.embeddedMessage = embeddedMessage; } private int writerVersion2; - private int StartDateTime; - private int EndDateTime; - private int OriginalStartDate; - private short OverrideFlags; + private int startDateTime; + private int endDateTime; + private int originalStartDate; + private short overrideFlags; private byte[] Subject = null; - private int MeetingType; + private int meetingType; private int ReminderDelta; private boolean ReminderSet; - private byte[] Location = null; - private int BusyStatus; - private int Attachment; - private boolean SubType; + private byte[] location = null; + private int busyStatus; + private int attachment; + private boolean subType; // private int AppointmentColor; // Reserved - don't read from the PST file @SuppressWarnings("unused") - private int ChangeHighlightValue; - private int WideCharSubjectLength = 0; - private byte[] WideCharSubject = null; - private int WideCharLocationLength = 0; - private byte[] WideCharLocation = null; + private int changeHighlightValue; + private int wideCharSubjectLength = 0; + private byte[] wideCharSubject = null; + private int wideCharLocationLength = 0; + private byte[] wideCharLocation = null; private PSTAppointment embeddedMessage = null; private PSTAppointment appt; private int length; @@ -368,12 +364,12 @@ void setEmbeddedMessage(PSTAppointment embeddedMessage) { // Length of this ExceptionInfo structure in the PST file - int getLength() { + public int getLength() { return length; } // Length of this ExtendedException structure in the PST file - int getExtendedLength() { + public int getExtendedLength() { return extendedLength; } diff --git a/com/pff/PSTException.java b/com/pff/exceptions/PSTException.java similarity index 93% rename from com/pff/PSTException.java rename to com/pff/exceptions/PSTException.java index 36d570e..b573ced 100644 --- a/com/pff/PSTException.java +++ b/com/pff/exceptions/PSTException.java @@ -31,7 +31,7 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.exceptions; /** * Simple exception for PST File related errors @@ -44,10 +44,10 @@ public class PSTException extends Exception */ private static final long serialVersionUID = 4284698344354718143L; - PSTException(String error) { + public PSTException(String error) { super(error); } - PSTException(String error, Exception orig) { + public PSTException(String error, Exception orig) { super(error, orig); } } diff --git a/com/pff/PSTActivity.java b/com/pff/objects/PSTActivity.java similarity index 80% rename from com/pff/PSTActivity.java rename to com/pff/objects/PSTActivity.java index d4cae3d..460bf2a 100644 --- a/com/pff/PSTActivity.java +++ b/com/pff/objects/PSTActivity.java @@ -31,11 +31,17 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects; import java.io.IOException; -import java.util.HashMap; import java.util.Date; +import java.util.HashMap; + +import com.pff.exceptions.PSTException; +import com.pff.parsing.DescriptorIndexNode; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.tables.PSTTableBC; +import com.pff.source.PSTSource; /** * PSTActivity represents Journal entries @@ -49,7 +55,7 @@ public class PSTActivity extends PSTMessage { * @throws PSTException * @throws IOException */ - public PSTActivity(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) + public PSTActivity(PSTSource theFile, DescriptorIndexNode descriptorIndexNode) throws PSTException, IOException { super(theFile, descriptorIndexNode); } @@ -60,7 +66,7 @@ public PSTActivity(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) * @param table * @param localDescriptorItems */ - public PSTActivity(PSTFile theFile, DescriptorIndexNode folderIndexNode, + public PSTActivity(PSTSource theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { super(theFile, folderIndexNode, table, localDescriptorItems); @@ -70,61 +76,61 @@ public PSTActivity(PSTFile theFile, DescriptorIndexNode folderIndexNode, * Type */ public String getLogType() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008700, PSTFile.PSETID_Log)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008700, PSTSource.PSETID_Log)); } /** * Start */ public Date getLogStart() { - return getDateItem(pstFile.getNameToIdMapItem(0x00008706, PSTFile.PSETID_Log)); + return getDateItem(pstFile.getNameToIdMapItem(0x00008706, PSTSource.PSETID_Log)); } /** * Duration */ public int getLogDuration() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008707, PSTFile.PSETID_Log)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008707, PSTSource.PSETID_Log)); } /** * End */ public Date getLogEnd() { - return getDateItem(pstFile.getNameToIdMapItem(0x00008708, PSTFile.PSETID_Log)); + return getDateItem(pstFile.getNameToIdMapItem(0x00008708, PSTSource.PSETID_Log)); } /** * LogFlags */ public int getLogFlags() { - return getIntItem(pstFile.getNameToIdMapItem(0x0000870c, PSTFile.PSETID_Log)); + return getIntItem(pstFile.getNameToIdMapItem(0x0000870c, PSTSource.PSETID_Log)); } /** * DocPrinted */ public boolean isDocumentPrinted() { - return (getBooleanItem(pstFile.getNameToIdMapItem(0x0000870e, PSTFile.PSETID_Log))); + return (getBooleanItem(pstFile.getNameToIdMapItem(0x0000870e, PSTSource.PSETID_Log))); } /** * DocSaved */ public boolean isDocumentSaved() { - return (getBooleanItem(pstFile.getNameToIdMapItem(0x0000870f, PSTFile.PSETID_Log))); + return (getBooleanItem(pstFile.getNameToIdMapItem(0x0000870f, PSTSource.PSETID_Log))); } /** * DocRouted */ public boolean isDocumentRouted() { - return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008710, PSTFile.PSETID_Log))); + return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008710, PSTSource.PSETID_Log))); } /** * DocPosted */ public boolean isDocumentPosted() { - return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008711, PSTFile.PSETID_Log))); + return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008711, PSTSource.PSETID_Log))); } /** * Type Description */ public String getLogTypeDesc() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008712, PSTFile.PSETID_Log)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008712, PSTSource.PSETID_Log)); } public String toString() { diff --git a/com/pff/PSTAppointment.java b/com/pff/objects/PSTAppointment.java similarity index 62% rename from com/pff/PSTAppointment.java rename to com/pff/objects/PSTAppointment.java index b82216e..df69cce 100644 --- a/com/pff/PSTAppointment.java +++ b/com/pff/objects/PSTAppointment.java @@ -31,59 +31,67 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects; import java.io.IOException; import java.util.Date; import java.util.HashMap; +import com.pff.exceptions.PSTException; +import com.pff.objects.sub.PSTGlobalObjectId; +import com.pff.objects.sub.PSTTimeZone; +import com.pff.parsing.DescriptorIndexNode; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.tables.PSTTableBC; +import com.pff.source.PSTSource; + /** * PSTAppointment is for Calendar items * @author Richard Johnson */ public class PSTAppointment extends PSTMessage { - PSTAppointment(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) + public PSTAppointment(PSTSource theFile, DescriptorIndexNode descriptorIndexNode) throws PSTException, IOException { super(theFile, descriptorIndexNode); } - PSTAppointment(PSTFile theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) + public PSTAppointment(PSTSource theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { super(theFile, folderIndexNode, table, localDescriptorItems); } public boolean getSendAsICAL() { - return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008200, PSTFile.PSETID_Appointment))); + return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008200, PSTSource.PSETID_Appointment))); } public int getBusyStatus() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008205, PSTFile.PSETID_Appointment)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008205, PSTSource.PSETID_Appointment)); } public boolean getShowAsBusy() { return getBusyStatus() == 2; } public String getLocation() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008208, PSTFile.PSETID_Appointment)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008208, PSTSource.PSETID_Appointment)); } public Date getStartTime() { - return getDateItem(pstFile.getNameToIdMapItem(0x0000820d, PSTFile.PSETID_Appointment)); + return getDateItem(pstFile.getNameToIdMapItem(0x0000820d, PSTSource.PSETID_Appointment)); } public PSTTimeZone getStartTimeZone() { - return getTimeZoneItem(pstFile.getNameToIdMapItem(0x0000825e, PSTFile.PSETID_Appointment)); + return getTimeZoneItem(pstFile.getNameToIdMapItem(0x0000825e, PSTSource.PSETID_Appointment)); } public Date getEndTime() { - return getDateItem(pstFile.getNameToIdMapItem(0x0000820e, PSTFile.PSETID_Appointment)); + return getDateItem(pstFile.getNameToIdMapItem(0x0000820e, PSTSource.PSETID_Appointment)); } public PSTTimeZone getEndTimeZone() { - return getTimeZoneItem(pstFile.getNameToIdMapItem(0x0000825f, PSTFile.PSETID_Appointment)); + return getTimeZoneItem(pstFile.getNameToIdMapItem(0x0000825f, PSTSource.PSETID_Appointment)); } public PSTTimeZone getRecurrenceTimeZone() { - String desc = getStringItem(pstFile.getNameToIdMapItem(0x00008234, PSTFile.PSETID_Appointment)); + String desc = getStringItem(pstFile.getNameToIdMapItem(0x00008234, PSTSource.PSETID_Appointment)); if ( desc!= null && desc.length() != 0 ) { - byte[] tzData = getBinaryItem(pstFile.getNameToIdMapItem(0x00008233, PSTFile.PSETID_Appointment)); + byte[] tzData = getBinaryItem(pstFile.getNameToIdMapItem(0x00008233, PSTSource.PSETID_Appointment)); if ( tzData != null && tzData.length != 0 ) { return new PSTTimeZone(desc, tzData); } @@ -91,103 +99,110 @@ public PSTTimeZone getRecurrenceTimeZone() { return null; } public int getDuration() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008213, PSTFile.PSETID_Appointment)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008213, PSTSource.PSETID_Appointment)); } public int getColor() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008214, PSTFile.PSETID_Appointment)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008214, PSTSource.PSETID_Appointment)); } public boolean getSubType() { - return (getIntItem(pstFile.getNameToIdMapItem(0x00008215, PSTFile.PSETID_Appointment)) != 0); + return (getIntItem(pstFile.getNameToIdMapItem(0x00008215, PSTSource.PSETID_Appointment)) != 0); } public int getMeetingStatus() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008217, PSTFile.PSETID_Appointment)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008217, PSTSource.PSETID_Appointment)); } public int getResponseStatus() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008218, PSTFile.PSETID_Appointment)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008218, PSTSource.PSETID_Appointment)); } public boolean isRecurring() { - return getBooleanItem(pstFile.getNameToIdMapItem(0x00008223, PSTFile.PSETID_Appointment)); + return getBooleanItem(pstFile.getNameToIdMapItem(0x00008223, PSTSource.PSETID_Appointment)); } public Date getRecurrenceBase() { - return getDateItem(pstFile.getNameToIdMapItem(0x00008228, PSTFile.PSETID_Appointment)); + return getDateItem(pstFile.getNameToIdMapItem(0x00008228, PSTSource.PSETID_Appointment)); } public int getRecurrenceType() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008231, PSTFile.PSETID_Appointment)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008231, PSTSource.PSETID_Appointment)); } public String getRecurrencePattern() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008232, PSTFile.PSETID_Appointment)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008232, PSTSource.PSETID_Appointment)); } public byte[] getRecurrenceStructure() { - return getBinaryItem(pstFile.getNameToIdMapItem(0x00008216, PSTFile.PSETID_Appointment)); + return getBinaryItem(pstFile.getNameToIdMapItem(0x00008216, PSTSource.PSETID_Appointment)); } public byte[] getTimezone() { - return getBinaryItem(pstFile.getNameToIdMapItem(0x00008233, PSTFile.PSETID_Appointment)); + return getBinaryItem(pstFile.getNameToIdMapItem(0x00008233, PSTSource.PSETID_Appointment)); } public String getAllAttendees() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008238, PSTFile.PSETID_Appointment)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008238, PSTSource.PSETID_Appointment)); } public String getToAttendees() { - return getStringItem(pstFile.getNameToIdMapItem(0x0000823b, PSTFile.PSETID_Appointment)); + return getStringItem(pstFile.getNameToIdMapItem(0x0000823b, PSTSource.PSETID_Appointment)); } public String getCCAttendees() { - return getStringItem(pstFile.getNameToIdMapItem(0x0000823c, PSTFile.PSETID_Appointment)); + return getStringItem(pstFile.getNameToIdMapItem(0x0000823c, PSTSource.PSETID_Appointment)); } public int getAppointmentSequence() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008201, PSTFile.PSETID_Appointment)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008201, PSTSource.PSETID_Appointment)); } // online meeting properties public boolean isOnlineMeeting() { - return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008240, PSTFile.PSETID_Appointment))); + return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008240, PSTSource.PSETID_Appointment))); } public int getNetMeetingType() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008241, PSTFile.PSETID_Appointment)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008241, PSTSource.PSETID_Appointment)); } public String getNetMeetingServer() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008242, PSTFile.PSETID_Appointment)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008242, PSTSource.PSETID_Appointment)); } public String getNetMeetingOrganizerAlias() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008243, PSTFile.PSETID_Appointment)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008243, PSTSource.PSETID_Appointment)); } public boolean getNetMeetingAutostart() { - return (getIntItem(pstFile.getNameToIdMapItem(0x00008245, PSTFile.PSETID_Appointment)) != 0); + return (getIntItem(pstFile.getNameToIdMapItem(0x00008245, PSTSource.PSETID_Appointment)) != 0); } public boolean getConferenceServerAllowExternal() { - return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008246, PSTFile.PSETID_Appointment))); + return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008246, PSTSource.PSETID_Appointment))); } public String getNetMeetingDocumentPathName() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008247, PSTFile.PSETID_Appointment)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008247, PSTSource.PSETID_Appointment)); } public String getNetShowURL() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008248, PSTFile.PSETID_Appointment)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008248, PSTSource.PSETID_Appointment)); } public Date getAttendeeCriticalChange() { - return getDateItem(pstFile.getNameToIdMapItem(0x00000001, PSTFile.PSETID_Meeting)); + return getDateItem(pstFile.getNameToIdMapItem(0x00000001, PSTSource.PSETID_Meeting)); } public Date getOwnerCriticalChange() { - return getDateItem(pstFile.getNameToIdMapItem(0x0000001a, PSTFile.PSETID_Meeting)); + return getDateItem(pstFile.getNameToIdMapItem(0x0000001a, PSTSource.PSETID_Meeting)); } public String getConferenceServerPassword() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008249, PSTFile.PSETID_Appointment)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008249, PSTSource.PSETID_Appointment)); } public boolean getAppointmentCounterProposal() { - return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008257, PSTFile.PSETID_Appointment))); + return (getBooleanItem(pstFile.getNameToIdMapItem(0x00008257, PSTSource.PSETID_Appointment))); } public boolean isSilent() { - return (getBooleanItem(pstFile.getNameToIdMapItem(0x00000004, PSTFile.PSETID_Meeting))); + return (getBooleanItem(pstFile.getNameToIdMapItem(0x00000004, PSTSource.PSETID_Meeting))); } public String getRequiredAttendees() { - return getStringItem(this.pstFile.getNameToIdMapItem(0x00000006, PSTFile.PSETID_Meeting)); + return getStringItem(this.pstFile.getNameToIdMapItem(0x00000006, PSTSource.PSETID_Meeting)); } public int getLocaleId() { return getIntItem(0x3ff1); } - public byte[] getGlobalObjectId() { - return getBinaryItem(pstFile.getNameToIdMapItem(0x00000003, PSTFile.PSETID_Meeting)); + /*public byte[] getGlobalObjectId() { + return getBinaryItem(pstFile.getNameToIdMapItem(0x00000003, PSTSource.PSETID_Meeting)); + }*/ + public PSTGlobalObjectId getGlobalObjectId() { + return new PSTGlobalObjectId(getBinaryItem(pstFile.getNameToIdMapItem(0x00000003, PSTSource.PSETID_Meeting))); + } + + public PSTGlobalObjectId getCleanGlobalObjectId() { + return new PSTGlobalObjectId(getBinaryItem(pstFile.getNameToIdMapItem(0x00000023, PSTSource.PSETID_Meeting))); } } diff --git a/com/pff/PSTAttachment.java b/com/pff/objects/PSTAttachment.java similarity index 92% rename from com/pff/PSTAttachment.java rename to com/pff/objects/PSTAttachment.java index 2b2f1db..3e03643 100644 --- a/com/pff/PSTAttachment.java +++ b/com/pff/objects/PSTAttachment.java @@ -31,11 +31,19 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects; import java.io.*; import java.util.*; +import com.pff.PSTUtils; +import com.pff.exceptions.PSTException; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.PSTNodeInputStream; +import com.pff.parsing.tables.PSTTableBC; +import com.pff.parsing.tables.PSTTableBCItem; +import com.pff.source.PSTSource; + /** * Class containing attachment information @@ -43,7 +51,7 @@ */ public class PSTAttachment extends PSTObject { - PSTAttachment(PSTFile theFile, PSTTableBC table, HashMap localDescriptorItems) { + PSTAttachment(PSTSource theFile, PSTTableBC table, HashMap localDescriptorItems) { super(theFile, null, table, localDescriptorItems); } @@ -74,11 +82,11 @@ public PSTMessage getEmbeddedPSTMessage() throw new PSTException("External reference in getEmbeddedPSTMessage()!\n"); } } else if ( item.entryValueType == 0x000D ) { - int descriptorItem = (int)PSTObject.convertLittleEndianBytesToLong(item.data, 0, 4); + int descriptorItem = (int)PSTUtils.convertLittleEndianBytesToLong(item.data, 0, 4); //PSTObject.printHexFormatted(item.data, true); PSTDescriptorItem descriptorItemNested = this.localDescriptorItems.get(descriptorItem); in = new PSTNodeInputStream(this.pstFile, descriptorItemNested); - this.localDescriptorItems.putAll(pstFile.getPSTDescriptorItems(descriptorItemNested.subNodeOffsetIndexIdentifier)); + this.localDescriptorItems.putAll(pstFile.getPSTDescriptorItems(descriptorItemNested.getSubNodeOffsetIndexIdentifier())); /* if ( descriptorItemNested != null ) { try { diff --git a/com/pff/PSTContact.java b/com/pff/objects/PSTContact.java similarity index 96% rename from com/pff/PSTContact.java rename to com/pff/objects/PSTContact.java index 7a1bd10..a3170cd 100644 --- a/com/pff/PSTContact.java +++ b/com/pff/objects/PSTContact.java @@ -31,12 +31,18 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects; import java.io.IOException; import java.util.Date; import java.util.HashMap; +import com.pff.exceptions.PSTException; +import com.pff.parsing.DescriptorIndexNode; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.tables.PSTTableBC; +import com.pff.source.PSTSource; + /** * Class for Contacts @@ -50,7 +56,7 @@ public class PSTContact extends PSTMessage { * @throws PSTException * @throws IOException */ - public PSTContact(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) + public PSTContact(PSTSource theFile, DescriptorIndexNode descriptorIndexNode) throws PSTException, IOException { super(theFile, descriptorIndexNode); } @@ -61,7 +67,7 @@ public PSTContact(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) * @param table * @param localDescriptorItems */ - public PSTContact(PSTFile theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { + public PSTContact(PSTSource theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { super(theFile, folderIndexNode, table, localDescriptorItems); } @@ -416,7 +422,7 @@ public String getNote() { } String getNamedStringItem(int key) { - int id = pstFile.getNameToIdMapItem(key, PSTFile.PSETID_Address); + int id = pstFile.getNameToIdMapItem(key, PSTSource.PSETID_Address); if ( id != -1 ) { return getStringItem(id); } @@ -548,7 +554,7 @@ public String getOtherAddress() { * Selected Mailing Address */ public int getPostalAddressId() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008022, PSTFile.PSETID_Address)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008022, PSTSource.PSETID_Address)); } /** diff --git a/com/pff/PSTFolder.java b/com/pff/objects/PSTFolder.java similarity index 92% rename from com/pff/PSTFolder.java rename to com/pff/objects/PSTFolder.java index d3fc0a4..68d00ff 100644 --- a/com/pff/PSTFolder.java +++ b/com/pff/objects/PSTFolder.java @@ -31,9 +31,24 @@ * along with java-libpst. If not, see . * */ -package com.pff; -import java.io.*; -import java.util.*; +package com.pff.objects; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + + +import com.pff.exceptions.PSTException; +import com.pff.parsing.DescriptorIndexNode; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.PSTNodeInputStream; +import com.pff.parsing.tables.PSTTable7C; +import com.pff.parsing.tables.PSTTable7CItem; +import com.pff.parsing.tables.PSTTableBC; +import com.pff.source.PSTSource; /** @@ -51,7 +66,7 @@ public class PSTFolder extends PSTObject { * @throws PSTException * @throws IOException */ - PSTFolder(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) + public PSTFolder(PSTSource theFile, DescriptorIndexNode descriptorIndexNode) throws PSTException, IOException { super(theFile, descriptorIndexNode); @@ -64,7 +79,7 @@ public class PSTFolder extends PSTObject { * @param folderIndexNode * @param table */ - PSTFolder(PSTFile theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { + PSTFolder(PSTSource theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { super(theFile, folderIndexNode, table, localDescriptorItems); } @@ -75,11 +90,11 @@ public class PSTFolder extends PSTObject { * @throws PSTException * @throws IOException */ - public Vector getSubFolders() + public ArrayList getSubFolders() throws PSTException, IOException { initSubfoldersTable(); - Vector output = new Vector(); + ArrayList output = new ArrayList(); if (this.hasSubfolders()) { try { List> itemMapSet = subfoldersTable.getItems(); @@ -126,7 +141,7 @@ private void initSubfoldersTable() * internal vars for the tracking of things.. */ private int currentEmailIndex = 0; - private LinkedHashSet otherItems = null; + //private LinkedHashSet otherItems = null; private PSTTable7C emailsTable = null; private LinkedList fallbackEmailsTable = null; @@ -198,12 +213,12 @@ private void initEmailsTable() * @throws PSTException * @throws IOException */ - public Vector getChildren(int numberToReturn) + public ArrayList getChildren(int numberToReturn) throws PSTException, IOException { initEmailsTable(); - Vector output = new Vector(); + ArrayList output = new ArrayList(); if (emailsTable != null) { List> rows = this.emailsTable.getItems(currentEmailIndex, numberToReturn); diff --git a/com/pff/PSTMessage.java b/com/pff/objects/PSTMessage.java similarity index 91% rename from com/pff/PSTMessage.java rename to com/pff/objects/PSTMessage.java index 2644276..4cf58e9 100644 --- a/com/pff/PSTMessage.java +++ b/com/pff/objects/PSTMessage.java @@ -31,12 +31,25 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects; import java.io.IOException; import java.util.Date; import java.util.HashMap; +import com.pff.PSTUtils; +import com.pff.exceptions.PSTException; +import com.pff.objects.sub.PSTConversationIndex; +import com.pff.objects.sub.PSTRecipient; +import com.pff.parsing.DescriptorIndexNode; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.PSTNodeInputStream; +import com.pff.parsing.tables.PSTTable7C; +import com.pff.parsing.tables.PSTTable7CItem; +import com.pff.parsing.tables.PSTTableBC; +import com.pff.parsing.tables.PSTTableBCItem; +import com.pff.source.PSTSource; + /** * PST Message contains functions that are common across most MAPI objects. * Note that many of these functions may not be applicable for the item in question, @@ -51,13 +64,13 @@ public class PSTMessage extends PSTObject { public static final int IMPORTANCE_NORMAL = 1; public static final int IMPORTANCE_HIGH = 2; - PSTMessage(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) + PSTMessage(PSTSource theFile, DescriptorIndexNode descriptorIndexNode) throws PSTException, IOException { super(theFile, descriptorIndexNode); } - PSTMessage(PSTFile theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) + PSTMessage(PSTSource theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { super(theFile, folderIndexNode, table, localDescriptorItems); } @@ -71,12 +84,12 @@ public String getRTFBody() // is it a reference? PSTTableBCItem item = this.items.get(0x1009); if (item.data.length > 0) { - return (LZFu.decode(item.data)); + return (PSTUtils.decodeLZFU(item.data)); } int ref = item.entryValueReference; PSTDescriptorItem descItem = this.localDescriptorItems.get(ref); if ( descItem != null ) { - return LZFu.decode(descItem.getData()); + return PSTUtils.decodeLZFU(descItem.getData()); } } @@ -317,8 +330,8 @@ public boolean getMessageCcMe () { /** * Message addressed to me ASCII or Unicode string */ - public String getMessageRecipMe () { - return this.getStringItem(0x0059); + public boolean getMessageRecipMe () { + return this.getIntItem(0x0059) != 0; } /** * Response requested Boolean @@ -585,6 +598,10 @@ public Date getMessageDeliveryTime() { // return (this.getIntItem(0x0e17) & 0x2000) != 0; // } + public int getNativeBodyType() { + return this.getIntItem(0x1016); + } + /** * Message content properties */ @@ -599,7 +616,7 @@ public String getBody() { cpItem = this.items.get(0x3FDE); // PidTagInternetCodepage } if (cpItem != null) { - cp = PSTFile.getInternetCodePageCharset(cpItem.entryValueReference); + cp = PSTSource.getInternetCodePageCharset(cpItem.entryValueReference); } return this.getStringItem(0x1000, 0, cp); } @@ -649,7 +666,7 @@ public String getBodyHTML() { cpItem = this.items.get(0x3FFD); // PidTagMessageCodepage } if (cpItem != null) { - cp = PSTFile.getInternetCodePageCharset(cpItem.entryValueReference); + cp = PSTSource.getInternetCodePageCharset(cpItem.entryValueReference); } return this.getStringItem(0x1013, 0, cp); } @@ -759,8 +776,8 @@ private void processRecipients() { PSTDescriptorItem item = this.localDescriptorItems.get(recipientTableKey); HashMap descriptorItems = null; - if (item.subNodeOffsetIndexIdentifier > 0) { - descriptorItems =pstFile.getPSTDescriptorItems(item.subNodeOffsetIndexIdentifier); + if (item.getSubNodeOffsetIndexIdentifier() > 0) { + descriptorItems =pstFile.getPSTDescriptorItems(item.getSubNodeOffsetIndexIdentifier()); } recipientTable = new PSTTable7C(new PSTNodeInputStream(pstFile, item), descriptorItems); } @@ -811,8 +828,8 @@ private void processAttachments() { PSTDescriptorItem item = this.localDescriptorItems.get(attachmentTableKey); HashMap descriptorItems = null; - if (item.subNodeOffsetIndexIdentifier > 0) { - descriptorItems =pstFile.getPSTDescriptorItems(item.subNodeOffsetIndexIdentifier); + if (item.getSubNodeOffsetIndexIdentifier() > 0) { + descriptorItems =pstFile.getPSTDescriptorItems(item.getSubNodeOffsetIndexIdentifier()); } attachmentTable = new PSTTable7C(new PSTNodeInputStream(pstFile, item), descriptorItems); } @@ -822,13 +839,13 @@ private void processAttachments() * Start date Filetime */ public Date getTaskStartDate() { - return getDateItem(pstFile.getNameToIdMapItem(0x00008104, PSTFile.PSETID_Task)); + return getDateItem(pstFile.getNameToIdMapItem(0x00008104, PSTSource.PSETID_Task)); } /** * Due date Filetime */ public Date getTaskDueDate() { - return getDateItem(pstFile.getNameToIdMapItem(0x00008105, PSTFile.PSETID_Task)); + return getDateItem(pstFile.getNameToIdMapItem(0x00008105, PSTSource.PSETID_Task)); } /** @@ -836,11 +853,11 @@ public Date getTaskDueDate() { * @return */ public boolean getReminderSet() { - return getBooleanItem(pstFile.getNameToIdMapItem(0x00008503, PSTFile.PSETID_Common)); + return getBooleanItem(pstFile.getNameToIdMapItem(0x00008503, PSTSource.PSETID_Common)); } public int getReminderDelta() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008501, PSTFile.PSETID_Common)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008501, PSTSource.PSETID_Common)); } /** @@ -871,7 +888,7 @@ public String[] getColorCategories() categories = new String[categoryCount]; int[] offsets = new int[categoryCount]; for (int x = 0; x < categoryCount; x++) { - offsets[x] = (int)PSTObject.convertBigEndianBytesToLong(item.data, (x*4)+1, (x+1)*4+1); + offsets[x] = (int)PSTUtils.convertBigEndianBytesToLong(item.data, (x*4)+1, (x+1)*4+1); } for (int x = 0; x < offsets.length -1; x++) { int start = offsets[x]; @@ -958,8 +975,8 @@ public PSTAttachment getAttachment(int attachmentNumber) // note that all the information that was in the c7 table is repeated in the eb table in attachment data. // so no need to pass it... HashMap attachmentDescriptorItems = new HashMap(); - if (descriptorItem.subNodeOffsetIndexIdentifier > 0) { - attachmentDescriptorItems = pstFile.getPSTDescriptorItems(descriptorItem.subNodeOffsetIndexIdentifier); + if (descriptorItem.getSubNodeOffsetIndexIdentifier() > 0) { + attachmentDescriptorItems = pstFile.getPSTDescriptorItems(descriptorItem.getSubNodeOffsetIndexIdentifier()); } return new PSTAttachment(this.pstFile, attachmentDetailsTable, attachmentDescriptorItems); } @@ -1014,4 +1031,16 @@ public String toString() { this.localDescriptorItems; } + + public byte[] getConversationId() { + return getBinaryItem(0x3013); + } + + public PSTConversationIndex getConversationIndex() { + return new PSTConversationIndex(getBinaryItem(0x0071)); + } + + public boolean isConversationIndexTracking() { + return getBooleanItem(0x3016, false); + } } diff --git a/com/pff/PSTMessageStore.java b/com/pff/objects/PSTMessageStore.java similarity index 79% rename from com/pff/PSTMessageStore.java rename to com/pff/objects/PSTMessageStore.java index 553593f..b231aab 100644 --- a/com/pff/PSTMessageStore.java +++ b/com/pff/objects/PSTMessageStore.java @@ -31,11 +31,17 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects; import java.io.*; import java.util.*; +import com.pff.PSTUtils; +import com.pff.exceptions.PSTException; +import com.pff.parsing.DescriptorIndexNode; +import com.pff.parsing.tables.PSTTableBCItem; +import com.pff.source.PSTSource; + /** * Object that represents the message store. @@ -44,7 +50,7 @@ */ public class PSTMessageStore extends PSTObject { - PSTMessageStore(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) + public PSTMessageStore(PSTSource theFile, DescriptorIndexNode descriptorIndexNode) throws PSTException, IOException { super(theFile, descriptorIndexNode); @@ -60,10 +66,10 @@ public UUID getTagRecordKeyAsUUID() { PSTTableBCItem item = this.items.get(guidEntryType); int offset = 0; byte[] bytes = item.data; - long mostSigBits = (PSTObject.convertLittleEndianBytesToLong(bytes, offset, offset+4) << 32) | - (PSTObject.convertLittleEndianBytesToLong(bytes, offset+4, offset+6) << 16) | - PSTObject.convertLittleEndianBytesToLong(bytes, offset+6, offset+8); - long leastSigBits = PSTObject.convertBigEndianBytesToLong(bytes, offset+8, offset+16); + long mostSigBits = (PSTUtils.convertLittleEndianBytesToLong(bytes, offset, offset+4) << 32) | + (PSTUtils.convertLittleEndianBytesToLong(bytes, offset+4, offset+6) << 16) | + PSTUtils.convertLittleEndianBytesToLong(bytes, offset+6, offset+8); + long leastSigBits = PSTUtils.convertBigEndianBytesToLong(bytes, offset+8, offset+16); return new UUID(mostSigBits, leastSigBits); } return null; diff --git a/com/pff/PSTObject.java b/com/pff/objects/PSTObject.java similarity index 60% rename from com/pff/PSTObject.java rename to com/pff/objects/PSTObject.java index c89aa48..aab6c34 100644 --- a/com/pff/PSTObject.java +++ b/com/pff/objects/PSTObject.java @@ -31,11 +31,21 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects; import java.io.IOException; import java.util.*; +import com.pff.PSTUtils; +import com.pff.exceptions.PSTException; +import com.pff.objects.sub.PSTTimeZone; +import com.pff.parsing.DescriptorIndexNode; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.PSTNodeInputStream; +import com.pff.parsing.tables.PSTTableBC; +import com.pff.parsing.tables.PSTTableBCItem; +import com.pff.source.PSTSource; + /** * PST Object is the root class of all PST Items. * It also provides a number of static utility functions. The most important of which is the @@ -71,7 +81,7 @@ public String getItemsString() { return items.toString(); } - protected PSTFile pstFile; + protected PSTSource pstFile; protected byte[] data; protected DescriptorIndexNode descriptorIndexNode; protected HashMap items; @@ -79,7 +89,7 @@ public String getItemsString() { protected LinkedHashMap> children; - protected PSTObject(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) + protected PSTObject(PSTSource theFile, DescriptorIndexNode descriptorIndexNode) throws PSTException, IOException { this.pstFile = theFile; @@ -104,7 +114,7 @@ protected PSTObject(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) * @param folderIndexNode * @param table */ - protected PSTObject(PSTFile theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { + protected PSTObject(PSTSource theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { this.pstFile = theFile; this.descriptorIndexNode = folderIndexNode; this.items = table.getItems(); @@ -129,7 +139,11 @@ public DescriptorIndexNode getDescriptorNode() { * @return item's descriptor node identifier */ public long getDescriptorNodeId() { - return this.descriptorIndexNode.descriptorIdentifier; + //return this.descriptorIndexNode.descriptorIdentifier; + if (this.descriptorIndexNode != null) { // Prevent null pointer exceptions for embedded messages + return this.descriptorIndexNode.descriptorIdentifier; + } + return 0; } public int getNodeType() { @@ -168,7 +182,7 @@ protected double getDoubleItem(int identifier) { protected double getDoubleItem(int identifier, double defaultValue) { if (this.items.containsKey(identifier)) { PSTTableBCItem item = this.items.get(identifier); - long longVersion = PSTObject.convertLittleEndianBytesToLong(item.data); + long longVersion = PSTUtils.convertLittleEndianBytesToLong(item.data); return Double.longBitsToDouble(longVersion); } return defaultValue; @@ -187,7 +201,7 @@ protected long getLongItem(int identifier, long defaultValue) { } else if ( item.entryValueType == 0x0014 ){ // we are a long if ( item.data != null && item.data.length == 8 ) { - return PSTObject.convertLittleEndianBytesToLong(item.data, 0, 8); + return PSTUtils.convertLittleEndianBytesToLong(item.data, 0, 8); } else { System.err.printf("Invalid data length for long id 0x%04X\n", identifier); // Return the default value for now... @@ -237,7 +251,7 @@ protected String getStringItem(int identifier, int stringType, String codepage) } catch (Exception e) { System.err.printf("Exception %s decoding string %s: %s\n", e.toString(), - PSTFile.getPropertyDescription(identifier, stringType), data != null ? data.toString() : "null"); + PSTSource.getPropertyDescription(identifier, stringType), data != null ? data.toString() : "null"); return ""; } //System.out.printf("PSTObject.getStringItem - item isn't a string: 0x%08X\n", identifier); @@ -292,7 +306,7 @@ private String getStringCodepage() { cpItem = this.items.get(0x3FDE); // PidTagInternetCodepage } if (cpItem != null) { - return PSTFile.getInternetCodePageCharset(cpItem.entryValueReference); + return PSTSource.getInternetCodePageCharset(cpItem.entryValueReference); } return null; } @@ -303,10 +317,10 @@ public Date getDateItem(int identifier) { if (item.data.length == 0 ) { return new Date(0); } - int high = (int)PSTObject.convertLittleEndianBytesToLong(item.data, 4, 8); - int low = (int)PSTObject.convertLittleEndianBytesToLong(item.data, 0, 4); + int high = (int)PSTUtils.convertLittleEndianBytesToLong(item.data, 4, 8); + int low = (int)PSTUtils.convertLittleEndianBytesToLong(item.data, 0, 4); - return PSTObject.filetimeToDate(high, low); + return PSTUtils.filetimeToDate(high, low); } return null; } @@ -398,209 +412,7 @@ public Date getLastModificationTime() { } - /** - * Static stuff below - * ------------------ - */ - - // substitution table for the compressible encryption type. - static int[] compEnc = { - 0x47, 0xf1, 0xb4, 0xe6, 0x0b, 0x6a, 0x72, 0x48, 0x85, 0x4e, 0x9e, 0xeb, 0xe2, 0xf8, 0x94, 0x53, - 0xe0, 0xbb, 0xa0, 0x02, 0xe8, 0x5a, 0x09, 0xab, 0xdb, 0xe3, 0xba, 0xc6, 0x7c, 0xc3, 0x10, 0xdd, - 0x39, 0x05, 0x96, 0x30, 0xf5, 0x37, 0x60, 0x82, 0x8c, 0xc9, 0x13, 0x4a, 0x6b, 0x1d, 0xf3, 0xfb, - 0x8f, 0x26, 0x97, 0xca, 0x91, 0x17, 0x01, 0xc4, 0x32, 0x2d, 0x6e, 0x31, 0x95, 0xff, 0xd9, 0x23, - 0xd1, 0x00, 0x5e, 0x79, 0xdc, 0x44, 0x3b, 0x1a, 0x28, 0xc5, 0x61, 0x57, 0x20, 0x90, 0x3d, 0x83, - 0xb9, 0x43, 0xbe, 0x67, 0xd2, 0x46, 0x42, 0x76, 0xc0, 0x6d, 0x5b, 0x7e, 0xb2, 0x0f, 0x16, 0x29, - 0x3c, 0xa9, 0x03, 0x54, 0x0d, 0xda, 0x5d, 0xdf, 0xf6, 0xb7, 0xc7, 0x62, 0xcd, 0x8d, 0x06, 0xd3, - 0x69, 0x5c, 0x86, 0xd6, 0x14, 0xf7, 0xa5, 0x66, 0x75, 0xac, 0xb1, 0xe9, 0x45, 0x21, 0x70, 0x0c, - 0x87, 0x9f, 0x74, 0xa4, 0x22, 0x4c, 0x6f, 0xbf, 0x1f, 0x56, 0xaa, 0x2e, 0xb3, 0x78, 0x33, 0x50, - 0xb0, 0xa3, 0x92, 0xbc, 0xcf, 0x19, 0x1c, 0xa7, 0x63, 0xcb, 0x1e, 0x4d, 0x3e, 0x4b, 0x1b, 0x9b, - 0x4f, 0xe7, 0xf0, 0xee, 0xad, 0x3a, 0xb5, 0x59, 0x04, 0xea, 0x40, 0x55, 0x25, 0x51, 0xe5, 0x7a, - 0x89, 0x38, 0x68, 0x52, 0x7b, 0xfc, 0x27, 0xae, 0xd7, 0xbd, 0xfa, 0x07, 0xf4, 0xcc, 0x8e, 0x5f, - 0xef, 0x35, 0x9c, 0x84, 0x2b, 0x15, 0xd5, 0x77, 0x34, 0x49, 0xb6, 0x12, 0x0a, 0x7f, 0x71, 0x88, - 0xfd, 0x9d, 0x18, 0x41, 0x7d, 0x93, 0xd8, 0x58, 0x2c, 0xce, 0xfe, 0x24, 0xaf, 0xde, 0xb8, 0x36, - 0xc8, 0xa1, 0x80, 0xa6, 0x99, 0x98, 0xa8, 0x2f, 0x0e, 0x81, 0x65, 0x73, 0xe4, 0xc2, 0xa2, 0x8a, - 0xd4, 0xe1, 0x11, 0xd0, 0x08, 0x8b, 0x2a, 0xf2, 0xed, 0x9a, 0x64, 0x3f, 0xc1, 0x6c, 0xf9, 0xec - }; - - /** - * Output a dump of data in hex format in the order it was read in - * @param data - * @param pretty - */ - public static void printHexFormatted(byte[] data, boolean pretty) { - printHexFormatted(data,pretty, new int[0]); - } - protected static void printHexFormatted(byte[] data, boolean pretty, int[] indexes) { - // groups of two - if (pretty) { System.out.println("---"); } - long tmpLongValue; - String line = ""; - int nextIndex = 0; - int indexIndex = 0; - if (indexes.length > 0) { - nextIndex = indexes[0]; - indexIndex++; - } - for (int x = 0; x < data.length; x++) { - tmpLongValue = (long)data[x] & 0xff; - - if (indexes.length > 0 && - x == nextIndex && - nextIndex < data.length) - { - System.out.print("+"); - line += "+"; - while (indexIndex < indexes.length-1 && indexes[indexIndex] <= nextIndex) - { - indexIndex++; - } - nextIndex = indexes[indexIndex]; - //indexIndex++; - } - - if (Character.isLetterOrDigit((char)tmpLongValue)) { - line += (char)tmpLongValue; - } - else - { - line += "."; - } - - if (Long.toHexString(tmpLongValue).length() < 2) { - System.out.print("0"); - } - System.out.print(Long.toHexString(tmpLongValue)); - if (x % 2 == 1 && pretty) { - System.out.print(" "); - } - if (x % 16 == 15 && pretty) { - System.out.print(" "+line); - System.out.println(""); - line = ""; - } - } - if (pretty) { System.out.println(" "+line); System.out.println("---"); System.out.println(data.length); } else { } - } - - - - /** - * decode a lump of data that has been encrypted with the compressible encryption - * @param data - * @return decoded data - */ - protected static byte[] decode(byte[] data) { - int temp; - for (int x = 0; x < data.length; x++) { - temp = data[x] & 0xff; - data[x] = (byte)compEnc[temp]; - } - - return data; - } - - - protected static byte[] encode(byte[] data) { - // create the encoding array... - int[] enc = new int[compEnc.length]; - for (int x = 0; x < enc.length; x++) { - enc[compEnc[x]] = x; - } - - // now it's just the same as decode... - int temp; - for (int x = 0; x < data.length; x++) { - temp = data[x] & 0xff; - data[x] = (byte)enc[temp]; - } - - return data; - } - - /** - * Utility function for converting little endian bytes into a usable java long - * @param data - * @return long version of the data - */ - public static long convertLittleEndianBytesToLong(byte[] data) { - return convertLittleEndianBytesToLong(data, 0, data.length); - } - /** - * Utility function for converting little endian bytes into a usable java long - * @param data - * @param start - * @param end - * @return long version of the data - */ - public static long convertLittleEndianBytesToLong(byte[] data, int start, int end) { - - long offset = data[end-1] & 0xff; - long tmpLongValue; - for (int x = end-2; x >= start; x--) { - offset = offset << 8; - tmpLongValue = (long)data[x] & 0xff; - offset |= tmpLongValue; - } - - return offset; - } - - /** - * Utility function for converting big endian bytes into a usable java long - * @param data - * @param start - * @param end - * @return long version of the data - */ - public static long convertBigEndianBytesToLong(byte[] data, int start, int end) { - - long offset = 0; - for ( int x = start; x < end; ++x ) { - offset = offset << 8; - offset |= ((long)data[x] & 0xFFL); - } - - return offset; - } -/* - protected static boolean isPSTArray(byte[] data) { - return (data[0] == 1 && data[1] == 1); - } -/**/ -/* - protected static int[] getBlockOffsets(RandomAccessFile in, byte[] data) - throws IOException, PSTException - { - // is the data an array? - if (!(data[0] == 1 && data[1] == 1)) - { - throw new PSTException("Unable to process array, does not appear to be one!"); - } - - // we are an array! - // get the array items and merge them together - int numberOfEntries = (int)PSTObject.convertLittleEndianBytesToLong(data, 2, 4); - int[] output = new int[numberOfEntries]; - int tableOffset = 8; - int blockOffset = 0; - for (int y = 0; y < numberOfEntries; y++) { - // get the offset identifier - long tableOffsetIdentifierIndex = PSTObject.convertLittleEndianBytesToLong(data, tableOffset, tableOffset+8); - // clear the last bit of the identifier. Why so hard? - tableOffsetIdentifierIndex = (tableOffsetIdentifierIndex & 0xfffffffe); - OffsetIndexItem tableOffsetIdentifier = PSTObject.getOffsetIndexNode(in, tableOffsetIdentifierIndex); - blockOffset += tableOffsetIdentifier.size; - output[y] = blockOffset; - tableOffset += 8; - } - - // replace the item data with the stuff from the array... - return output; - } -/**/ - /** * Detect and load a PST Object from a file with the specified descriptor index * @param theFile @@ -609,10 +421,10 @@ protected static int[] getBlockOffsets(RandomAccessFile in, byte[] data) * @throws IOException * @throws PSTException */ - public static PSTObject detectAndLoadPSTObject(PSTFile theFile, long descriptorIndex) + public static PSTObject detectAndLoadPSTObject(PSTSource theFile, long descriptorIndex) throws IOException, PSTException { - return PSTObject.detectAndLoadPSTObject(theFile, theFile.getDescriptorIndexNode(descriptorIndex)); + return detectAndLoadPSTObject(theFile, theFile.getDescriptorIndexNode(descriptorIndex)); } /** @@ -623,7 +435,7 @@ public static PSTObject detectAndLoadPSTObject(PSTFile theFile, long descriptorI * @throws IOException * @throws PSTException */ - static PSTObject detectAndLoadPSTObject(PSTFile theFile, DescriptorIndexNode folderIndexNode) + public static PSTObject detectAndLoadPSTObject(PSTSource theFile, DescriptorIndexNode folderIndexNode) throws IOException, PSTException { int nidType = (folderIndexNode.descriptorIdentifier & 0x1F); @@ -639,7 +451,7 @@ static PSTObject detectAndLoadPSTObject(PSTFile theFile, DescriptorIndexNode fol if ( nidType == 0x02 || nidType == 0x03 ) { return new PSTFolder(theFile, folderIndexNode, table, localDescriptorItems); } else { - return PSTObject.createAppropriatePSTMessageObject(theFile, folderIndexNode, table, localDescriptorItems); + return createAppropriatePSTMessageObject(theFile, folderIndexNode, table, localDescriptorItems); } } else @@ -647,8 +459,10 @@ static PSTObject detectAndLoadPSTObject(PSTFile theFile, DescriptorIndexNode fol throw new PSTException("Unknown child type with offset id: "+folderIndexNode.localDescriptorsOffsetIndexIdentifier); } } - - static PSTMessage createAppropriatePSTMessageObject(PSTFile theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) + + + + static PSTMessage createAppropriatePSTMessageObject(PSTSource theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { PSTTableBCItem item = table.getItems().get(0x001a); @@ -679,7 +493,8 @@ static PSTMessage createAppropriatePSTMessageObject(PSTFile theFile, DescriptorI return new PSTMessage(theFile, folderIndexNode, table, localDescriptorItems); } - static String guessPSTObjectType(PSTFile theFile, DescriptorIndexNode folderIndexNode) + + public static String guessPSTObjectType(PSTSource theFile, DescriptorIndexNode folderIndexNode) throws IOException, PSTException { @@ -734,79 +549,5 @@ else if (key.intValue() >= 0x3c00 && } return "Unknown"; } - - /** - * the code below was taken from a random apache project - * http://www.koders.com/java/fidA9D4930E7443F69F32571905DD4CA01E4D46908C.aspx - * my bit-shifting isn't that 1337 - */ - - /** - *

The difference between the Windows epoch (1601-01-01 - * 00:00:00) and the Unix epoch (1970-01-01 00:00:00) in - * milliseconds: 11644473600000L. (Use your favorite spreadsheet - * program to verify the correctness of this value. By the way, - * did you notice that you can tell from the epochs which - * operating system is the modern one? :-))

- */ - private static final long EPOCH_DIFF = 11644473600000L; - - /** - *

Converts a Windows FILETIME into a {@link Date}. The Windows - * FILETIME structure holds a date and time associated with a - * file. The structure identifies a 64-bit integer specifying the - * number of 100-nanosecond intervals which have passed since - * January 1, 1601. This 64-bit value is split into the two double - * words stored in the structure.

- * - * @param high The higher double word of the FILETIME structure. - * @param low The lower double word of the FILETIME structure. - * @return The Windows FILETIME as a {@link Date}. - */ - protected static Date filetimeToDate(final int high, final int low) - { - final long filetime = ((long) high) << 32 | (low & 0xffffffffL); - //System.out.printf("0x%X\n", filetime); - final long ms_since_16010101 = filetime / (1000 * 10); - final long ms_since_19700101 = ms_since_16010101 - EPOCH_DIFF; - return new Date(ms_since_19700101); - } - public static Calendar apptTimeToCalendar(int minutes) { - final long ms_since_16010101 = minutes * (60*1000L); - final long ms_since_19700101 = ms_since_16010101 - EPOCH_DIFF; - Calendar c = Calendar.getInstance(PSTTimeZone.utcTimeZone); - c.setTimeInMillis(ms_since_19700101); - return c; - } - - public static Calendar apptTimeToUTC(int minutes, PSTTimeZone tz) { - // Must convert minutes since 1/1/1601 in local time to UTC - // There's got to be a better way of doing this... - // First get a UTC calendar object that contains _local time_ - Calendar cUTC = PSTObject.apptTimeToCalendar(minutes); - if ( tz != null ) { - // Create an empty Calendar object with the required time zone - Calendar cLocal = Calendar.getInstance(tz.getSimpleTimeZone()); - cLocal.clear(); - - // Now transfer the local date/time from the UTC calendar object - // to the object that knows about the time zone... - cLocal.set(cUTC.get(Calendar.YEAR), - cUTC.get(Calendar.MONTH), - cUTC.get(Calendar.DATE), - cUTC.get(Calendar.HOUR_OF_DAY), - cUTC.get(Calendar.MINUTE), - cUTC.get(Calendar.SECOND)); - - // Get the true UTC from the local time calendar object. - // Drop any milliseconds, they won't be printed anyway! - long utcs = cLocal.getTimeInMillis() / 1000; - - // Finally, set the true UTC in the UTC calendar object - cUTC.setTimeInMillis(utcs * 1000); - } // else hope for the best! - - return cUTC; - } } diff --git a/com/pff/PSTRss.java b/com/pff/objects/PSTRss.java similarity index 84% rename from com/pff/PSTRss.java rename to com/pff/objects/PSTRss.java index 85c830c..bec2e93 100644 --- a/com/pff/PSTRss.java +++ b/com/pff/objects/PSTRss.java @@ -31,11 +31,17 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects; import java.io.IOException; import java.util.HashMap; +import com.pff.exceptions.PSTException; +import com.pff.parsing.DescriptorIndexNode; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.tables.PSTTableBC; +import com.pff.source.PSTSource; + /** * Object that represents a RSS item * @author Richard Johnson @@ -48,7 +54,7 @@ public class PSTRss extends PSTMessage { * @throws PSTException * @throws IOException */ - public PSTRss(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) + public PSTRss(PSTSource theFile, DescriptorIndexNode descriptorIndexNode) throws PSTException, IOException { super(theFile, descriptorIndexNode); } @@ -59,7 +65,7 @@ public PSTRss(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) * @param table * @param localDescriptorItems */ - public PSTRss(PSTFile theFile, DescriptorIndexNode folderIndexNode, + public PSTRss(PSTSource theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { super(theFile, folderIndexNode, table, localDescriptorItems); @@ -69,43 +75,43 @@ public PSTRss(PSTFile theFile, DescriptorIndexNode folderIndexNode, * Channel */ public String getPostRssChannelLink() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008900, PSTFile.PSETID_PostRss)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008900, PSTSource.PSETID_PostRss)); } /** * Item link */ public String getPostRssItemLink() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008901, PSTFile.PSETID_PostRss)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008901, PSTSource.PSETID_PostRss)); } /** * Item hash Integer 32-bit signed */ public int getPostRssItemHash() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008902, PSTFile.PSETID_PostRss)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008902, PSTSource.PSETID_PostRss)); } /** * Item GUID */ public String getPostRssItemGuid() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008903, PSTFile.PSETID_PostRss)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008903, PSTSource.PSETID_PostRss)); } /** * Channel GUID */ public String getPostRssChannel() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008904, PSTFile.PSETID_PostRss)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008904, PSTSource.PSETID_PostRss)); } /** * Item XML */ public String getPostRssItemXml() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008905, PSTFile.PSETID_PostRss)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008905, PSTSource.PSETID_PostRss)); } /** * Subscription */ public String getPostRssSubscription() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008906, PSTFile.PSETID_PostRss)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008906, PSTSource.PSETID_PostRss)); } public String toString() { diff --git a/com/pff/PSTTask.java b/com/pff/objects/PSTTask.java similarity index 81% rename from com/pff/PSTTask.java rename to com/pff/objects/PSTTask.java index c58888b..1477aec 100644 --- a/com/pff/PSTTask.java +++ b/com/pff/objects/PSTTask.java @@ -31,11 +31,17 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects; import java.io.IOException; -import java.util.HashMap; import java.util.Date; +import java.util.HashMap; + +import com.pff.exceptions.PSTException; +import com.pff.parsing.DescriptorIndexNode; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.tables.PSTTableBC; +import com.pff.source.PSTSource; /** * Object that represents Task items @@ -49,7 +55,7 @@ public class PSTTask extends PSTMessage { * @throws PSTException * @throws IOException */ - public PSTTask(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) + public PSTTask(PSTSource theFile, DescriptorIndexNode descriptorIndexNode) throws PSTException, IOException { super(theFile, descriptorIndexNode); } @@ -60,7 +66,7 @@ public PSTTask(PSTFile theFile, DescriptorIndexNode descriptorIndexNode) * @param table * @param localDescriptorItems */ - public PSTTask(PSTFile theFile, DescriptorIndexNode folderIndexNode, + public PSTTask(PSTSource theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap localDescriptorItems) { super(theFile, folderIndexNode, table, localDescriptorItems); @@ -70,98 +76,98 @@ public PSTTask(PSTFile theFile, DescriptorIndexNode folderIndexNode, * Status Integer 32-bit signed 0x0 => Not started */ public int getTaskStatus() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008101, PSTFile.PSETID_Task)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008101, PSTSource.PSETID_Task)); } /** * Percent Complete Floating point double precision (64-bit) */ public double getPercentComplete() { - return getDoubleItem(pstFile.getNameToIdMapItem(0x00008102, PSTFile.PSETID_Task)); + return getDoubleItem(pstFile.getNameToIdMapItem(0x00008102, PSTSource.PSETID_Task)); } /** * Is team task Boolean */ public boolean isTeamTask() { - return getBooleanItem(pstFile.getNameToIdMapItem(0x00008103, PSTFile.PSETID_Task)); + return getBooleanItem(pstFile.getNameToIdMapItem(0x00008103, PSTSource.PSETID_Task)); } /** * Date completed Filetime */ public Date getTaskDateCompleted() { - return getDateItem(pstFile.getNameToIdMapItem(0x0000810f, PSTFile.PSETID_Task)); + return getDateItem(pstFile.getNameToIdMapItem(0x0000810f, PSTSource.PSETID_Task)); } /** * Actual effort in minutes Integer 32-bit signed */ public int getTaskActualEffort() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008110, PSTFile.PSETID_Task)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008110, PSTSource.PSETID_Task)); } /** * Total effort in minutes Integer 32-bit signed */ public int getTaskEstimatedEffort() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008111, PSTFile.PSETID_Task)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008111, PSTSource.PSETID_Task)); } /** * Task version Integer 32-bit signed FTK: Access count */ public int getTaskVersion() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008112, PSTFile.PSETID_Task)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008112, PSTSource.PSETID_Task)); } /** * Complete Boolean */ public boolean isTaskComplete() { - return getBooleanItem(pstFile.getNameToIdMapItem(0x0000811c, PSTFile.PSETID_Task)); + return getBooleanItem(pstFile.getNameToIdMapItem(0x0000811c, PSTSource.PSETID_Task)); } /** * Owner ASCII or Unicode string */ public String getTaskOwner() { - return getStringItem(pstFile.getNameToIdMapItem(0x0000811f, PSTFile.PSETID_Task)); + return getStringItem(pstFile.getNameToIdMapItem(0x0000811f, PSTSource.PSETID_Task)); } /** * Delegator ASCII or Unicode string */ public String getTaskAssigner() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008121, PSTFile.PSETID_Task)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008121, PSTSource.PSETID_Task)); } /** * Unknown ASCII or Unicode string */ public String getTaskLastUser() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008122, PSTFile.PSETID_Task)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008122, PSTSource.PSETID_Task)); } /** * Ordinal Integer 32-bit signed */ public int getTaskOrdinal() { - return this.getIntItem(pstFile.getNameToIdMapItem(0x00008123, PSTFile.PSETID_Task)); + return this.getIntItem(pstFile.getNameToIdMapItem(0x00008123, PSTSource.PSETID_Task)); } /** * Is recurring Boolean */ public boolean isTaskFRecurring() { - return getBooleanItem(pstFile.getNameToIdMapItem(0x00008126, PSTFile.PSETID_Task)); + return getBooleanItem(pstFile.getNameToIdMapItem(0x00008126, PSTSource.PSETID_Task)); } /** * Role ASCII or Unicode string */ public String getTaskRole() { - return getStringItem(pstFile.getNameToIdMapItem(0x00008127, PSTFile.PSETID_Task)); + return getStringItem(pstFile.getNameToIdMapItem(0x00008127, PSTSource.PSETID_Task)); } /** * Ownership Integer 32-bit signed */ public int getTaskOwnership() { - return getIntItem(pstFile.getNameToIdMapItem(0x00008129, PSTFile.PSETID_Task)); + return getIntItem(pstFile.getNameToIdMapItem(0x00008129, PSTSource.PSETID_Task)); } /** * Delegation State */ public int getAcceptanceState() { - return getIntItem(pstFile.getNameToIdMapItem(0x0000812a, PSTFile.PSETID_Task)); + return getIntItem(pstFile.getNameToIdMapItem(0x0000812a, PSTSource.PSETID_Task)); } public String toString() { diff --git a/com/pff/PSTAppointmentRecurrence.java b/com/pff/objects/sub/PSTAppointmentRecurrence.java similarity index 76% rename from com/pff/PSTAppointmentRecurrence.java rename to com/pff/objects/sub/PSTAppointmentRecurrence.java index 4d06c3d..f78f138 100644 --- a/com/pff/PSTAppointmentRecurrence.java +++ b/com/pff/objects/sub/PSTAppointmentRecurrence.java @@ -31,7 +31,7 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects.sub; /* import java.text.SimpleDateFormat; @@ -41,6 +41,12 @@ import java.util.Date; import java.util.SimpleTimeZone; +import com.pff.PSTUtils; +import com.pff.exceptions.PSTAppointmentException; +import com.pff.objects.PSTAppointment; +import com.pff.objects.PSTAttachment; +import com.pff.objects.PSTMessage; + /** * Class containing recurrence information for a recurring appointment * @author Orin Eman @@ -52,6 +58,14 @@ public class PSTAppointmentRecurrence { // Access methods + public Calendar[] getDeletedInstanceDates() { + return DeletedInstanceDates; + } + + public Calendar[] getModifiedInstanceDates() { + return ModifiedInstanceDates; + } + public short getExceptionCount() { return ExceptionCount; } @@ -132,34 +146,34 @@ public PSTAppointmentRecurrence(byte[] recurrencePattern, PSTAppointment appt, P SimpleTimeZone stz = RecurrenceTimeZone.getSimpleTimeZone(); // Read the structure - RecurFrequency = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, 4, 6); - PatternType = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, 6, 8); - CalendarType = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, 8, 10); - FirstDateTime = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, 10, 14); - Period = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, 14, 18); - SlidingFlag = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, 18, 22); + RecurFrequency = (short)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, 4, 6); + PatternType = (short)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, 6, 8); + CalendarType = (short)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, 8, 10); + FirstDateTime = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, 10, 14); + Period = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, 14, 18); + SlidingFlag = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, 18, 22); int offset = 22; if ( PatternType != 0 ) { - PatternSpecific = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + PatternSpecific = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; if ( PatternType == 0x0003 || PatternType == 0x000B ) { - PatternSpecificNth = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + PatternSpecificNth = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; } } - EndType = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + EndType = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - OccurrenceCount = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + OccurrenceCount = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - FirstDOW = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + FirstDOW = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - DeletedInstanceCount = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + DeletedInstanceCount = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; DeletedInstanceDates = new Calendar[DeletedInstanceCount]; for ( int i = 0; i < DeletedInstanceCount; ++i ) { - DeletedInstanceDates[i] = PSTObject.apptTimeToUTC( - (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4), + DeletedInstanceDates[i] = PSTUtils.apptTimeToUTC( + (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4), RecurrenceTimeZone); offset += 4; /* @@ -169,12 +183,12 @@ public PSTAppointmentRecurrence(byte[] recurrencePattern, PSTAppointment appt, P /**/ } - ModifiedInstanceCount = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + ModifiedInstanceCount = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; ModifiedInstanceDates = new Calendar[ModifiedInstanceCount]; for ( int i = 0; i < ModifiedInstanceCount; ++i ) { - ModifiedInstanceDates[i] = PSTObject.apptTimeToUTC( - (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4), + ModifiedInstanceDates[i] = PSTUtils.apptTimeToUTC( + (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4), RecurrenceTimeZone); offset += 4; /* @@ -184,19 +198,19 @@ public PSTAppointmentRecurrence(byte[] recurrencePattern, PSTAppointment appt, P /**/ } - StartDate = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + StartDate = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - EndDate = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + EndDate = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4 + 4; // Skip ReaderVersion2 - writerVersion2 = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + writerVersion2 = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - StartTimeOffset = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + StartTimeOffset = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - EndTimeOffset = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + EndTimeOffset = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4; - ExceptionCount = (short)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); + ExceptionCount = (short)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+2); offset += 2; // Read exceptions @@ -207,13 +221,13 @@ public PSTAppointmentRecurrence(byte[] recurrencePattern, PSTAppointment appt, P } if ( (offset + 4) <= recurrencePattern.length ) { - int ReservedBlock1Size = (int)PSTObject.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); + int ReservedBlock1Size = (int)PSTUtils.convertLittleEndianBytesToLong(recurrencePattern, offset, offset+4); offset += 4 + (ReservedBlock1Size * 4); } // Read extended exception info for ( int i = 0; i < ExceptionCount; ++i ) { - Exceptions[i].ExtendedException(recurrencePattern, offset); + Exceptions[i].buildExtendedException(recurrencePattern, offset); offset += Exceptions[i].getExtendedLength(); /* Calendar c = PSTObject.apptTimeToUTC(Exceptions[i].getStartDateTime(), RecurrenceTimeZone); diff --git a/com/pff/PSTRecipient.java b/com/pff/objects/sub/PSTRecipient.java similarity index 96% rename from com/pff/PSTRecipient.java rename to com/pff/objects/sub/PSTRecipient.java index 5d9bc8e..4e7ebe3 100644 --- a/com/pff/PSTRecipient.java +++ b/com/pff/objects/sub/PSTRecipient.java @@ -31,11 +31,13 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects.sub; //import java.util.Date; import java.util.HashMap; +import com.pff.parsing.tables.PSTTable7CItem; + /** * Class containing recipient information * @author Orin Eman @@ -50,8 +52,7 @@ public class PSTRecipient { public static final int MAPI_CC = 2; public static final int MAPI_BCC = 3; - PSTRecipient(HashMap recipientDetails) - { + public PSTRecipient(HashMap recipientDetails) { details = recipientDetails; } diff --git a/com/pff/PSTTimeZone.java b/com/pff/objects/sub/PSTTimeZone.java similarity index 77% rename from com/pff/PSTTimeZone.java rename to com/pff/objects/sub/PSTTimeZone.java index 063d2ca..152a424 100644 --- a/com/pff/PSTTimeZone.java +++ b/com/pff/objects/sub/PSTTimeZone.java @@ -31,11 +31,13 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.objects.sub; import java.util.Calendar; import java.util.SimpleTimeZone; +import com.pff.PSTUtils; + /** * Class containing time zone information * @author Orin Eman @@ -44,21 +46,23 @@ */ public class PSTTimeZone { - PSTTimeZone(byte [] timeZoneData) { + + + public PSTTimeZone(byte [] timeZoneData) { this.rule = null; name = ""; try { - int headerLen = (int)PSTObject.convertLittleEndianBytesToLong(timeZoneData, 2, 4); - int nameLen = 2*(int)PSTObject.convertLittleEndianBytesToLong(timeZoneData, 6, 8); + int headerLen = (int)PSTUtils.convertLittleEndianBytesToLong(timeZoneData, 2, 4); + int nameLen = 2*(int)PSTUtils.convertLittleEndianBytesToLong(timeZoneData, 6, 8); name = new String(timeZoneData, 8, nameLen, "UTF-16LE"); int ruleOffset = 8+nameLen; - int nRules = (int)PSTObject.convertLittleEndianBytesToLong(timeZoneData, ruleOffset, ruleOffset+2); + int nRules = (int)PSTUtils.convertLittleEndianBytesToLong(timeZoneData, ruleOffset, ruleOffset+2); ruleOffset = 4 + headerLen; for ( int rule = 0; rule < nRules; ++rule ) { // Is this rule the effective rule? - int flags = (int)PSTObject.convertLittleEndianBytesToLong(timeZoneData, ruleOffset+4, ruleOffset+6); + int flags = (int)PSTUtils.convertLittleEndianBytesToLong(timeZoneData, ruleOffset+4, ruleOffset+6); if ( (flags & 0x0002) != 0 ) { this.rule = new TZRule(timeZoneData, ruleOffset+6); break; @@ -74,7 +78,7 @@ public class PSTTimeZone { } } - PSTTimeZone(String name, byte[] timeZoneData) { + public PSTTimeZone(String name, byte[] timeZoneData) { this.name = name; this.rule = null; @@ -181,14 +185,14 @@ public class SYSTEMTIME { } SYSTEMTIME(byte[] timeZoneData, int offset) { - wYear = (short)(PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset, offset+2)&0x7FFF); - wMonth = (short)(PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+2, offset+4)&0x7FFF); - wDayOfWeek = (short)(PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+4, offset+6)&0x7FFF); - wDay = (short)(PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+6, offset+8)&0x7FFF); - wHour = (short)(PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+8, offset+10)&0x7FFF); - wMinute = (short)(PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+10, offset+12)&0x7FFF); - wSecond = (short)(PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+12, offset+14)&0x7FFF); - wMilliseconds = (short)(PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+14, offset+16)&0x7FFF); + wYear = (short)(PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset, offset+2)&0x7FFF); + wMonth = (short)(PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+2, offset+4)&0x7FFF); + wDayOfWeek = (short)(PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+4, offset+6)&0x7FFF); + wDay = (short)(PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+6, offset+8)&0x7FFF); + wHour = (short)(PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+8, offset+10)&0x7FFF); + wMinute = (short)(PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+10, offset+12)&0x7FFF); + wSecond = (short)(PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+12, offset+14)&0x7FFF); + wMilliseconds = (short)(PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+14, offset+16)&0x7FFF); } boolean isEqual(SYSTEMTIME rhs) { @@ -223,10 +227,10 @@ private class TZRule { this.dtStart = dtStart; InitBiases(timeZoneData, offset); @SuppressWarnings("unused") - short wStandardYear = (short)PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+12, offset+14); + short wStandardYear = (short)PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+12, offset+14); startStandard = new SYSTEMTIME(timeZoneData, offset+14); @SuppressWarnings("unused") - short wDaylightYear = (short)PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+30, offset+32); + short wDaylightYear = (short)PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+30, offset+32); startDaylight = new SYSTEMTIME(timeZoneData, offset+32); } @@ -238,9 +242,9 @@ private class TZRule { } private void InitBiases(byte[] timeZoneData, int offset) { - lBias = (int)PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset, offset+4); - lStandardBias = (int)PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+4, offset+8); - lDaylightBias = (int)PSTObject.convertLittleEndianBytesToLong(timeZoneData, offset+8, offset+12); + lBias = (int)PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset, offset+4); + lStandardBias = (int)PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+4, offset+8); + lDaylightBias = (int)PSTUtils.convertLittleEndianBytesToLong(timeZoneData, offset+8, offset+12); } boolean isEqual(TZRule rhs) { diff --git a/com/pff/DescriptorIndexNode.java b/com/pff/parsing/DescriptorIndexNode.java similarity index 72% rename from com/pff/DescriptorIndexNode.java rename to com/pff/parsing/DescriptorIndexNode.java index 8e97b76..6b13daf 100644 --- a/com/pff/DescriptorIndexNode.java +++ b/com/pff/parsing/DescriptorIndexNode.java @@ -31,10 +31,14 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.parsing; import java.io.IOException; +import com.pff.PSTUtils; +import com.pff.exceptions.PSTException; +import com.pff.source.PSTSource; + /** * DescriptorIndexNode is a leaf item from the Descriptor index b-tree * It is like a pointer to an element in the PST file, everything has one... @@ -53,21 +57,21 @@ public class DescriptorIndexNode { * parse the data out into something meaningful * @param data */ - DescriptorIndexNode(byte[] data, int pstFileType) { + public DescriptorIndexNode(byte[] data, int pstFileType) { // parse it out // first 4 bytes - if (pstFileType == PSTFile.PST_TYPE_ANSI) { - descriptorIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, 0, 4); - dataOffsetIndexIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, 4, 8); - localDescriptorsOffsetIndexIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, 8, 12); - parentDescriptorIndexIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, 12, 16); + if (pstFileType == PSTSource.PST_TYPE_ANSI) { + descriptorIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, 0, 4); + dataOffsetIndexIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, 4, 8); + localDescriptorsOffsetIndexIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, 8, 12); + parentDescriptorIndexIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, 12, 16); //itemType = (int)PSTObject.convertLittleEndianBytesToLong(data, 28, 32); } else { - descriptorIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, 0, 4); - dataOffsetIndexIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, 8, 16); - localDescriptorsOffsetIndexIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, 16, 24); - parentDescriptorIndexIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, 24, 28); - itemType = (int)PSTObject.convertLittleEndianBytesToLong(data, 28, 32); + descriptorIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, 0, 4); + dataOffsetIndexIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, 8, 16); + localDescriptorsOffsetIndexIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, 16, 24); + parentDescriptorIndexIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, 24, 28); + itemType = (int)PSTUtils.convertLittleEndianBytesToLong(data, 28, 32); } } @@ -82,7 +86,7 @@ void readData(PSTFile file) * */ - PSTNodeInputStream getNodeInputStream(PSTFile pstFile) + PSTNodeInputStream getNodeInputStream(PSTSource pstFile) throws IOException, PSTException { return new PSTNodeInputStream(pstFile,pstFile.getOffsetIndexNode(dataOffsetIndexIdentifier)); diff --git a/com/pff/OffsetIndexItem.java b/com/pff/parsing/OffsetIndexItem.java similarity index 67% rename from com/pff/OffsetIndexItem.java rename to com/pff/parsing/OffsetIndexItem.java index 76f1808..6e7635c 100644 --- a/com/pff/OffsetIndexItem.java +++ b/com/pff/parsing/OffsetIndexItem.java @@ -31,34 +31,38 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.parsing; + +import com.pff.PSTUtils; +import com.pff.source.PSTSource; /** * OffsetIndexItem is a leaf item from the Offset index b-tree * Only really used internally to get the file offset for items * @author Richard Johnson */ -class OffsetIndexItem { +public class OffsetIndexItem { long indexIdentifier; long fileOffset; int size; long cRef; - OffsetIndexItem(byte[] data, int pstFileType) { - if (pstFileType == PSTFile.PST_TYPE_ANSI) { - indexIdentifier = PSTObject.convertLittleEndianBytesToLong(data, 0, 4); - fileOffset = PSTObject.convertLittleEndianBytesToLong(data, 4, 8); - size = (int)PSTObject.convertLittleEndianBytesToLong(data, 8, 10); - cRef = (int)PSTObject.convertLittleEndianBytesToLong(data, 10, 12); + public OffsetIndexItem(byte[] data, int pstFileType) { + if (pstFileType == PSTSource.PST_TYPE_ANSI) { + indexIdentifier = PSTUtils.convertLittleEndianBytesToLong(data, 0, 4); + fileOffset = PSTUtils.convertLittleEndianBytesToLong(data, 4, 8); + size = (int)PSTUtils.convertLittleEndianBytesToLong(data, 8, 10); + cRef = (int)PSTUtils.convertLittleEndianBytesToLong(data, 10, 12); } else { - indexIdentifier = PSTObject.convertLittleEndianBytesToLong(data, 0, 8); - fileOffset = PSTObject.convertLittleEndianBytesToLong(data, 8, 16); - size = (int)PSTObject.convertLittleEndianBytesToLong(data, 16, 18); - cRef = (int)PSTObject.convertLittleEndianBytesToLong(data, 16, 18); + indexIdentifier = PSTUtils.convertLittleEndianBytesToLong(data, 0, 8); + fileOffset = PSTUtils.convertLittleEndianBytesToLong(data, 8, 16); + size = (int)PSTUtils.convertLittleEndianBytesToLong(data, 16, 18); + cRef = (int)PSTUtils.convertLittleEndianBytesToLong(data, 16, 18); } //System.out.println("Data size: "+data.length); } + @Override public String toString() { @@ -68,4 +72,23 @@ public String toString() { "cRef: "+cRef+" (0x"+Long.toHexString(cRef)+" bin:"+Long.toBinaryString(cRef)+")\n"+ "Size: "+size+" (0x"+Long.toHexString(size)+")"; } + + + public long getIndexIdentifier() { + return indexIdentifier; + } + + + public long getFileOffset() { + return fileOffset; + } + + + public int getSize() { + return size; + } + + + + } diff --git a/com/pff/PSTDescriptorItem.java b/com/pff/parsing/PSTDescriptorItem.java similarity index 69% rename from com/pff/PSTDescriptorItem.java rename to com/pff/parsing/PSTDescriptorItem.java index 3d67dc7..96a861d 100644 --- a/com/pff/PSTDescriptorItem.java +++ b/com/pff/parsing/PSTDescriptorItem.java @@ -31,40 +31,41 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.parsing; import java.io.IOException; -import java.util.*; + +import com.pff.PSTUtils; +import com.pff.exceptions.PSTException; +import com.pff.source.PSTSource; + /** * The descriptor items contain information that describes a PST object. * This is like extended table entries, usually when the data cannot fit in a traditional table item. * @author Richard Johnson */ -class PSTDescriptorItem +public class PSTDescriptorItem { - PSTDescriptorItem(byte[] data, int offset, PSTFile pstFile) - { + public PSTDescriptorItem(byte[] data, int offset, PSTSource pstFile) { this.pstFile = pstFile; - if (pstFile.getPSTFileType() == PSTFile.PST_TYPE_ANSI) { - descriptorIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, offset, offset+4); - offsetIndexIdentifier = ((int)PSTObject.convertLittleEndianBytesToLong(data, offset+4, offset+8)) + if (pstFile.getPSTFileType() == PSTSource.PST_TYPE_ANSI) { + descriptorIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, offset, offset+4); + offsetIndexIdentifier = ((int)PSTUtils.convertLittleEndianBytesToLong(data, offset+4, offset+8)) & 0xfffffffe; - subNodeOffsetIndexIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, offset+8, offset+12) + subNodeOffsetIndexIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, offset+8, offset+12) & 0xfffffffe; } else { - descriptorIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, offset, offset+4); - offsetIndexIdentifier = ((int)PSTObject.convertLittleEndianBytesToLong(data, offset+8, offset+16)) + descriptorIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, offset, offset+4); + offsetIndexIdentifier = ((int)PSTUtils.convertLittleEndianBytesToLong(data, offset+8, offset+16)) & 0xfffffffe; - subNodeOffsetIndexIdentifier = (int)PSTObject.convertLittleEndianBytesToLong(data, offset+16, offset+24) + subNodeOffsetIndexIdentifier = (int)PSTUtils.convertLittleEndianBytesToLong(data, offset+16, offset+24) & 0xfffffffe; } } - public byte[] getData() - throws IOException, PSTException - { + public byte[] getData() throws IOException, PSTException { if ( dataBlockData != null ) { return dataBlockData; } @@ -76,11 +77,8 @@ public byte[] getData() return dataBlockData; } - public int[] getBlockOffsets() - throws IOException, PSTException - { + public int[] getBlockOffsets() throws IOException, PSTException { if ( dataBlockOffsets != null ) { - return dataBlockOffsets; } Long[] offsets = pstFile.readLeaf(offsetIndexIdentifier).getBlockOffsets(); @@ -91,14 +89,14 @@ public int[] getBlockOffsets() return offsetsOut; } - public int getDataSize() - throws IOException, PSTException - { + public int getDataSize() throws IOException, PSTException { return pstFile.getLeafSize(offsetIndexIdentifier); } // Public data int descriptorIdentifier; + + int offsetIndexIdentifier; int subNodeOffsetIndexIdentifier; @@ -106,7 +104,7 @@ public int getDataSize() //private PSTFile.PSTFileBlock dataBlock = null; byte[] dataBlockData = null; int[] dataBlockOffsets = null; - private PSTFile pstFile; + private PSTSource pstFile; @Override public String toString() { @@ -118,5 +116,17 @@ public String toString() { } + + + public int getDescriptorIdentifier() { + return descriptorIdentifier; + } + + public int getSubNodeOffsetIndexIdentifier() { + return subNodeOffsetIndexIdentifier; + } + + + } diff --git a/com/pff/PSTNodeInputStream.java b/com/pff/parsing/PSTNodeInputStream.java similarity index 80% rename from com/pff/PSTNodeInputStream.java rename to com/pff/parsing/PSTNodeInputStream.java index 3c36218..707126f 100644 --- a/com/pff/PSTNodeInputStream.java +++ b/com/pff/parsing/PSTNodeInputStream.java @@ -32,10 +32,15 @@ * */ -package com.pff; +package com.pff.parsing; -import java.io.*; -import java.util.*; +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedList; + +import com.pff.PSTUtils; +import com.pff.exceptions.PSTException; +import com.pff.source.PSTSource; /** * this input stream basically "maps" an input stream on top of the random access file @@ -43,8 +48,8 @@ */ public class PSTNodeInputStream extends InputStream { - private RandomAccessFile in; - private PSTFile pstFile; + //private _RandomAccessPSTSource in; + private PSTSource pstFile; private LinkedList skipPoints = new LinkedList(); private LinkedList indexItems = new LinkedList(); private int currentBlock = 0; @@ -56,14 +61,14 @@ public class PSTNodeInputStream extends InputStream { private boolean encrypted = false; - PSTNodeInputStream(PSTFile pstFile, byte[] attachmentData) { + public PSTNodeInputStream(PSTSource pstFile, byte[] attachmentData) { this.allData = attachmentData; this.length = this.allData.length; - encrypted = pstFile.getEncryptionType() == PSTFile.ENCRYPTION_TYPE_COMPRESSIBLE; + encrypted = pstFile.getEncryptionType() == PSTSource.ENCRYPTION_TYPE_COMPRESSIBLE; this.currentBlock = 0; this.currentLocation = 0; } - PSTNodeInputStream(PSTFile pstFile, byte[] attachmentData, boolean encrypted) { + public PSTNodeInputStream(PSTSource pstFile, byte[] attachmentData, boolean encrypted) { this.allData = attachmentData; this.encrypted = encrypted; this.length = this.allData.length; @@ -71,12 +76,12 @@ public class PSTNodeInputStream extends InputStream { this.currentLocation = 0; } - PSTNodeInputStream(PSTFile pstFile, PSTDescriptorItem descriptorItem) + public PSTNodeInputStream(PSTSource pstFile, PSTDescriptorItem descriptorItem) throws IOException, PSTException { - this.in = pstFile.getFileHandle(); + //this.in = pstFile.getFileHandle(); this.pstFile = pstFile; - this.encrypted = pstFile.getEncryptionType() == PSTFile.ENCRYPTION_TYPE_COMPRESSIBLE; + this.encrypted = pstFile.getEncryptionType() == PSTSource.ENCRYPTION_TYPE_COMPRESSIBLE; // we want to get the first block of data and see what we are dealing with OffsetIndexItem offsetItem = pstFile.getOffsetIndexNode(descriptorItem.offsetIndexIdentifier); @@ -86,12 +91,12 @@ public class PSTNodeInputStream extends InputStream { } - PSTNodeInputStream(PSTFile pstFile, OffsetIndexItem offsetItem) + public PSTNodeInputStream(PSTSource pstFile, OffsetIndexItem offsetItem) throws IOException, PSTException { - this.in = pstFile.getFileHandle(); + //this.in = pstFile.getFileHandle(); this.pstFile = pstFile; - this.encrypted = pstFile.getEncryptionType() == PSTFile.ENCRYPTION_TYPE_COMPRESSIBLE; + this.encrypted = pstFile.getEncryptionType() == PSTSource.ENCRYPTION_TYPE_COMPRESSIBLE; loadFromOffsetItem(offsetItem); this.currentBlock = 0; this.currentLocation = 0; @@ -102,9 +107,11 @@ private void loadFromOffsetItem(OffsetIndexItem offsetItem) { boolean bInternal = (offsetItem.indexIdentifier & 0x02) != 0; - in.seek(offsetItem.fileOffset); + //System.out.println("PSTNodeInputStream - loadFromOffsetItem 0 => seek "+ offsetItem.fileOffset); + + pstFile.getRASource().seek(offsetItem.fileOffset); byte[] data = new byte[offsetItem.size]; - in.read(data); + pstFile.getRASource().read(data); if ( bInternal ) { // All internal blocks are at least 8 bytes long... @@ -116,7 +123,7 @@ private void loadFromOffsetItem(OffsetIndexItem offsetItem) { bInternal = false; // we are a block, or xxblock - length = PSTObject.convertLittleEndianBytesToLong(data, 4, 8); + length = PSTUtils.convertLittleEndianBytesToLong(data, 4, 8); // go through all of the blocks and create skip points. this.getBlockSkipPoints(data); return; @@ -143,23 +150,25 @@ private void getBlockSkipPoints(byte[] data) throw new PSTException("Unable to process XBlock, incorrect identifier"); } - int numberOfEntries = (int)PSTObject.convertLittleEndianBytesToLong(data, 2, 4); + int numberOfEntries = (int)PSTUtils.convertLittleEndianBytesToLong(data, 2, 4); int arraySize = 8; - if (this.pstFile.getPSTFileType() == PSTFile.PST_TYPE_ANSI) { + if (this.pstFile.getPSTFileType() == PSTSource.PST_TYPE_ANSI) { arraySize = 4; } if (data[1] == 0x2) { // XXBlock int offset = 8; for (int x = 0; x < numberOfEntries; x++) { - long bid = PSTObject.convertLittleEndianBytesToLong(data, offset, offset+arraySize); + long bid = PSTUtils.convertLittleEndianBytesToLong(data, offset, offset+arraySize); bid &= 0xfffffffe; // get the details in this block and OffsetIndexItem offsetItem = this.pstFile.getOffsetIndexNode(bid); - in.seek(offsetItem.fileOffset); + //System.out.println("PSTNodeInputStream - getBlockSkipPoints 0 => seek "+ offsetItem.fileOffset); + + pstFile.getRASource().seek(offsetItem.fileOffset); byte[] blockData = new byte[offsetItem.size]; - in.read(blockData); + pstFile.getRASource().read(blockData); this.getBlockSkipPoints(blockData); offset += arraySize; } @@ -167,7 +176,7 @@ private void getBlockSkipPoints(byte[] data) // normal XBlock int offset = 8; for (int x = 0; x < numberOfEntries; x++) { - long bid = PSTObject.convertLittleEndianBytesToLong(data, offset, offset+arraySize); + long bid = PSTUtils.convertLittleEndianBytesToLong(data, offset, offset+arraySize); bid &= 0xfffffffe; // get the details in this block and add it to the list OffsetIndexItem offsetItem = pstFile.getOffsetIndexNode(bid); @@ -197,7 +206,7 @@ public int read() int value = this.allData[(int)this.currentLocation] & 0xFF; this.currentLocation++; if (this.encrypted) { - value = PSTObject.compEnc[value]; + value = PSTUtils.getCompEnc(value); } return value; } @@ -218,16 +227,16 @@ public int read() // get the next byte. long pos = (item.fileOffset + (this.currentLocation - skipPoint)); - if (in.getFilePointer() != pos) { - in.seek(pos); + if (pstFile.getRASource().position() != pos) { + pstFile.getRASource().seek(pos); } - int output = in.read(); + int output = pstFile.getRASource().read(); if (output < 0) { return -1; } if (this.encrypted) { - output = PSTObject.compEnc[output]; + output = PSTUtils.getCompEnc(output); } this.currentLocation++; @@ -235,7 +244,7 @@ public int read() return output; } - private int totalLoopCount = 0; + //private int totalLoopCount = 0; /** * Read a block from the input stream. @@ -263,14 +272,14 @@ public int read(byte[] output) if (output.length >= bytesRemaining) { System.arraycopy(this.allData, (int)this.currentLocation, output, 0, bytesRemaining); if (this.encrypted) { - PSTObject.decode(output); + PSTUtils.decode(output); } this.currentLocation += bytesRemaining; // should be = to this.length return bytesRemaining; } else { System.arraycopy(this.allData, (int)this.currentLocation, output, 0, output.length); if (this.encrypted) { - PSTObject.decode(output); + PSTUtils.decode(output); } this.currentLocation += output.length; return output.length; @@ -287,7 +296,10 @@ public int read(byte[] output) OffsetIndexItem offset = this.indexItems.get(this.currentBlock); long skipPoint = this.skipPoints.get(currentBlock); int currentPosInBlock = (int)(this.currentLocation - skipPoint); - in.seek(offset.fileOffset + currentPosInBlock); + + //System.out.println("PSTNodeInputStream - read 0 => seek "+ (offset.fileOffset + currentPosInBlock)); + + pstFile.getRASource().seek(offset.fileOffset + currentPosInBlock); long nextSkipPoint = skipPoint + offset.size; int bytesRemaining = (output.length - totalBytesFilled); @@ -300,7 +312,7 @@ public int read(byte[] output) if (nextSkipPoint >= this.currentLocation + bytesRemaining) { // we can fill the output with the rest of our current block! byte[] chunk = new byte[bytesRemaining]; - in.read(chunk); + pstFile.getRASource().read(chunk); System.arraycopy(chunk, 0, output, totalBytesFilled, bytesRemaining); totalBytesFilled += bytesRemaining; @@ -311,18 +323,18 @@ public int read(byte[] output) // we need to read out a whole chunk and keep going int bytesToRead = offset.size - currentPosInBlock; byte[] chunk = new byte[bytesToRead]; - in.read(chunk); + pstFile.getRASource().read(chunk); System.arraycopy(chunk, 0, output, totalBytesFilled, bytesToRead); totalBytesFilled += bytesToRead; this.currentBlock++; this.currentLocation += bytesToRead; } - totalLoopCount++; + //totalLoopCount++; } // decode the array if required if (this.encrypted) { - PSTObject.decode(output); + PSTUtils.decode(output); } // fill up our chunk @@ -430,7 +442,9 @@ public void seek(long location) blockStart = this.indexItems.get(currentBlock).fileOffset; } long newFilePos = blockStart + (location - skipPoint); - this.in.seek(newFilePos); + + //System.out.println("PSTNodeInputStream - seek 0 => seek "+ newFilePos); + pstFile.getRASource().seek(newFilePos); } @@ -440,10 +454,10 @@ public long seekAndReadLong(long location, int bytes) this.seek(location); byte[] buffer = new byte[bytes]; this.read(buffer); - return PSTObject.convertLittleEndianBytesToLong(buffer); + return PSTUtils.convertLittleEndianBytesToLong(buffer); } - public PSTFile getPSTFile() { + public PSTSource getPSTFile() { return this.pstFile; } diff --git a/com/pff/PSTTable.java b/com/pff/parsing/tables/PSTTable.java similarity index 96% rename from com/pff/PSTTable.java rename to com/pff/parsing/tables/PSTTable.java index 1e27667..6892703 100644 --- a/com/pff/PSTTable.java +++ b/com/pff/parsing/tables/PSTTable.java @@ -31,11 +31,16 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.parsing.tables; import java.io.IOException; import java.util.HashMap; +import com.pff.PSTUtils; +import com.pff.exceptions.PSTException; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.PSTNodeInputStream; + /** * The PST Table is the workhorse of the whole system. @@ -81,8 +86,8 @@ protected PSTTable(PSTNodeInputStream in, HashMap su in.read(headdata); if ((int)headdata[2] != 0xffffffec) { //System.out.println(in.isEncrypted()); - PSTObject.decode(headdata); - PSTObject.printHexFormatted(headdata, true); + PSTUtils.decode(headdata); + PSTUtils.printHexFormatted(headdata, true); throw new PSTException("Unable to parse table, bad table type..."); } @@ -131,7 +136,7 @@ protected PSTTable(PSTNodeInputStream in, HashMap su headerNodeInfo.in.seek(headerNodeInfo.startOffset); byte[] tmp = new byte[1024]; headerNodeInfo.in.read(tmp); - PSTObject.printHexFormatted(tmp, true); + PSTUtils.printHexFormatted(tmp, true); //System.out.println(PSTObject.compEnc[headerByte]); throw new PSTException("Unable to parse table, can't find BTHHEADER header information: "+headerByte); } diff --git a/com/pff/PSTTable7C.java b/com/pff/parsing/tables/PSTTable7C.java similarity index 94% rename from com/pff/PSTTable7C.java rename to com/pff/parsing/tables/PSTTable7C.java index e092ebf..883dd16 100644 --- a/com/pff/PSTTable7C.java +++ b/com/pff/parsing/tables/PSTTable7C.java @@ -31,20 +31,27 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.parsing.tables; /* import java.io.UnsupportedEncodingException; /**/ -import java.util.*; -import java.io.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.pff.exceptions.PSTException; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.PSTNodeInputStream; +import com.pff.source.PSTSource; /** * Specific functions for the 7c table type ("Table Context"). * This is used for attachments. * @author Richard Johnson */ -class PSTTable7C extends PSTTable { +public class PSTTable7C extends PSTTable { private final int BLOCK_SIZE = 8176; @@ -56,12 +63,12 @@ class PSTTable7C extends PSTTable { private int TCI_1b = 0; private int overrideCol = -1; - protected PSTTable7C(PSTNodeInputStream in, HashMap subNodeDescriptorItems) + public PSTTable7C(PSTNodeInputStream in, HashMap subNodeDescriptorItems) throws PSTException, java.io.IOException { this(in, subNodeDescriptorItems, -1); } - protected PSTTable7C(PSTNodeInputStream in, HashMap subNodeDescriptorItems, int entityToExtract) + public PSTTable7C(PSTNodeInputStream in, HashMap subNodeDescriptorItems, int entityToExtract) throws PSTException, java.io.IOException { super(in, subNodeDescriptorItems); @@ -154,16 +161,15 @@ protected PSTTable7C(PSTNodeInputStream in, HashMap * get all the items parsed out of this table. * @return */ - List> getItems() - throws PSTException, IOException - { + public List> getItems() throws PSTException, IOException { if ( items == null ) { items = getItems(-1, -1); } return items; } + - List> getItems(int startAtRecord, int numberOfRecordsToReturn) + public List> getItems(int startAtRecord, int numberOfRecordsToReturn) throws PSTException, IOException { List> itemList = new ArrayList>(); @@ -194,7 +200,7 @@ List> getItems(int startAtRecord, int numberOfR { HashMap currentItem = new HashMap(); // add on some padding for block boundries? - if (rowNodeInfo.in.getPSTFile().getPSTFileType() == PSTFile.PST_TYPE_ANSI) { + if (rowNodeInfo.in.getPSTFile().getPSTFileType() == PSTSource.PST_TYPE_ANSI) { if (currentValueArrayStart >= BLOCK_SIZE) { currentValueArrayStart = currentValueArrayStart + (4) * (currentValueArrayStart / BLOCK_SIZE); } diff --git a/com/pff/PSTTable7CItem.java b/com/pff/parsing/tables/PSTTable7CItem.java similarity index 94% rename from com/pff/PSTTable7CItem.java rename to com/pff/parsing/tables/PSTTable7CItem.java index 16b9877..0d0fec3 100644 --- a/com/pff/PSTTable7CItem.java +++ b/com/pff/parsing/tables/PSTTable7CItem.java @@ -31,13 +31,13 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.parsing.tables; /** * Items found in the 7c tables * @author Richard Johnson */ -class PSTTable7CItem extends PSTTableItem +public class PSTTable7CItem extends PSTTableItem { public String toString() { diff --git a/com/pff/PSTTableBC.java b/com/pff/parsing/tables/PSTTableBC.java similarity index 90% rename from com/pff/PSTTableBC.java rename to com/pff/parsing/tables/PSTTableBC.java index f681248..22a56aa 100644 --- a/com/pff/PSTTableBC.java +++ b/com/pff/parsing/tables/PSTTableBC.java @@ -31,26 +31,29 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.parsing.tables; import java.util.HashMap; +import com.pff.PSTUtils; +import com.pff.exceptions.PSTException; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.PSTNodeInputStream; + /** * The BC Table type. (Property Context) * Used by pretty much everything. * @author Richard Johnson */ -class PSTTableBC extends PSTTable { +public class PSTTableBC extends PSTTable { private HashMap items = new HashMap(); private StringBuilder descBuffer = new StringBuilder(); private boolean isDescNotYetInitiated = false; - PSTTableBC(PSTNodeInputStream in) - throws PSTException, java.io.IOException - { + public PSTTableBC(PSTNodeInputStream in) throws PSTException, java.io.IOException { super(in, new HashMap()); //data = null; // No direct access to data! @@ -81,11 +84,11 @@ class PSTTableBC extends PSTTable { PSTTableBCItem item = new PSTTableBCItem(); item.itemIndex = x; - item.entryType =(int)PSTObject.convertLittleEndianBytesToLong(keyTableInfo, offset+0, offset+2); + item.entryType =(int)PSTUtils.convertLittleEndianBytesToLong(keyTableInfo, offset+0, offset+2); //item.entryType =(int)in.seekAndReadLong(offset, 2); - item.entryValueType = (int)PSTObject.convertLittleEndianBytesToLong(keyTableInfo, offset+2, offset+4); + item.entryValueType = (int)PSTUtils.convertLittleEndianBytesToLong(keyTableInfo, offset+2, offset+4); //item.entryValueType = (int)in.seekAndReadLong(offset+2, 2); - item.entryValueReference = (int)PSTObject.convertLittleEndianBytesToLong(keyTableInfo, offset+4, offset+8); + item.entryValueReference = (int)PSTUtils.convertLittleEndianBytesToLong(keyTableInfo, offset+4, offset+8); //item.entryValueReference = (int)in.seekAndReadLong(offset+4, 4); // Data is in entryValueReference for all types <= 4 bytes long diff --git a/com/pff/PSTTableBCItem.java b/com/pff/parsing/tables/PSTTableBCItem.java similarity index 94% rename from com/pff/PSTTableBCItem.java rename to com/pff/parsing/tables/PSTTableBCItem.java index 4f7b330..bf33aa0 100644 --- a/com/pff/PSTTableBCItem.java +++ b/com/pff/parsing/tables/PSTTableBCItem.java @@ -31,13 +31,13 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.parsing.tables; /** * Items within the BC Table * @author Richard Johnson */ -class PSTTableBCItem extends PSTTableItem +public class PSTTableBCItem extends PSTTableItem { public String toString() { diff --git a/com/pff/PSTTableItem.java b/com/pff/parsing/tables/PSTTableItem.java similarity index 91% rename from com/pff/PSTTableItem.java rename to com/pff/parsing/tables/PSTTableItem.java index fe5fd1a..f660413 100644 --- a/com/pff/PSTTableItem.java +++ b/com/pff/parsing/tables/PSTTableItem.java @@ -31,7 +31,7 @@ * along with java-libpst. If not, see . * */ -package com.pff; +package com.pff.parsing.tables; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; @@ -39,12 +39,15 @@ import java.util.Date; import java.util.SimpleTimeZone; +import com.pff.PSTUtils; +import com.pff.source.PSTSource; + /** * Generic table item. * Provides some basic string functions * @author Richard Johnson */ -class PSTTableItem { +public class PSTTableItem { public static final int VALUE_TYPE_PT_UNICODE = 0x1f; public static final int VALUE_TYPE_PT_STRING8 = 0x1e; @@ -59,7 +62,7 @@ class PSTTableItem { public long getLongValue() { if ( this.data.length > 0 ) { - return PSTObject.convertLittleEndianBytesToLong(data); + return PSTUtils.convertLittleEndianBytesToLong(data); } return -1; } @@ -134,7 +137,7 @@ public String getStringValue(int stringType) { } public String toString() { - String ret = PSTFile.getPropertyDescription(entryType, entryValueType); + String ret = PSTSource.getPropertyDescription(entryType, entryValueType); if ( entryValueType == 0x000B ) { @@ -153,7 +156,7 @@ public String toString() { return ret + "no data"; } if ( data.length == 8 ) { - long l = PSTObject.convertLittleEndianBytesToLong(data, 0, 8); + long l = PSTUtils.convertLittleEndianBytesToLong(data, 0, 8); return String.format("%s0x%016X (%d)", ret, l, l); } else { return String.format("%s invalid data length: %d", ret, data.length); @@ -162,10 +165,10 @@ public String toString() { if ( entryValueType == 0x0040 ) { // It's a date... - int high = (int)PSTObject.convertLittleEndianBytesToLong(data, 4, 8); - int low = (int)PSTObject.convertLittleEndianBytesToLong(data, 0, 4); + int high = (int)PSTUtils.convertLittleEndianBytesToLong(data, 4, 8); + int low = (int)PSTUtils.convertLittleEndianBytesToLong(data, 0, 4); - Date d = PSTObject.filetimeToDate(high, low); + Date d = PSTUtils.filetimeToDate(high, low); dateFormatter.setTimeZone(utcTimeZone); return ret + dateFormatter.format(d); } diff --git a/com/pff/source/PSTRandomAccessFile.java b/com/pff/source/PSTRandomAccessFile.java new file mode 100644 index 0000000..fe4cc9f --- /dev/null +++ b/com/pff/source/PSTRandomAccessFile.java @@ -0,0 +1,57 @@ +package com.pff.source; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; + +public class PSTRandomAccessFile implements _RandomAccessPSTSource { + + RandomAccessFile raf; + + public PSTRandomAccessFile(File f) throws FileNotFoundException { + this.raf = new RandomAccessFile(f, "r"); + } + + + public PSTRandomAccessFile(String filename) throws FileNotFoundException { + this.raf = new RandomAccessFile(filename, "r"); + } + + + + @Override + public void close() throws IOException { + this.raf.close(); + } + + + @Override + public void seek(long pos) throws IOException { + this.raf.seek(pos); + } + + + @Override + public int read() throws IOException { + return this.raf.read(); + } + + + @Override + public int read(byte[] buffer, int offset, int length) throws IOException { + return this.raf.read(buffer, offset, length); + } + + + @Override + public int read(byte[] b) throws IOException { + return this.raf.read(b); + } + + + @Override + public long position() throws IOException { + return this.raf.getFilePointer(); + } +} diff --git a/com/pff/source/PSTSource.java b/com/pff/source/PSTSource.java new file mode 100644 index 0000000..94b28a1 --- /dev/null +++ b/com/pff/source/PSTSource.java @@ -0,0 +1,918 @@ +/** + * Copyright 2010 Richard Johnson & Orin Eman + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * --- + * + * This file is part of java-libpst. + * + * java-libpst is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * java-libpst is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with java-libpst. If not, see . + * + */ +package com.pff.source; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Properties; +import java.util.UUID; + +import com.pff.PSTUtils; +import com.pff.exceptions.PSTException; +import com.pff.objects.PSTFolder; +import com.pff.objects.PSTMessageStore; +import com.pff.parsing.DescriptorIndexNode; +import com.pff.parsing.OffsetIndexItem; +import com.pff.parsing.PSTDescriptorItem; +import com.pff.parsing.PSTNodeInputStream; +import com.pff.parsing.tables.PSTTableBC; +import com.pff.parsing.tables.PSTTableBCItem; +import com.pff.parsing.tables.PSTTableItem; + +/** + * PSTFile is the containing class that allows you to access items within a .pst file. + * Start here, get the root of the folders and work your way down through your items. + * @author Richard Johnson + */ +public class PSTSource { + + public static final int ENCRYPTION_TYPE_NONE = 0; + public static final int ENCRYPTION_TYPE_COMPRESSIBLE = 1; + + private static final int MESSAGE_STORE_DESCRIPTOR_IDENTIFIER = 33; + private static final int ROOT_FOLDER_DESCRIPTOR_IDENTIFIER = 290; + + public static final int PST_TYPE_ANSI = 14; + protected static final int PST_TYPE_ANSI_2 = 15; + public static final int PST_TYPE_UNICODE = 23; + + // Known GUIDs + // Local IDs first + public static final int PS_PUBLIC_STRINGS = 0; + public static final int PSETID_Common = 1; + public static final int PSETID_Address = 2; + public static final int PS_INTERNET_HEADERS = 3; + public static final int PSETID_Appointment = 4; + public static final int PSETID_Meeting = 5; + public static final int PSETID_Log = 6; + public static final int PSETID_Messaging = 7; + public static final int PSETID_Note = 8; + public static final int PSETID_PostRss = 9; + public static final int PSETID_Task = 10; + public static final int PSETID_UnifiedMessaging = 11; + public static final int PS_MAPI = 12; + public static final int PSETID_AirSync = 13; + public static final int PSETID_Sharing = 14; + + // Now the string guids + private static final String guidStrings[] = + { "00020329-0000-0000-C000-000000000046", + "00062008-0000-0000-C000-000000000046", + "00062004-0000-0000-C000-000000000046", + "00020386-0000-0000-C000-000000000046", + "00062002-0000-0000-C000-000000000046", + "6ED8DA90-450B-101B-98DA-00AA003F1305", + "0006200A-0000-0000-C000-000000000046", + "41F28F13-83F4-4114-A584-EEDB5A6B0BFF", + "0006200E-0000-0000-C000-000000000046", + "00062041-0000-0000-C000-000000000046", + "00062003-0000-0000-C000-000000000046", + "4442858E-A9E3-4E80-B900-317A210CC15B", + "00020328-0000-0000-C000-000000000046", + "71035549-0739-4DCB-9163-00F0580DBBDF", + "00062040-0000-0000-C000-000000000046" }; + + private HashMap guidMap = new HashMap(); + + // the type of encryption the files uses. + private int encryptionType = 0; + + // our all important tree. + private LinkedHashMap> childrenDescriptorTree = null; + + private HashMap nameToId = new HashMap(); + private HashMap stringToId = new HashMap(); + private static HashMap idToName = new HashMap(); + private HashMap idToString = new HashMap(); + private byte[] guids = null; + + _RandomAccessPSTSource in; + + int itemCount=0; + + /** + * constructor + * @param fileName + * @throws FileNotFoundException + * @throws PSTException + * @throws IOException + */ + public PSTSource(_RandomAccessPSTSource in) + throws FileNotFoundException, PSTException, IOException + { + // attempt to open the file. + this.in = in; + + // get the first 4 bytes, should be !BDN + try { + byte[] temp = new byte[4]; + in.read(temp); + String strValue = new String(temp); + if (!strValue.equals("!BDN")) { + throw new PSTException("Invalid file header: "+strValue+", expected: !BDN"); + } + + // make sure we are using a supported version of a PST... + byte[] fileTypeBytes = new byte[2]; + in.seek(10); //seekStream(in, 10); // + in.read(fileTypeBytes); + // ANSI file types can be 14 or 15: + if (fileTypeBytes[0] == PSTSource.PST_TYPE_ANSI_2) { + fileTypeBytes[0] = PSTSource.PST_TYPE_ANSI; + } + if (fileTypeBytes[0] != PSTSource.PST_TYPE_ANSI && + fileTypeBytes[0] != PSTSource.PST_TYPE_UNICODE) + { + throw new PSTException("Unrecognised PST File version: "+fileTypeBytes[0]); + } + this.pstFileType = fileTypeBytes[0]; + + // make sure encryption is turned off at this stage... + if (this.getPSTFileType() == PST_TYPE_ANSI) { + in.seek(461); + } else { + in.seek(513); + } + encryptionType = in.read(); + if (encryptionType == 0x02) { + throw new PSTException("Only unencrypted and compressable PST files are supported at this time"); + } + + // build out name to id map. + processNameToIdMap(in); + + } catch (IOException err) { + throw new PSTException("Unable to read PST Sig", err); + } + + } + + private int pstFileType = 0; + public int getPSTFileType() { + return pstFileType; + } + + /** + * read the name-to-id map from the file and load it in + * @param in + * @throws IOException + * @throws PSTException + */ + private void processNameToIdMap(_RandomAccessPSTSource in) + throws IOException, PSTException + { + + // Create our guid map + for ( int i = 0; i < guidStrings.length; ++i ) { + UUID uuid = UUID.fromString(guidStrings[i]); + guidMap.put(uuid, i); +/* + System.out.printf("guidMap[{%s}] = %d\n", uuid.toString(), i); +/**/ + } + + // process the name to id map + DescriptorIndexNode nameToIdMapDescriptorNode = (getDescriptorIndexNode(97)); + //nameToIdMapDescriptorNode.readData(this); + + // get the descriptors if we have them + HashMap localDescriptorItems = null; + if (nameToIdMapDescriptorNode.localDescriptorsOffsetIndexIdentifier != 0) { + //PSTDescriptor descriptor = new PSTDescriptor(this, nameToIdMapDescriptorNode.localDescriptorsOffsetIndexIdentifier); + //localDescriptorItems = descriptor.getChildren(); + localDescriptorItems = this.getPSTDescriptorItems(nameToIdMapDescriptorNode.localDescriptorsOffsetIndexIdentifier); + } + + // process the map + //PSTTableBC bcTable = new PSTTableBC(nameToIdMapDescriptorNode.dataBlock.data, nameToIdMapDescriptorNode.dataBlock.blockOffsets); + OffsetIndexItem off = this.getOffsetIndexNode(nameToIdMapDescriptorNode.dataOffsetIndexIdentifier); + PSTNodeInputStream nodein = new PSTNodeInputStream(this, off); + byte[] tmp = new byte[1024]; + nodein.read(tmp); + PSTTableBC bcTable = new PSTTableBC(nodein); + + HashMap tableItems = (bcTable.getItems()); + // Get the guids + PSTTableBCItem guidEntry = tableItems.get(2); // PidTagNameidStreamGuid + guids = getData(guidEntry, localDescriptorItems); + int nGuids = guids.length / 16; + UUID[] uuidArray = new UUID[nGuids]; + int[] uuidIndexes = new int[nGuids]; + int offset = 0; + for ( int i = 0; i < nGuids; ++i ) { + long mostSigBits = (PSTUtils.convertLittleEndianBytesToLong(guids, offset, offset+4) << 32) | + (PSTUtils.convertLittleEndianBytesToLong(guids, offset+4, offset+6) << 16) | + PSTUtils.convertLittleEndianBytesToLong(guids, offset+6, offset+8); + long leastSigBits = PSTUtils.convertBigEndianBytesToLong(guids, offset+8, offset+16); + uuidArray[i] = new UUID(mostSigBits, leastSigBits); + if ( guidMap.containsKey(uuidArray[i]) ) { + uuidIndexes[i] = guidMap.get(uuidArray[i]); + } else { + uuidIndexes[i] = -1; // We don't know this guid + } +/* + System.out.printf("uuidArray[%d] = {%s},%d\n", i, uuidArray[i].toString(), uuidIndexes[i]); +/**/ + offset += 16; + } + + // if we have a reference to an internal descriptor + PSTTableBCItem mapEntries = tableItems.get(3); // + byte[] nameToIdByte = getData(mapEntries, localDescriptorItems); + + PSTTableBCItem stringMapEntries = tableItems.get(4); // + byte[] stringNameToIdByte = getData(stringMapEntries, localDescriptorItems); + + // process the entries + for (int x = 0; x+8 < nameToIdByte.length; x += 8) { + int dwPropertyId = (int)PSTUtils.convertLittleEndianBytesToLong(nameToIdByte, x, x+4); + int wGuid = (int)PSTUtils.convertLittleEndianBytesToLong(nameToIdByte, x+4, x+6); + int wPropIdx = ((int)PSTUtils.convertLittleEndianBytesToLong(nameToIdByte, x+6, x+8)); + + if ( (wGuid & 0x0001) == 0 ) { + wPropIdx += 0x8000; + wGuid >>= 1; + int guidIndex; + if ( wGuid == 1 ) { + guidIndex = PS_MAPI; + } else if ( wGuid == 2 ) { + guidIndex = PS_PUBLIC_STRINGS; + } else { + guidIndex = uuidIndexes[wGuid-3]; + } + nameToId.put((long)dwPropertyId | ((long)guidIndex << 32), wPropIdx); + idToName.put(wPropIdx, (long)dwPropertyId); +/* + System.out.printf("0x%08X:%04X, 0x%08X\n", dwPropertyId, guidIndex, wPropIdx); +/**/ + } else { + // else the identifier is a string + // dwPropertyId becomes thHke byte offset into the String stream in which the string name of the property is stored. + int len = (int)PSTUtils.convertLittleEndianBytesToLong( + stringNameToIdByte, + dwPropertyId, + dwPropertyId+4 + ); + byte[] keyByteValue = new byte[len]; + System.arraycopy(stringNameToIdByte, dwPropertyId+4, keyByteValue, 0, keyByteValue.length); + wPropIdx += 0x8000; + String key = new String(keyByteValue, "UTF-16LE"); + stringToId.put(key, wPropIdx); + idToString.put(wPropIdx, key); + /* + if (wPropIdx == 32784) { + System.out.println("here!" + dwPropertyId); + System.out.println(key); + //System.out.println(32784 - 0x8000); + } + */ + } + } + } + + + private byte [] getData(PSTTableItem item, HashMap localDescriptorItems) + throws IOException, PSTException + { + if ( item.data.length != 0 ) { + return item.data; + } + + if ( localDescriptorItems == null ) { + throw new PSTException("External reference but no localDescriptorItems in PSTFile.getData()"); + } + + if ( item.entryValueType != 0x0102 ) { + throw new PSTException("Attempting to get non-binary data in PSTFile.getData()"); + } + + PSTDescriptorItem mapDescriptorItem = localDescriptorItems.get(item.entryValueReference); + if (mapDescriptorItem == null) { + throw new PSTException ("not here "+item.entryValueReference + "\n"+localDescriptorItems.keySet()); + } + return mapDescriptorItem.getData(); + } + + public int getNameToIdMapItem(int key, int propertySetIndex) + { + long lKey = ((long)propertySetIndex << 32) | (long)key; + Integer i = nameToId.get(lKey); + if ( i == null ) + { + return -1; + } + return i; + } + public int getPublicStringToIdMapItem(String key) + { + Integer i = this.stringToId.get(key); + if (i == null) { + return -1; + } + return i; + } + + + static long getNameToIdMapKey(int id) + //throws PSTException + { + Long i = idToName.get(id); + if ( i == null ) + { + //throw new PSTException("Name to Id mapping not found"); + return -1; + } + return i; + } + + + + static private Properties propertyInternetCodePages = null; + static private boolean bCPFirstTime = true; + public static String getInternetCodePageCharset(int propertyId) { + if ( bCPFirstTime ) { + bCPFirstTime = false; + propertyInternetCodePages = new Properties(); + try { + InputStream propertyStream = PSTSource.class.getResourceAsStream("/InternetCodepages.txt"); + if ( propertyStream != null ) { + propertyInternetCodePages.load(propertyStream); + } else { + propertyInternetCodePages = null; + } + } catch (FileNotFoundException e) { + propertyInternetCodePages = null; + e.printStackTrace(); + } catch (IOException e) { + propertyInternetCodePages = null; + e.printStackTrace(); + } + } + if ( propertyInternetCodePages != null ) { + return propertyInternetCodePages.getProperty(propertyId+""); + } + return null; + } + + + static private Properties propertyNames = null; + static private boolean bFirstTime = true; + + static String getPropertyName(int propertyId, boolean bNamed) { + if ( bFirstTime ) { + bFirstTime = false; + propertyNames = new Properties(); + try { + InputStream propertyStream = PSTSource.class.getResourceAsStream("/PropertyNames.txt"); + if ( propertyStream != null ) { + propertyNames.load(propertyStream); + } else { + propertyNames = null; + } + } catch (FileNotFoundException e) { + propertyNames = null; + e.printStackTrace(); + } catch (IOException e) { + propertyNames = null; + e.printStackTrace(); + } + } + + if ( propertyNames != null ) { + String key = String.format((bNamed ? "%08X" : "%04X"), propertyId); + return propertyNames.getProperty(key); + } + + return null; + } + + + + public static String getPropertyDescription(int entryType, int entryValueType) { + String ret = ""; + if ( entryType < 0x8000 ) { + String name = PSTSource.getPropertyName(entryType, false); + if ( name != null ) { + ret = String.format("%s:%04X: ", name, entryValueType); + } else { + ret = String.format("0x%04X:%04X: ", entryType, entryValueType); + } + } else { + long type = PSTSource.getNameToIdMapKey(entryType); + if ( type == -1 ) { + ret = String.format("0xFFFF(%04X):%04X: ", entryType, entryValueType); + } else { + String name = PSTSource.getPropertyName((int)type, true); + if ( name != null ) { + ret = String.format("%s(%04X):%04X: ", name, entryType, entryValueType); + } else { + ret = String.format("0x%04X(%04X):%04X: ", type, entryType, entryValueType); + } + } + } + return ret; + } + + /** + * destructor just closes the file handle... + */ + @Override + protected void finalize() throws IOException { + in.close(); + } + + /** + * get the type of encryption the file uses + * @return encryption type used in the PST File + */ + public int getEncryptionType() { + return this.encryptionType; + } + + /** + * get the handle to the file we are currently accessing + */ + /*public RandomAccessFile getFileHandle() { + return this.in; + }*/ + + + /** + * get the message store of the PST file. + * Note that this doesn't really have much information, better to look under the root folder + * @throws PSTException + * @throws IOException + */ + public PSTMessageStore getMessageStore() throws PSTException, IOException { + DescriptorIndexNode messageStoreDescriptor = getDescriptorIndexNode(MESSAGE_STORE_DESCRIPTOR_IDENTIFIER); + return new PSTMessageStore(this, messageStoreDescriptor); + } + + /** + * get the root folder for the PST file. + * You should find all of your data under here... + * @throws PSTException + * @throws IOException + */ + public PSTFolder getRootFolder() throws PSTException, IOException { + DescriptorIndexNode rootFolderDescriptor = getDescriptorIndexNode(ROOT_FOLDER_DESCRIPTOR_IDENTIFIER); + PSTFolder output = new PSTFolder(this, rootFolderDescriptor); + return output; + } + + + + public PSTNodeInputStream readLeaf(long bid) throws IOException, PSTException { + //PSTFileBlock ret = null; + //PSTNodeInputStream ret = null; + + // get the index node for the descriptor index + OffsetIndexItem offsetItem = getOffsetIndexNode(bid); + return new PSTNodeInputStream(this, offsetItem); + + } + + + public int getLeafSize(long bid) throws IOException, PSTException { + OffsetIndexItem offsetItem = getOffsetIndexNode(bid); + + // Internal block? + if ( (offsetItem.getIndexIdentifier() & 0x02) == 0 ) { + // No, return the raw size + return offsetItem.getSize(); + } + + // we only need the first 8 bytes + byte[] data = new byte[8]; + in.seek(offsetItem.getFileOffset()); + in.read(data); + + // we are an array, get the sum of the sizes... + return (int)PSTUtils.convertLittleEndianBytesToLong(data, 4, 8); + } + + /** + * Read a file offset from the file + * PST Files have this tendency to store file offsets (pointers) in 8 little endian bytes. + * Convert this to a long for seeking to. + * @param in handle for PST file + * @param startOffset where to read the 8 bytes from + * @return long representing the read location + * @throws IOException + */ + protected long extractLEFileOffset(long startOffset) + throws IOException + { + long offset = 0; + if (this.getPSTFileType() == PSTSource.PST_TYPE_ANSI) { + in.seek(startOffset); + byte[] temp = new byte[4]; + in.read(temp); + offset |= temp[3] & 0xff; + offset <<= 8; + offset |= temp[2] & 0xff; + offset <<= 8; + offset |= temp[1] & 0xff; + offset <<= 8; + offset |= temp[0] & 0xff; + } else { + in.seek(startOffset); + byte[] temp = new byte[8]; + in.read(temp); + offset = temp[7] & 0xff; + long tmpLongValue; + for (int x = 6; x >= 0; x--) { + offset = offset << 8; + tmpLongValue = (long)temp[x] & 0xff; + offset |= tmpLongValue; + } + } + + return offset; + } + + /** + * Generic function used by getOffsetIndexNode and getDescriptorIndexNode for navigating the PST B-Trees + * @param in + * @param index + * @param descTree + * @return + * @throws IOException + * @throws PSTException + */ + private byte[] findBtreeItem(_RandomAccessPSTSource in, long index, boolean descTree) + throws IOException, PSTException + { + + long btreeStartOffset; + // first find the starting point for the offset index + if (this.getPSTFileType() == PST_TYPE_ANSI) { + btreeStartOffset = this.extractLEFileOffset(196); + if (descTree) { + btreeStartOffset = this.extractLEFileOffset(188); + } + } else { + btreeStartOffset = this.extractLEFileOffset(240); + if (descTree) { + btreeStartOffset = this.extractLEFileOffset(224); + } + } + + // okay, what we want to do is navigate the tree until you reach the bottom.... + // try and read the index b-tree + byte[] temp = new byte[2]; + if (this.getPSTFileType() == PST_TYPE_ANSI) { + in.seek(btreeStartOffset+500); + } else { + in.seek(btreeStartOffset+496); + } + in.read(temp); + while ((temp[0] == 0xffffff80 && temp[1] == 0xffffff80 && !descTree) || + (temp[0] == 0xffffff81 && temp[1] == 0xffffff81 && descTree)) + { + + // get the rest of the data.... + byte[] branchNodeItems; + if (this.getPSTFileType() == PST_TYPE_ANSI) { + branchNodeItems = new byte[496]; + } else { + branchNodeItems = new byte[488]; + } + in.seek(btreeStartOffset); + in.read(branchNodeItems); + + int numberOfItems = in.read(); + in.read(); // maxNumberOfItems + in.read(); // itemSize + int levelsToLeaf = in.read(); + + if (levelsToLeaf > 0) { + boolean found = false; + for (int x = 0; x < numberOfItems; x++) { + if (this.getPSTFileType() == PST_TYPE_ANSI) { + long indexIdOfFirstChildNode = extractLEFileOffset(btreeStartOffset + (x * 12)); + if (indexIdOfFirstChildNode > index) { + // get the address for the child first node in this group + btreeStartOffset = extractLEFileOffset(btreeStartOffset+((x-1) * 12)+8); + in.seek(btreeStartOffset+500); + in.read(temp); + found = true; + break; + } + } else { + long indexIdOfFirstChildNode = extractLEFileOffset(btreeStartOffset + (x * 24)); + if (indexIdOfFirstChildNode > index) { + // get the address for the child first node in this group + btreeStartOffset = extractLEFileOffset(btreeStartOffset+((x-1) * 24)+16); + in.seek(btreeStartOffset+496); + in.read(temp); + found = true; + break; + } + } + } + if (!found) { + // it must be in the very last branch... + if (this.getPSTFileType() == PST_TYPE_ANSI) { + btreeStartOffset = extractLEFileOffset(btreeStartOffset+((numberOfItems-1) * 12)+8); + in.seek(btreeStartOffset+500); + in.read(temp); + } else { + btreeStartOffset = extractLEFileOffset(btreeStartOffset+((numberOfItems-1) * 24)+16); + in.seek(btreeStartOffset+496); + in.read(temp); + } + } + } + else + { + // we are at the bottom of the tree... + // we want to get our file offset! + for (int x = 0; x < numberOfItems; x++) { + + if (this.getPSTFileType() == PSTSource.PST_TYPE_ANSI) { + if (descTree) + { + // The 32-bit descriptor index b-tree leaf node item + in.seek(btreeStartOffset + (x * 16)); + temp = new byte[4]; + in.read(temp); + if (PSTUtils.convertLittleEndianBytesToLong(temp) == index) { + // give me the offset index please! + in.seek(btreeStartOffset + (x * 16)); + temp = new byte[16]; + in.read(temp); + return temp; + } + } + else + { + // The 32-bit (file) offset index item + long indexIdOfFirstChildNode = extractLEFileOffset(btreeStartOffset + (x * 12)); + + if (indexIdOfFirstChildNode == index) { + // we found it!!!! OMG + //System.out.println("item found as item #"+x); + in.seek(btreeStartOffset + (x * 12)); + + temp = new byte[12]; + in.read(temp); + return temp; + } + } + } else { + if (descTree) + { + // The 64-bit descriptor index b-tree leaf node item + in.seek(btreeStartOffset + (x * 32)); + + temp = new byte[4]; + in.read(temp); + if (PSTUtils.convertLittleEndianBytesToLong(temp) == index) { + // give me the offset index please! + in.seek(btreeStartOffset + (x * 32)); + temp = new byte[32]; + in.read(temp); + return temp; + } + } + else + { + // The 64-bit (file) offset index item + long indexIdOfFirstChildNode = extractLEFileOffset(btreeStartOffset + (x * 24)); + + if (indexIdOfFirstChildNode == index) { + // we found it!!!! OMG + //System.out.println("item found as item #"+x); + in.seek(btreeStartOffset + (x * 24)); + + temp = new byte[24]; + in.read(temp); + return temp; + } + } + } + } + throw new PSTException("Unable to find "+index); + } + } + + throw new PSTException("Unable to find node: "+index); + } + + /** + * navigate the internal descriptor B-Tree and find a specific item + * @param in + * @param identifier + * @return the descriptor node for the item + * @throws IOException + * @throws PSTException + */ + public DescriptorIndexNode getDescriptorIndexNode(long identifier) + throws IOException, PSTException + { + return new DescriptorIndexNode(findBtreeItem(in, identifier, true), this.getPSTFileType()); + } + + /** + * navigate the internal index B-Tree and find a specific item + * @param in + * @param identifier + * @return the offset index item + * @throws IOException + * @throws PSTException + */ + public OffsetIndexItem getOffsetIndexNode(long identifier) throws IOException, PSTException { + return new OffsetIndexItem(findBtreeItem(in, identifier, false), this.getPSTFileType()); + } + + + /** + * parse a PSTDescriptor and get all of its items + */ + public HashMap getPSTDescriptorItems(long localDescriptorsOffsetIndexIdentifier) + throws PSTException, IOException + { + return this.getPSTDescriptorItems(this.readLeaf(localDescriptorsOffsetIndexIdentifier)); + } + HashMap getPSTDescriptorItems(PSTNodeInputStream in) + throws PSTException, IOException + { + // make sure the signature is correct + in.seek(0); + int sig = in.read(); + if (sig != 0x2) { + throw new PSTException("Unable to process descriptor node, bad signature: "+sig); + } + + HashMap output = new HashMap(); + int numberOfItems = (int)in.seekAndReadLong(2, 2); + int offset; + if (this.getPSTFileType() == PSTSource.PST_TYPE_ANSI) { + offset = 4; + } else { + offset = 8; + } + + byte[] data = new byte[(int)in.length()]; + in.seek(0); + in.read(data); + + for (int x = 0; x < numberOfItems; x++) { + PSTDescriptorItem item = new PSTDescriptorItem(data, offset, this); + output.put(item.getDescriptorIdentifier(), item); + if (this.getPSTFileType() == PSTSource.PST_TYPE_ANSI) { + offset += 12; + } else { + offset += 24; + } + } + + return output; + } + + /** + * Build the children descriptor tree + * This goes through the entire descriptor B-Tree and adds every item to the childrenDescriptorTree. + * This is used as fallback when the nodes that list file contents are broken. + * @param in + * @throws IOException + * @throws PSTException + */ + public LinkedHashMap> getChildDescriptorTree() + throws IOException, PSTException + { + if (this.childrenDescriptorTree == null) { + long btreeStartOffset = 0; + if (this.getPSTFileType() == PST_TYPE_ANSI) { + btreeStartOffset = this.extractLEFileOffset(188); + } else { + btreeStartOffset = this.extractLEFileOffset(224); + } + this.childrenDescriptorTree = new LinkedHashMap>(); + processDescriptorBTree(btreeStartOffset); + } + return this.childrenDescriptorTree; + } + + /** + * Recursive function for building the descriptor tree, used by buildDescriptorTree + * @param in + * @param btreeStartOffset + * @throws IOException + * @throws PSTException + */ + private void processDescriptorBTree(long btreeStartOffset) + throws IOException, PSTException + { + byte[] temp = new byte[2]; + if (this.getPSTFileType() == PST_TYPE_ANSI) { + in.seek(btreeStartOffset+500); + } else { + in.seek(btreeStartOffset+496); + } + in.read(temp); + + if ((temp[0] == 0xffffff81 && temp[1] == 0xffffff81)) { + + if (this.getPSTFileType() == PST_TYPE_ANSI) { + in.seek(btreeStartOffset+496); + } else { + in.seek(btreeStartOffset+488); + } + + int numberOfItems = in.read(); + in.read(); // maxNumberOfItems + in.read(); // itemSize + int levelsToLeaf = in.read(); + + if (levelsToLeaf > 0) { + for (int x = 0; x < numberOfItems; x++) { + if (this.getPSTFileType() == PST_TYPE_ANSI) { + long branchNodeItemStartIndex = (btreeStartOffset + (12*x)); + long nextLevelStartsAt = this.extractLEFileOffset(branchNodeItemStartIndex+8); + processDescriptorBTree(nextLevelStartsAt); + } else { + long branchNodeItemStartIndex = (btreeStartOffset + (24*x)); + long nextLevelStartsAt = this.extractLEFileOffset(branchNodeItemStartIndex+16); + processDescriptorBTree(nextLevelStartsAt); + } + } + } else { + for (int x = 0; x < numberOfItems; x++) { + // The 64-bit descriptor index b-tree leaf node item give me the offset index please! + if (this.getPSTFileType() == PSTSource.PST_TYPE_ANSI) { + in.seek(btreeStartOffset + (x * 16)); + temp = new byte[16]; + in.read(temp); + } else { + in.seek(btreeStartOffset + (x * 32)); + temp = new byte[32]; + in.read(temp); + } + + DescriptorIndexNode tempNode = new DescriptorIndexNode(temp, this.getPSTFileType()); + + // we don't want to be children of ourselves... + if (tempNode.parentDescriptorIndexIdentifier == tempNode.descriptorIdentifier) { + // skip! + } else if (childrenDescriptorTree.containsKey(tempNode.parentDescriptorIndexIdentifier)) { + // add this entry to the existing list of children + LinkedList children = childrenDescriptorTree.get(tempNode.parentDescriptorIndexIdentifier); + children.add(tempNode); + } else { + // create a new entry and add this one to that + LinkedList children = new LinkedList(); + children.add(tempNode); + childrenDescriptorTree.put(tempNode.parentDescriptorIndexIdentifier, children); + } + this.itemCount++; + } + } + } else { + PSTUtils.printHexFormatted(temp, true); + throw new PSTException("Unable to read descriptor node, is not a descriptor"); + } + } + + + public _RandomAccessPSTSource getRASource() { + return this.in; + } + + +} diff --git a/com/pff/source/_RandomAccessPSTSource.java b/com/pff/source/_RandomAccessPSTSource.java new file mode 100644 index 0000000..8fa11d1 --- /dev/null +++ b/com/pff/source/_RandomAccessPSTSource.java @@ -0,0 +1,22 @@ +package com.pff.source; + +import java.io.Closeable; +import java.io.IOException; + +public interface _RandomAccessPSTSource extends Closeable { + + + public void seek(long pos) throws IOException; + + public int read() throws IOException; + + public int read(byte[] buffer, int offset, int length) throws IOException; + + public int read( byte[] b ) throws IOException; + + public long position() throws IOException; + + + + +} diff --git a/deprecated/LZFu.java b/deprecated/LZFu.java new file mode 100644 index 0000000..48f387e --- /dev/null +++ b/deprecated/LZFu.java @@ -0,0 +1,49 @@ +/* + * Copyright 2010 Richard Johnson & Orin Eman + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * --- + * + * This file is part of java-libpst. + * + * java-libpst is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * java-libpst is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with java-libpst. If not, see . + * + */ + +package com.pff; + +import java.io.UnsupportedEncodingException; + +import com.pff.exceptions.PSTException; + +/** + * An implementation of the LZFu algorithm to decompress RTF content + * @author Richard Johnson + */ +public class LZFu { + + + +} diff --git a/com/pff/PSTFile.java b/deprecated/PSTFile.java similarity index 93% rename from com/pff/PSTFile.java rename to deprecated/PSTFile.java index 64e396e..596e5f6 100644 --- a/com/pff/PSTFile.java +++ b/deprecated/PSTFile.java @@ -135,7 +135,8 @@ public PSTFile(File fileName) // make sure we are using a supported version of a PST... byte[] fileTypeBytes = new byte[2]; - in.seek(10); + //in.seek(10); + seek(10); in.read(fileTypeBytes); // ANSI file types can be 14 or 15: if (fileTypeBytes[0] == PSTFile.PST_TYPE_ANSI_2) { @@ -150,9 +151,11 @@ public PSTFile(File fileName) // make sure encryption is turned off at this stage... if (this.getPSTFileType() == PST_TYPE_ANSI) { - in.seek(461); + //in.seek(461); + seek(461); } else { - in.seek(513); + //in.seek(513); + seek(513); } encryptionType = in.readByte(); if (encryptionType == 0x02) { @@ -407,6 +410,7 @@ static String getPropertyName(int propertyId, boolean bNamed) { return null; } + static String getPropertyDescription(int entryType, int entryValueType) { String ret = ""; if ( entryType < 0x8000 ) { @@ -492,7 +496,7 @@ PSTNodeInputStream readLeaf(long bid) throws IOException, PSTException { //PSTFileBlock ret = null; - PSTNodeInputStream ret = null; + //PSTNodeInputStream ret = null; // get the index node for the descriptor index OffsetIndexItem offsetItem = getOffsetIndexNode(bid); @@ -514,7 +518,8 @@ public int getLeafSize(long bid) // we only need the first 8 bytes byte[] data = new byte[8]; - in.seek(offsetItem.fileOffset); + //in.seek(offsetItem.fileOffset); + seek(offsetItem.fileOffset); in.read(data); // we are an array, get the sum of the sizes... @@ -535,7 +540,8 @@ protected long extractLEFileOffset(long startOffset) { long offset = 0; if (this.getPSTFileType() == PSTFile.PST_TYPE_ANSI) { - in.seek(startOffset); + //in.seek(startOffset); + seek(startOffset); byte[] temp = new byte[4]; in.read(temp); offset |= temp[3] & 0xff; @@ -546,7 +552,8 @@ protected long extractLEFileOffset(long startOffset) offset <<= 8; offset |= temp[0] & 0xff; } else { - in.seek(startOffset); + //in.seek(startOffset); + seek(startOffset); byte[] temp = new byte[8]; in.read(temp); offset = temp[7] & 0xff; @@ -570,7 +577,7 @@ protected long extractLEFileOffset(long startOffset) * @throws IOException * @throws PSTException */ - private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) + private byte[] findBtreeItem(/*RandomAccessFile in, */long index, boolean descTree) throws IOException, PSTException { @@ -592,9 +599,11 @@ private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) // try and read the index b-tree byte[] temp = new byte[2]; if (this.getPSTFileType() == PST_TYPE_ANSI) { - in.seek(btreeStartOffset+500); + //in.seek(btreeStartOffset+500); + seek(btreeStartOffset+500); } else { - in.seek(btreeStartOffset+496); + //in.seek(btreeStartOffset+496); + seek(btreeStartOffset+496); } in.read(temp); while ((temp[0] == 0xffffff80 && temp[1] == 0xffffff80 && !descTree) || @@ -608,7 +617,8 @@ private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) } else { branchNodeItems = new byte[488]; } - in.seek(btreeStartOffset); + //in.seek(btreeStartOffset); + seek(btreeStartOffset); in.read(branchNodeItems); int numberOfItems = in.read(); @@ -624,7 +634,8 @@ private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) if (indexIdOfFirstChildNode > index) { // get the address for the child first node in this group btreeStartOffset = extractLEFileOffset(btreeStartOffset+((x-1) * 12)+8); - in.seek(btreeStartOffset+500); + //in.seek(btreeStartOffset+500); + seek(btreeStartOffset+500); in.read(temp); found = true; break; @@ -634,7 +645,8 @@ private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) if (indexIdOfFirstChildNode > index) { // get the address for the child first node in this group btreeStartOffset = extractLEFileOffset(btreeStartOffset+((x-1) * 24)+16); - in.seek(btreeStartOffset+496); + //in.seek(btreeStartOffset+496); + seek(btreeStartOffset+496); in.read(temp); found = true; break; @@ -645,11 +657,13 @@ private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) // it must be in the very last branch... if (this.getPSTFileType() == PST_TYPE_ANSI) { btreeStartOffset = extractLEFileOffset(btreeStartOffset+((numberOfItems-1) * 12)+8); - in.seek(btreeStartOffset+500); + //in.seek(btreeStartOffset+500); + seek(btreeStartOffset+500); in.read(temp); } else { btreeStartOffset = extractLEFileOffset(btreeStartOffset+((numberOfItems-1) * 24)+16); - in.seek(btreeStartOffset+496); + //in.seek(btreeStartOffset+496); + seek(btreeStartOffset+496); in.read(temp); } } @@ -664,12 +678,14 @@ private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) if (descTree) { // The 32-bit descriptor index b-tree leaf node item - in.seek(btreeStartOffset + (x * 16)); + //in.seek(btreeStartOffset + (x * 16)); + seek(btreeStartOffset + (x * 16)); temp = new byte[4]; in.read(temp); if (PSTObject.convertLittleEndianBytesToLong(temp) == index) { // give me the offset index please! - in.seek(btreeStartOffset + (x * 16)); + //in.seek(btreeStartOffset + (x * 16)); + seek(btreeStartOffset + (x * 16)); temp = new byte[16]; in.read(temp); return temp; @@ -683,7 +699,8 @@ private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) if (indexIdOfFirstChildNode == index) { // we found it!!!! OMG //System.out.println("item found as item #"+x); - in.seek(btreeStartOffset + (x * 12)); + //in.seek(btreeStartOffset + (x * 12)); + seek(btreeStartOffset + (x * 12)); temp = new byte[12]; in.read(temp); @@ -694,13 +711,15 @@ private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) if (descTree) { // The 64-bit descriptor index b-tree leaf node item - in.seek(btreeStartOffset + (x * 32)); + //in.seek(btreeStartOffset + (x * 32)); + seek(btreeStartOffset + (x * 32)); temp = new byte[4]; in.read(temp); if (PSTObject.convertLittleEndianBytesToLong(temp) == index) { // give me the offset index please! - in.seek(btreeStartOffset + (x * 32)); + //in.seek(btreeStartOffset + (x * 32)); + seek(btreeStartOffset + (x * 32)); temp = new byte[32]; in.read(temp); return temp; @@ -714,7 +733,8 @@ private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) if (indexIdOfFirstChildNode == index) { // we found it!!!! OMG //System.out.println("item found as item #"+x); - in.seek(btreeStartOffset + (x * 24)); + //in.seek(btreeStartOffset + (x * 24)); + seek(btreeStartOffset + (x * 24)); temp = new byte[24]; in.read(temp); @@ -741,7 +761,7 @@ private byte[] findBtreeItem(RandomAccessFile in, long index, boolean descTree) DescriptorIndexNode getDescriptorIndexNode(long identifier) throws IOException, PSTException { - return new DescriptorIndexNode(findBtreeItem(in, identifier, true), this.getPSTFileType()); + return new DescriptorIndexNode(findBtreeItem(/*in,*/ identifier, true), this.getPSTFileType()); } /** @@ -755,7 +775,7 @@ DescriptorIndexNode getDescriptorIndexNode(long identifier) OffsetIndexItem getOffsetIndexNode(long identifier) throws IOException, PSTException { - return new OffsetIndexItem(findBtreeItem(in, identifier, false), this.getPSTFileType()); + return new OffsetIndexItem(findBtreeItem(/*in,*/ identifier, false), this.getPSTFileType()); } @@ -909,4 +929,10 @@ private void processDescriptorBTree(long btreeStartOffset) } + + + private void seek(long pos) throws IOException { + System.out.println("seeking file => "+pos); + this.in.seek(pos); + } } diff --git a/example/Test.java b/example/Test.java index b95d13b..112540d 100644 --- a/example/Test.java +++ b/example/Test.java @@ -1,16 +1,23 @@ package example; -import com.pff.*; -import java.util.*; +import java.util.ArrayList; + +import com.pff.exceptions.PSTException; +import com.pff.objects.PSTFolder; +import com.pff.objects.PSTMessage; +import com.pff.source.PSTRandomAccessFile; +import com.pff.source.PSTSource; +import com.pff.source._RandomAccessPSTSource; public class Test { - public static void main(String[] args) - { + + public static void main(String[] args) { new Test(args[0]); } public Test(String filename) { try { - PSTFile pstFile = new PSTFile(filename); + _RandomAccessPSTSource raSrc = new PSTRandomAccessFile(filename); + PSTSource pstFile = new PSTSource(raSrc); System.out.println(pstFile.getMessageStore().getDisplayName()); processFolder(pstFile.getRootFolder()); } catch (Exception err) { @@ -19,9 +26,7 @@ public Test(String filename) { } int depth = -1; - public void processFolder(PSTFolder folder) - throws PSTException, java.io.IOException - { + public void processFolder(PSTFolder folder) throws PSTException, java.io.IOException { depth++; // the root folder doesn't have a display name if (depth > 0) { @@ -31,7 +36,7 @@ public void processFolder(PSTFolder folder) // go through the folders... if (folder.hasSubfolders()) { - Vector childFolders = folder.getSubFolders(); + ArrayList childFolders = folder.getSubFolders(); for (PSTFolder childFolder : childFolders) { processFolder(childFolder); } diff --git a/example/TestGui.java b/example/TestGui.java index 6672855..a945dbb 100644 --- a/example/TestGui.java +++ b/example/TestGui.java @@ -4,26 +4,62 @@ package example; -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.table.AbstractTableModel; +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; import javax.swing.JMenuItem; -import java.io.*; -import javax.swing.tree.*; - -import com.pff.*; - -import java.util.*; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.JTextPane; +import javax.swing.JTree; +import javax.swing.ListSelectionModel; +import javax.swing.WindowConstants; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.table.AbstractTableModel; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; + +import com.pff.exceptions.PSTException; +import com.pff.objects.PSTActivity; +import com.pff.objects.PSTAttachment; +import com.pff.objects.PSTContact; +import com.pff.objects.PSTFolder; +import com.pff.objects.PSTMessage; +import com.pff.objects.PSTMessageStore; +import com.pff.objects.PSTObject; +import com.pff.objects.PSTRss; +import com.pff.objects.PSTTask; +import com.pff.source.PSTRandomAccessFile; +import com.pff.source.PSTSource; /** * @author toweruser * */ public class TestGui implements ActionListener { - private PSTFile pstFile; + private PSTSource pstFile; private EmailTableModel emailTableModel; private JTextPane emailText; private JPanel emailPanel; @@ -40,7 +76,7 @@ public TestGui() throws PSTException, IOException { // attempt to open the pst file try { - /* + JFileChooser chooser = new JFileChooser(); if (chooser.showOpenDialog(f) == JFileChooser.APPROVE_OPTION) { } else { @@ -48,13 +84,12 @@ public TestGui() throws PSTException, IOException { } String filename = chooser.getSelectedFile().getCanonicalPath(); - */ - String filename = "Outlook-new.pst"; - filename = "G:\\From old Tower\\pff\\java\\Old Email.pst"; + + /*String filename = "Outlook-new.pst"; + filename = "G:\\From old Tower\\pff\\java\\Old Email.pst";*/ //filename = "RichardJohnson@sumac.uk.com - exchange.ost"; //String filename = "Outlook 32bit.pst"; - //String russian = "Узеи́р Абду́л-Гусе́йн оглы́ Гаджибе́ков (азерб. Üzeyir bəy Əbdülhüseyn oğlu Hacıbəyov; 18 сентября 1885, Агджабеди, Шушинский уезд, Елизаветпольская губерния, Российская империя — 23 ноября 1948, Баку, Азербайджанская ССР, СССР) — азербайджанский композитор, дирижёр, публицист, фельетонист, драматург и педагог, народный артист СССР (1938), дважды лауреат Сталинских премий (1941, 1946). Действительный член АН Азербайджана (1945), профессор (1940), ректор Азербайджанской государственной "; - + //System.out.println(java.nio.charset.Charset.availableCharsets()); //byte[] russianBytes = russian.getBytes("UTF-8"); @@ -62,7 +97,8 @@ public TestGui() throws PSTException, IOException { //String filename = "Outlook 32bit.pst"; //filename = "RichardJohnson@sumac.uk.com - exchange.ost"; - pstFile = new PSTFile(filename); + PSTRandomAccessFile pstRaF = new PSTRandomAccessFile(filename); + pstFile = new PSTSource(pstRaF); //pstFile = new PSTFile("RichardJohnson@sumac.uk.com - exchange.ost"); @@ -175,7 +211,9 @@ public TestGui() throws PSTException, IOException { } final JTree folderTree = new JTree(top){ - public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + private static final long serialVersionUID = 1L; + + public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { DefaultMutableTreeNode nodeValue = (DefaultMutableTreeNode)value; if (nodeValue.getUserObject() instanceof PSTFolder) { PSTFolder folderValue = (PSTFolder)nodeValue.getUserObject(); @@ -293,14 +331,14 @@ public void valueChanged(ListSelectionEvent e) { // Set the visibility as true, thereby displaying it f.setVisible(true); // f.setSize(800, 600); - f.setExtendedState(f.getExtendedState() | f.MAXIMIZED_BOTH); + f.setExtendedState(f.getExtendedState() | JFrame.MAXIMIZED_BOTH); } private void buildTree(DefaultMutableTreeNode top, PSTFolder theFolder) { // this is recursive, try and keep up. try { - Vector children = theFolder.getSubFolders(); - Iterator childrenIterator = children.iterator(); + ArrayList children = theFolder.getSubFolders(); + Iterator childrenIterator = children.iterator(); while (childrenIterator.hasNext()) { PSTFolder folder = (PSTFolder)childrenIterator.next(); @@ -429,13 +467,14 @@ public static void main(String[] args) throws PSTException, IOException { } class EmailTableModel extends AbstractTableModel { + private static final long serialVersionUID = 6414607674310021030L; PSTFolder theFolder = null; - PSTFile theFile = null; + PSTSource theFile = null; - HashMap cache = new HashMap(); + HashMap cache = new HashMap(); - public EmailTableModel(PSTFolder theFolder, PSTFile theFile) { + public EmailTableModel(PSTFolder theFolder, PSTSource theFile) { super(); this.theFolder = theFolder; @@ -527,7 +566,7 @@ public void setFolder(PSTFolder theFolder) { theFolder.moveChildCursorTo(0); this.theFolder = theFolder; - cache = new HashMap(); + cache = new HashMap(); this.fireTableDataChanged(); } diff --git a/example/TestRandomAccess.java b/example/TestRandomAccess.java new file mode 100644 index 0000000..d0fdc97 --- /dev/null +++ b/example/TestRandomAccess.java @@ -0,0 +1,15 @@ +package example; + +public class TestRandomAccess { + + public TestRandomAccess() { + + } + + + public static void main(String[] args) { + + + } + +}