2.1.2 PowerPoint Document Stream

A required stream whose name MUST be "PowerPoint Document".

Let a top-level record be specified as any one of the following: DocumentContainer (section 2.4.1), MasterOrSlideContainer (section 2.5.5), HandoutContainer (section 2.5.8), SlideContainer (section 2.5.1), NotesContainer (section 2.5.6), ExOleObjStg (section 2.10.34), ExControlStg (section 2.10.37), VbaProjectStg (section 2.10.40), PersistDirectoryAtom (section 2.3.4), or UserEditAtom (section 2.3.3) record.

The contents of this stream are specified by a sequence of top-level records. Partial ordering restrictions on the record sequence are specified in the PersistDirectoryAtom and UserEditAtom records.

As container records, the DocumentContainer, MainMasterContainer (section 2.5.3), HandoutContainer (section 2.5.8), SlideContainer (section 2.5.1), and NotesContainer (section 2.5.6) records are each the root of a tree of container records and atom records. Inside any container record, other records can exist that are not explicitly listed as child records. Unknown records are identified when the recType field of the RecordHeader structure (section 2.3.1) contains a value not specified by the RecordType enumeration (section 2.13.24). These unknown records, if encountered, MUST be ignored, and MAY<1> be preserved. Unknown records can be ignored by seeking forward recLen bytes from the end of the RecordHeader structure.

Each time this stream is written, new top-level records, a user edit, can be appended to the existing stream, or the entire stream contents can be replaced with an updated sequence of top-level records. If the entire stream is not replaced, any previously existing top-level records that comprised any previous user edit, can be made obsolete by the subsequently appended top-level records that comprise the current user edit.

Let a live record be specified as any top-level record in this stream, or any descendant of a top-level record in this stream, identified by the following process:

Part 1: Construct the persist object directory.

  1. Read the CurrentUserAtom record (section 2.3.2) from the Current User Stream (section 2.1.1). All seek operations in the steps that follow this step are in the PowerPoint Document Stream.

  2. Seek, in the PowerPoint Document Stream, to the offset specified by the offsetToCurrentEdit field of the CurrentUserAtom record identified in step 1.

  3. Read the UserEditAtom record at the current offset. Let this record be a live record.

  4. Seek to the offset specified by the offsetPersistDirectory field of the UserEditAtom record identified in step 3.

  5. Read the PersistDirectoryAtom record at the current offset. Let this record be a live record.

  6. Seek to the offset specified by the offsetLastEdit field in the UserEditAtom record identified in step 3.

  7. Repeat steps 3 through 6 until offsetLastEdit is 0x00000000.

  8. Construct the complete persist object directory for this file as follows:

    1. For each PersistDirectoryAtom record previously identified in step 5, add the persist object identifier and persist object stream offset pairs to the persist object directory starting with the PersistDirectoryAtom record last identified, that is, the one closest to the beginning of the stream.

    2. Continue adding these pairs to the persist object directory for each PersistDirectoryAtom record in the reverse order that they were identified in step 5; that is, the pairs from the PersistDirectoryAtom record closest to the end of the stream are added last.

    3. When adding a new pair to the persist object directory, if the persist object identifier already exists in the persist object directory, the persist object stream offset from the new pair replaces the existing persist object stream offset for that persist object identifier.

Part 2: Identify the document persist object.

  1. Read the docPersistIdRef field of the UserEditAtom record first identified in step 3 of Part 1, that is, the UserEditAtom record closest to the end of the stream.

  2. Lookup the value of the docPersistIdRef field in the persist object directory constructed in step 8 of Part 1 to find the stream offset of a persist object.

  3. Seek to the stream offset specified in step 2.

  4. Read the DocumentContainer record at the current offset. Let this record be a live record.

Part 3: Identify the notes master slide persist object.

  1. Read the documentAtom.notesMasterPersistIdRef field of the DocumentContainer record identified in step 4 of Part 2. If the value of the field is zero, skip to step 1 of Part 4.

  2. Lookup the value of the documentAtom.notesMasterPersistIdRef field in the persist object directory constructed in step 8 of Part 1 to find the stream offset of a persist object.

  3. Seek to the stream offset specified in step 2.

  4. Read the NotesContainer record at the current offset. Let this record be a live record.

Part 4: Identify the handout master slide persist object.

  1. Read the documentAtom.handoutMasterPersistIdRef field of the DocumentContainer record identified in step 4 of Part 2. If the value of the field is zero, skip to step 1 of Part 5.

  2. Lookup the value of the documentAtom.handoutMasterPersistIdRef field in the persist object directory constructed in step 8 of Part 1 to find the stream offset of a persist object.

  3. Seek to the stream offset specified in step 2.

  4. Read the HandoutContainer record at the current offset. Let this record be a live record.

Part 5: Identify the main master slide and title master slide persist objects.

  1. Read the MasterListWithTextContainer record specified by the masterList field of the DocumentContainer record identified in step 4 of Part 2.

  2. Read the first MasterPersistAtom (section 2.4.14.2) child record of the MasterListWithTextContainer record identified in step 1.

  3. Lookup the value of the persistIdRef field of the MasterPersistAtom record previously identified in the persist object directory constructed in step 8 of Part 1 to find the stream offset of a persist object.

  4. Seek to the stream offset specified in step 3.

  5. Read the MasterOrSlideContainer record at the current offset. Let this record be a live record.

  6. Repeat steps 3 through 5 for each MasterPersistAtom child record of the MasterListWithTextContainer record identified in step 1.

