public int getLeafSize(long bid) throws IOException, PSTException { OffsetIndexItem offsetItem = getOffsetIndexNode(bid); // Internal block? if ((offsetItem.indexIdentifier & 0x02) == 0) { // No, return the raw size return offsetItem.size; } // we only need the first 8 bytes byte[] data = new byte[8]; in.seek(offsetItem.fileOffset); in.read(data); // we are an array, get the sum of the sizes... return (int) PSTObject.convertLittleEndianBytesToLong(data, 4, 8); }
/** * 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() == PSTFile.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<DescriptorIndexNode> children = childrenDescriptorTree.get(tempNode.parentDescriptorIndexIdentifier); children.add(tempNode); } else { // create a new entry and add this one to that LinkedList<DescriptorIndexNode> children = new LinkedList<DescriptorIndexNode>(); children.add(tempNode); childrenDescriptorTree.put(tempNode.parentDescriptorIndexIdentifier, children); } this.itemCount++; } } } else { PSTObject.printHexFormatted(temp, true); throw new PSTException("Unable to read descriptor node, is not a descriptor"); } }
/** * 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(RandomAccessFile 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() == PSTFile.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 (PSTObject.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 (PSTObject.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); }
/** * read the name-to-id map from the file and load it in * * @param in * @throws IOException * @throws PSTException */ private void processNameToIdMap(RandomAccessFile 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<Integer, PSTDescriptorItem> 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<Integer, PSTTableBCItem> 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 = (PSTObject.convertLittleEndianBytesToLong(guids, offset, offset + 4) << 32) | (PSTObject.convertLittleEndianBytesToLong(guids, offset + 4, offset + 6) << 16) | PSTObject.convertLittleEndianBytesToLong(guids, offset + 6, offset + 8); long leastSigBits = PSTObject.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); // process the entries for (int x = 0; x + 8 < nameToIdByte.length; x += 8) { int dwPropertyId = (int) PSTObject.convertLittleEndianBytesToLong(nameToIdByte, x, x + 4); int wGuid = (int) PSTObject.convertLittleEndianBytesToLong(nameToIdByte, x + 4, x + 6); int wPropIdx = ((int) PSTObject.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 the identifier is a string } }