Free Support Forum -

Using unique reference accessors in PSTs

I’m in the process of migrating from an open source library that reads PST files (java-libpst) to I’m able to most of what I need to do with the aspose APIs, but I’m struggling with the unique identifiers for items in a PST file.

In the PersonalStorage class, there is a method

- public MapiMessage extractMessage(StringentryId)

This method is used to extract a specific MapiMessage using a special StringentryID that is unique for every entry in the PersonalStorage (PST) file. This seems to have the same purpose as the java-libpst library’s DiscriptorIndexNode and the method

- public static PSTObject detectAndLoadPSTObject(PSTFile theFile, long descriptorIndexNode)

Since the underlying file format is unlikely to have two unique identifiers for any given object and I believe that the java-libpst is just using the unique long value in the PST file, I expect that there is a way to map one to the other.

Can you explain how the StringentryID is derived from the descriptorIndexNode? This will let me maintain compatibility between the information saved using the old java-libpst and new work we do using

Hi Steven,

Thank you for considering Aspose.Email and we are sorry for a delayed response.

Please note that Aspose.Email doesn’t use Java-libpst at its base and, hence, is not derived from the descriptorIndexNode. To get information on your requirements, I have forwarded your inquiry to our development team for having further details. We will update you here once we have any information in this regard and are thankful to you for your patience.

The investigation ticket has been logged as: NETWRKJAVA-33197 in our issue tracking system.

Understood that aspose-email does not use java-libpst. But I believe that java-libpst pulls the discrptorIndexNode straight out of the pst file so the same data is probably being used as the source of the StringentryID. Thanks for helping me understand how they map back and forth.

Hi Steven,

Thank you for your understanding.

I have forwarded your requirements to our development to assist further in this regard. As soon as we get some information, we will update you here. We appreciate your patience in this regard.

Hi Steven,

Thank you for your patience.

Please have a look at the following functions for conversion from EntryId to DescriptorIndexNode and vice versa.

static long EntryIdToDescriptorIndexNode(String entryIdString) {<o:p></o:p>

byte[] entryId = Base64.decodeBase64(entryIdString);<o:p></o:p>

return entryId[23] << 24 | entryId[22] << 16 | entryId[21] << 8 | entryId[20];<o:p></o:p>


static String DescriptorIndexNodeToEntryId(long descriptorIndexNode, byte[] recordKey) {<o:p></o:p>

byte[] result = new byte[24];<o:p></o:p>

System.arraycopy(recordKey, 0, result, 4, recordKey.length);<o:p></o:p>

byte[] descriptor = new byte[]{<o:p></o:p>

(byte) ((descriptorIndexNode & 0x000000FFL)),<o:p></o:p>

(byte) ((descriptorIndexNode & 0x0000FF00L) >>> 8),<o:p></o:p>

(byte) ((descriptorIndexNode & 0x00FF0000L) >>> 16),<o:p></o:p>

(byte) ((descriptorIndexNode & 0xFF000000L) >>> 24)<o:p></o:p>


System.arraycopy(descriptor, 0, result, 20, 4);<o:p></o:p>

return Base64.encodeBase64String(result);<o:p></o:p>


Please note that the Base64 class was taken from Apache Commons Framework at:

Here is a test function for checking the functionality of these functions:

public void test()<o:p></o:p>


String entryId = “AAAAANSPNJdBq6lNjiWVUlCW6eokACAA”;<o:p></o:p>

byte[] decodedEntryId = Base64.decodeBase64(entryId);<o:p></o:p>

byte[] recordKey = new byte[16];<o:p></o:p>

System.arraycopy(decodedEntryId, 4, recordKey, 0, 16);<o:p></o:p>

long descriptor = EntryIdToDescriptorIndexNode(entryId);<o:p></o:p>

String entryId2 = DescriptorIndexNodeToEntryId(descriptor, recordKey);<o:p></o:p>

assert entryId.equals(entryId2);<o:p></o:p>


and the Aspose.Email for Java code is as follow:

PersonalStorage pst = PersonalStorage.fromFile(“test.pst”);<o:p></o:p>



byte[] recordKey = pst.getMessageStoreProperties().get(MapiPropertyTag.PR_RECORD_KEY).getData();<o:p></o:p>


finally { if (pst != null) pst.dispose(); }

Thank you very much. This was almost perfect. The only problem I had was with this line:

return entryId[23] <<<

I needed to AND each byte with 0xFF before the shift so that bytes with the high order bit set would be handled correctly. But with that in place, I’m able to successfully connect older data accessed using the descriptor index nodes using the EntryIDs provided by aspose.

Best regards,

Hi Steven,

Thank you for the feedback.

It’s good to know that your problem is solved now. If you have any additional query/inquiry, please feel free to contact us. We will be glad to assist you further as soon as possible.

The issues you have found earlier (filed as ) have been fixed in this update. This message was posted using BugNotificationTool from Downloads module by MuzammilKhan