Part 6: Identify the presentation slide persist objects.

  1. Read the SlideListWithTextContainer record (section 2.4.14.3), if present, specified by the slideList field of the DocumentContainer record identified in step 4 of Part 2. If not present, skip to step 1 of Part 7.

  2. Read the first SlidePersistAtom (section 2.4.14.5) child record of the SlideListWithTextContainer record identified in step 1.

  3. Lookup the value of the persistIdRef field of the SlidePersistAtom record (section 2.4.14.5) previously identified in the persist object directory constructed in step 8 of Part 1 to find the stream offset of a persist object.

  4. Seek to the stream offset specified in step 3.

  5. Read the SlideContainer record at the current offset. Let this record be a live record.

  6. Repeat steps 3 through 5 for each SlidePersistAtom child record (section 2.4.14.5) of the SlideListWithTextContainer record identified in step 1.

Part 7: Identify the notes slide persist objects.

  1. Read the NotesListWithTextContainer record (section 2.4.14.6), if present, specified by the notesList field of the DocumentContainer record identified in step 4 of Part 2. If not present, skip to step 1 of Part 8.

  2. Read the first NotesPersistAtom (section 2.4.14.7) child record of the NotesListWithTextContainer record identified in step 1.

  3. Lookup the value of the persistIdRef field of the NotesPersistAtom record previously identified in the persist object directory constructed in step 8 of Part 1 to find the stream offset of a persist object.

  4. Seek to the stream offset specified in step 3.

  5. Read the NotesContainer record at the current offset. Let this record be a live record.

  6. Repeat steps 3 through 5 for each NotesPersistAtom child record of the NotesListWithTextContainer record identified in step 1.

Part 8: Identify the ActiveX control persist objects.

  1. Read the ExObjListContainer record (section 2.10.1), if present, specified by the exObjList field of the DocumentContainer record identified in step 4 of Part 2. If not present, skip to step 1 of Part 11.

  2. Read the first, if any, ExControlContainer child record (section 2.10.10) of the ExObjListContainer record identified in step 1. If no such child record exists, skip to step 1 of Part 9.

  3. Lookup the value of the exOleObjAtom.persistIdRef field of the ExControlContainer record previously identified in the persist object directory constructed in step 8 of Part 1 to find the stream offset of a persist object.

  4. Seek to the stream offset specified in step 3.

  5. Read the ExControlStg record at the current offset. Let this record be a live record.

  6. Repeat steps 3 through 5 for each ExControlContainer child record of the ExObjListContainer record identified in step 1.

Part 9: Identify the embedded OLE object persist objects.

  1. Read the first, if any, ExOleEmbedContainer child record (section 2.10.27) of the ExObjListContainer record identified in step 1 of Part 8. If no such child record exists, skip to step 1 of Part 10.

  2. Lookup the value of the exOleObjAtom.persistIdRef field of the ExOleEmbedContainer record previously identified in the persist object directory constructed in step 8 of Part 1 to find the stream offset of a persist object.

  3. Seek to the stream offset specified in step 2.

  4. Read the ExOleObjStg record at the current offset. Let this record be a live record.

  5. Repeat steps 2 through 4 for each ExOleEmbedContainer child record of the ExObjListContainer record identified in step 1 of Part 8.

Part 10: Identify the linked OLE object persist objects.

  1. Read the first, if any, ExOleLinkContainer child record (section 2.10.29) of the ExObjListContainer record identified in step 1 of Part 8. If no such child record exists, skip to step 1 of Part 11.

  2. Lookup the value of the exOleObjAtom.persistIdRef field of the ExOleLinkContainer record previously identified in the persist object directory constructed in step 8 of Part 1 to find the stream offset of a persist object.

  3. Seek to the stream offset specified in step 2.

  4. Read the ExOleObjStg record at the current offset. Let this record be a live record.

  5. Repeat steps 2 through 4 for each ExOleLinkContainer child record of the ExObjListContainer record identified in step 1 of Part 8.

Part 11: Identify the VBA project persist object.

  1. Read the DocInfoListContainer record (section 2.4.4), if present, specified by the docInfoList field of the DocumentContainer record identified in step 4 of Part 2. If not present, skip to step 6.

  2. Read the VBAInfoContainer (section 2.4.10) child record, if present, of the DocInfoListContainer record identified in step 1. If no such child record exists, skip to step 6.

  3. Lookup the value of the vbaInfoAtom.persistIdRef field of the VBAInfoContainer record identified in step 2 in the persist object directory constructed in step 8 of Part 1 to find the stream offset of a persist object.

  4. Seek to the stream offset specified in step 3.

  5. Read the VbaProjectStg record at the current offset. Let this record be a live record.

  6. End of process. All live records have been identified.

Let a dead record be specified as any top-level record in this stream, or any descendant of a top-level record in this stream, that is not a live record.

All uses of prescriptive terminology (MAY, SHOULD, MUST, SHOULD NOT, MUST NOT) in the specification of records in the following sections apply only to live records. The contents of all dead records are undefined and MUST be ignored.