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
    }
  }