import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
+import java.util.Map;
import org.apache.poi.POIDocument;
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
import org.apache.poi.hslf.record.PersistRecord;
import org.apache.poi.hslf.record.PositionDependentRecord;
import org.apache.poi.hslf.record.Record;
+import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.record.UserEditAtom;
import org.apache.poi.hslf.usermodel.ObjectData;
import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.DocumentInputStream;
+import org.apache.poi.poifs.filesystem.EntryUtils;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.LittleEndian;
* @author Nick Burch
*/
public final class HSLFSlideShow extends POIDocument {
+ public static final int UNSET_OFFSET = -1;
+
// For logging
private POILogger logger = POILogFactory.getLogger(this.getClass());
int offset = pos;
// Image signature
+ @SuppressWarnings("unused")
int signature = LittleEndian.getUShort(pictstream, pos);
pos += LittleEndian.SHORT_SIZE;
// Image type + 0xF018
}
}
+ /**
+ * This is a helper functions, which is needed for adding new position dependent records
+ * or finally write the slideshow to a file.
+ *
+ * @param os the stream to write to, if null only the references are updated
+ * @param interestingRecords a map of interesting records (PersistPtrHolder and UserEditAtom)
+ * referenced by their RecordType. Only the very last of each type will be saved to the map.
+ * May be null, if not needed.
+ * @throws IOException
+ */
+ public void updateAndWriteDependantRecords(OutputStream os, Map<RecordTypes.Type,PositionDependentRecord> interestingRecords)
+ throws IOException {
+ // For position dependent records, hold where they were and now are
+ // As we go along, update, and hand over, to any Position Dependent
+ // records we happen across
+ Hashtable<Integer,Integer> oldToNewPositions = new Hashtable<Integer,Integer>();
+
+ // First pass - figure out where all the position dependent
+ // records are going to end up, in the new scheme
+ // (Annoyingly, some powerpoint files have PersistPtrHolders
+ // that reference slides after the PersistPtrHolder)
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ for (Record record : _records) {
+ if(record instanceof PositionDependentRecord) {
+ PositionDependentRecord pdr = (PositionDependentRecord)record;
+ int oldPos = pdr.getLastOnDiskOffset();
+ int newPos = baos.size();
+ pdr.setLastOnDiskOffset(newPos);
+ if (oldPos != UNSET_OFFSET) {
+ // new records don't need a mapping, as they aren't in a relation yet
+ oldToNewPositions.put(Integer.valueOf(oldPos),Integer.valueOf(newPos));
+ }
+ }
+
+ // Dummy write out, so the position winds on properly
+ record.writeOut(baos);
+ }
+ baos = null;
+
+ // For now, we're only handling PositionDependentRecord's that
+ // happen at the top level.
+ // In future, we'll need the handle them everywhere, but that's
+ // a bit trickier
+ UserEditAtom usr = null;
+ for (Record record : _records) {
+ if (record instanceof PositionDependentRecord) {
+ // We've already figured out their new location, and
+ // told them that
+ // Tell them of the positions of the other records though
+ PositionDependentRecord pdr = (PositionDependentRecord)record;
+ pdr.updateOtherRecordReferences(oldToNewPositions);
+
+ // Grab interesting records as they come past
+ // this will only save the very last record of each type
+ RecordTypes.Type saveme = null;
+ int recordType = (int)record.getRecordType();
+ if (recordType == RecordTypes.PersistPtrIncrementalBlock.typeID) {
+ saveme = RecordTypes.PersistPtrIncrementalBlock;
+ } else if (recordType == RecordTypes.UserEditAtom.typeID) {
+ saveme = RecordTypes.UserEditAtom;
+ usr = (UserEditAtom)pdr;
+ }
+ if (interestingRecords != null && saveme != null) {
+ interestingRecords.put(saveme,pdr);
+ }
+ }
+
+ // Whatever happens, write out that record tree
+ if (os != null) {
+ record.writeOut(os);
+ }
+ }
+ // Update and write out the Current User atom
+ int oldLastUserEditAtomPos = (int)currentUser.getCurrentEditOffset();
+ Integer newLastUserEditAtomPos = oldToNewPositions.get(oldLastUserEditAtomPos);
+ if(usr == null || newLastUserEditAtomPos == null || usr.getLastOnDiskOffset() != newLastUserEditAtomPos) {
+ throw new HSLFException("Couldn't find the new location of the last UserEditAtom that used to be at " + oldLastUserEditAtomPos);
+ }
+ currentUser.setCurrentEditOffset(usr.getLastOnDiskOffset());
+ }
+
/**
* Writes out the slideshow file the is represented by an instance
* of this class.
// Write out the Property Streams
writeProperties(outFS, writtenEntries);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
// For position dependent records, hold where they were and now are
// As we go along, update, and hand over, to any Position Dependent
- // records we happen across
- Hashtable<Integer,Integer> oldToNewPositions = new Hashtable<Integer,Integer>();
-
- // First pass - figure out where all the position dependent
- // records are going to end up, in the new scheme
- // (Annoyingly, some powerpoing files have PersistPtrHolders
- // that reference slides after the PersistPtrHolder)
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- for(int i=0; i<_records.length; i++) {
- if(_records[i] instanceof PositionDependentRecord) {
- PositionDependentRecord pdr = (PositionDependentRecord)_records[i];
- int oldPos = pdr.getLastOnDiskOffset();
- int newPos = baos.size();
- pdr.setLastOnDiskOffset(newPos);
- oldToNewPositions.put(Integer.valueOf(oldPos),Integer.valueOf(newPos));
- //System.out.println(oldPos + " -> " + newPos);
- }
+ // records we happen across
+ updateAndWriteDependantRecords(baos, null);
- // Dummy write out, so the position winds on properly
- _records[i].writeOut(baos);
- }
-
- // No go back through, actually writing ourselves out
- baos.reset();
- for(int i=0; i<_records.length; i++) {
- // For now, we're only handling PositionDependentRecord's that
- // happen at the top level.
- // In future, we'll need the handle them everywhere, but that's
- // a bit trickier
- if(_records[i] instanceof PositionDependentRecord) {
- // We've already figured out their new location, and
- // told them that
- // Tell them of the positions of the other records though
- PositionDependentRecord pdr = (PositionDependentRecord)_records[i];
- pdr.updateOtherRecordReferences(oldToNewPositions);
- }
-
- // Whatever happens, write out that record tree
- _records[i].writeOut(baos);
- }
// Update our cached copy of the bytes that make up the PPT stream
_docstream = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
outFS.createDocument(bais,"PowerPoint Document");
writtenEntries.add("PowerPoint Document");
-
-
- // Update and write out the Current User atom
- int oldLastUserEditAtomPos = (int)currentUser.getCurrentEditOffset();
- Integer newLastUserEditAtomPos = (Integer)oldToNewPositions.get(Integer.valueOf(oldLastUserEditAtomPos));
- if(newLastUserEditAtomPos == null) {
- throw new HSLFException("Couldn't find the new location of the UserEditAtom that used to be at " + oldLastUserEditAtomPos);
- }
- currentUser.setCurrentEditOffset(newLastUserEditAtomPos.intValue());
currentUser.writeToFS(outFS);
writtenEntries.add("Current User");
// If requested, write out any other streams we spot
if(preserveNodes) {
- copyNodes(directory.getFileSystem(), outFS, writtenEntries);
+ EntryUtils.copyNodes(directory.getFileSystem(), outFS, writtenEntries);
}
// Send the POIFSFileSystem object out to the underlying stream
public ObjectData[] getEmbeddedObjects() {
if (_objects == null) {
List<ObjectData> objects = new ArrayList<ObjectData>();
- for (int i = 0; i < _records.length; i++) {
- if (_records[i] instanceof ExOleObjStg) {
- objects.add(new ObjectData((ExOleObjStg) _records[i]));
+ for (Record r : _records) {
+ if (r instanceof ExOleObjStg) {
+ objects.add(new ObjectData((ExOleObjStg)r));
}
}
_objects = objects.toArray(new ObjectData[objects.size()]);
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
import org.apache.poi.hslf.exceptions.HSLFException;
-import org.apache.poi.hslf.model.*;
+import org.apache.poi.hslf.model.HeadersFooters;
+import org.apache.poi.hslf.model.Hyperlink;
+import org.apache.poi.hslf.model.MovieShape;
import org.apache.poi.hslf.model.Notes;
+import org.apache.poi.hslf.model.PPFont;
+import org.apache.poi.hslf.model.Picture;
+import org.apache.poi.hslf.model.Shape;
import org.apache.poi.hslf.model.Slide;
-import org.apache.poi.hslf.record.*;
+import org.apache.poi.hslf.model.SlideMaster;
+import org.apache.poi.hslf.model.TitleMaster;
+import org.apache.poi.hslf.record.Document;
+import org.apache.poi.hslf.record.DocumentAtom;
+import org.apache.poi.hslf.record.ExAviMovie;
+import org.apache.poi.hslf.record.ExControl;
+import org.apache.poi.hslf.record.ExEmbed;
+import org.apache.poi.hslf.record.ExEmbedAtom;
+import org.apache.poi.hslf.record.ExHyperlink;
+import org.apache.poi.hslf.record.ExHyperlinkAtom;
+import org.apache.poi.hslf.record.ExMCIMovie;
+import org.apache.poi.hslf.record.ExObjList;
+import org.apache.poi.hslf.record.ExObjListAtom;
+import org.apache.poi.hslf.record.ExOleObjAtom;
+import org.apache.poi.hslf.record.ExOleObjStg;
+import org.apache.poi.hslf.record.ExVideoContainer;
+import org.apache.poi.hslf.record.FontCollection;
+import org.apache.poi.hslf.record.FontEntityAtom;
+import org.apache.poi.hslf.record.HeadersFootersContainer;
+import org.apache.poi.hslf.record.PersistPtrHolder;
+import org.apache.poi.hslf.record.PositionDependentRecord;
+import org.apache.poi.hslf.record.PositionDependentRecordContainer;
+import org.apache.poi.hslf.record.Record;
+import org.apache.poi.hslf.record.RecordContainer;
+import org.apache.poi.hslf.record.RecordTypes;
+import org.apache.poi.hslf.record.SlideListWithText;
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
+import org.apache.poi.hslf.record.SlidePersistAtom;
+import org.apache.poi.hslf.record.UserEditAtom;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.POILogFactory;
// What we're based on
private HSLFSlideShow _hslfSlideShow;
- // Low level contents, as taken from HSLFSlideShow
- private Record[] _records;
-
// Pointers to the most recent versions of the core records
// (Document, Notes, Slide etc)
private Record[] _mostRecentCoreRecords;
// Lookup between the PersitPtr "sheet" IDs, and the position
// in the mostRecentCoreRecords array
- private Hashtable<Integer,Integer> _sheetIdToCoreRecordsLookup;
+ private Map<Integer,Integer> _sheetIdToCoreRecordsLookup;
// Records that are interesting
private Document _documentRecord;
public SlideShow(HSLFSlideShow hslfSlideShow) {
// Get useful things from our base slideshow
_hslfSlideShow = hslfSlideShow;
- _records = _hslfSlideShow.getRecords();
// Handle Parent-aware Records
- for (Record record : _records) {
+ for (Record record : _hslfSlideShow.getRecords()) {
if(record instanceof RecordContainer){
RecordContainer.handleParentAwareRecords((RecordContainer)record);
}
*/
private void findMostRecentCoreRecords() {
// To start with, find the most recent in the byte offset domain
- Hashtable<Integer,Integer> mostRecentByBytes = new Hashtable<Integer,Integer>();
- for (int i = 0; i < _records.length; i++) {
- if (_records[i] instanceof PersistPtrHolder) {
- PersistPtrHolder pph = (PersistPtrHolder) _records[i];
+ Map<Integer,Integer> mostRecentByBytes = new HashMap<Integer,Integer>();
+ for (Record record : _hslfSlideShow.getRecords()) {
+ if (record instanceof PersistPtrHolder) {
+ PersistPtrHolder pph = (PersistPtrHolder) record;
// If we've already seen any of the "slide" IDs for this
// PersistPtr, remove their old positions
int[] ids = pph.getKnownSlideIDs();
- for (int j = 0; j < ids.length; j++) {
- Integer id = Integer.valueOf(ids[j]);
+ for (int id : ids) {
if (mostRecentByBytes.containsKey(id)) {
mostRecentByBytes.remove(id);
}
}
// Now, update the byte level locations with their latest values
- Hashtable<Integer,Integer> thisSetOfLocations = pph.getSlideLocationsLookup();
- for (int j = 0; j < ids.length; j++) {
- Integer id = Integer.valueOf(ids[j]);
+ Map<Integer,Integer> thisSetOfLocations = pph.getSlideLocationsLookup();
+ for (int id : ids) {
mostRecentByBytes.put(id, thisSetOfLocations.get(id));
}
}
// We'll also want to be able to turn the slide IDs into a position
// in this array
- _sheetIdToCoreRecordsLookup = new Hashtable<Integer,Integer>();
- int[] allIDs = new int[_mostRecentCoreRecords.length];
- Enumeration<Integer> ids = mostRecentByBytes.keys();
- for (int i = 0; i < allIDs.length; i++) {
- Integer id = ids.nextElement();
- allIDs[i] = id.intValue();
- }
+ _sheetIdToCoreRecordsLookup = new HashMap<Integer,Integer>();
+ Integer[] allIDs = mostRecentByBytes.keySet().toArray(new Integer[mostRecentByBytes.size()]);
Arrays.sort(allIDs);
for (int i = 0; i < allIDs.length; i++) {
- _sheetIdToCoreRecordsLookup.put(Integer.valueOf(allIDs[i]), Integer.valueOf(i));
+ _sheetIdToCoreRecordsLookup.put(allIDs[i], i);
}
// Now convert the byte offsets back into record offsets
- for (int i = 0; i < _records.length; i++) {
- if (_records[i] instanceof PositionDependentRecord) {
- PositionDependentRecord pdr = (PositionDependentRecord) _records[i];
- Integer recordAt = Integer.valueOf(pdr.getLastOnDiskOffset());
+ for (Record record : _hslfSlideShow.getRecords()) {
+ if (record instanceof PositionDependentRecord) {
+ PositionDependentRecord pdr = (PositionDependentRecord) record;
+ int recordAt = pdr.getLastOnDiskOffset();
// Is it one we care about?
- for (int j = 0; j < allIDs.length; j++) {
- Integer thisID = Integer.valueOf(allIDs[j]);
- Integer thatRecordAt = mostRecentByBytes.get(thisID);
+ for (Integer thisID : allIDs) {
+ int thatRecordAt = mostRecentByBytes.get(thisID);
- if (thatRecordAt.equals(recordAt)) {
+ if (thatRecordAt == recordAt) {
// Bingo. Now, where do we store it?
Integer storeAtI = _sheetIdToCoreRecordsLookup.get(thisID);
int storeAt = storeAtI.intValue();
// Tell it its Sheet ID, if it cares
if (pdr instanceof PositionDependentRecordContainer) {
- PositionDependentRecordContainer pdrc = (PositionDependentRecordContainer) _records[i];
- pdrc.setSheetId(thisID.intValue());
+ PositionDependentRecordContainer pdrc = (PositionDependentRecordContainer) record;
+ pdrc.setSheetId(thisID);
}
// Finally, save the record
- _mostRecentCoreRecords[storeAt] = _records[i];
+ _mostRecentCoreRecords[storeAt] = record;
}
}
}
}
// Now look for the interesting records in there
- for (int i = 0; i < _mostRecentCoreRecords.length; i++) {
+ for (Record record : _mostRecentCoreRecords) {
// Check there really is a record at this number
- if (_mostRecentCoreRecords[i] != null) {
+ if (record != null) {
// Find the Document, and interesting things in it
- if (_mostRecentCoreRecords[i].getRecordType() == RecordTypes.Document.typeID) {
- _documentRecord = (Document) _mostRecentCoreRecords[i];
+ if (record.getRecordType() == RecordTypes.Document.typeID) {
+ _documentRecord = (Document) record;
_fonts = _documentRecord.getEnvironment().getFontCollection();
}
} else {
ArrayList<SlideMaster> mmr = new ArrayList<SlideMaster>();
ArrayList<TitleMaster> tmr = new ArrayList<TitleMaster>();
- for (int i = 0; i < masterSets.length; i++) {
- Record r = getCoreRecordForSAS(masterSets[i]);
- SlideAtomsSet sas = masterSets[i];
+ for (SlideAtomsSet sas : masterSets) {
+ Record r = getCoreRecordForSAS(sas);
int sheetNo = sas.getSlidePersistAtom().getSlideIdentifier();
if (r instanceof org.apache.poi.hslf.record.Slide) {
TitleMaster master = new TitleMaster((org.apache.poi.hslf.record.Slide) r,
}
}
- _masters = new SlideMaster[mmr.size()];
- mmr.toArray(_masters);
-
- _titleMasters = new TitleMaster[tmr.size()];
- tmr.toArray(_titleMasters);
+ _masters = mmr.toArray(new SlideMaster[mmr.size()]);
+ _titleMasters = tmr.toArray(new TitleMaster[tmr.size()]);
}
// Having sorted out the masters, that leaves the notes and slides
// notesSLWT
org.apache.poi.hslf.record.Notes[] notesRecords;
SlideAtomsSet[] notesSets = new SlideAtomsSet[0];
- Hashtable<Integer,Integer> slideIdToNotes = new Hashtable<Integer,Integer>();
+ Map<Integer,Integer> slideIdToNotes = new HashMap<Integer,Integer>();
if (notesSLWT == null) {
// None
notesRecords = new org.apache.poi.hslf.record.Notes[0];
} else {
// Match up the records and the SlideAtomSets
notesSets = notesSLWT.getSlideAtomsSets();
- ArrayList<org.apache.poi.hslf.record.Notes> notesRecordsL =
+ List<org.apache.poi.hslf.record.Notes> notesRecordsL =
new ArrayList<org.apache.poi.hslf.record.Notes>();
for (int i = 0; i < notesSets.length; i++) {
// Get the right core record
// Record the match between slide id and these notes
SlidePersistAtom spa = notesSets[i].getSlidePersistAtom();
- Integer slideId = Integer.valueOf(spa.getSlideIdentifier());
- slideIdToNotes.put(slideId, Integer.valueOf(i));
+ int slideId = spa.getSlideIdentifier();
+ slideIdToNotes.put(slideId, i);
} else {
logger.log(POILogger.ERROR, "A Notes SlideAtomSet at " + i
+ " said its record was at refID "
// (Will stay as null if no SlidePersistAtom exists yet in
// the slide, or only master slide's ones do)
SlidePersistAtom prev = null;
- SlideAtomsSet[] sas = slist.getSlideAtomsSets();
- for (int j = 0; j < sas.length; j++) {
- SlidePersistAtom spa = sas[j].getSlidePersistAtom();
+ for (SlideAtomsSet sas : slist.getSlideAtomsSets()) {
+ SlidePersistAtom spa = sas.getSlidePersistAtom();
if (spa.getSlideIdentifier() < 0) {
// This is for a master slide
// Odd, since we only deal with the Slide SLWT
* found
*/
public PPFont getFont(int idx) {
- PPFont font = null;
FontCollection fonts = getDocumentRecord().getEnvironment().getFontCollection();
- Record[] ch = fonts.getChildRecords();
- for (int i = 0; i < ch.length; i++) {
- if (ch[i] instanceof FontEntityAtom) {
- FontEntityAtom atom = (FontEntityAtom) ch[i];
+ for (Record ch : fonts.getChildRecords()) {
+ if (ch instanceof FontEntityAtom) {
+ FontEntityAtom atom = (FontEntityAtom) ch;
if (atom.getFontIndex() == idx) {
- font = new PPFont(atom);
- break;
+ return new PPFont(atom);
}
}
}
- return font;
+ return null;
}
/**
boolean ppt2007 = "___PPT12".equals(tag);
HeadersFootersContainer hdd = null;
- Record[] ch = _documentRecord.getChildRecords();
- for (int i = 0; i < ch.length; i++) {
- if (ch[i] instanceof HeadersFootersContainer
- && ((HeadersFootersContainer) ch[i]).getOptions() == HeadersFootersContainer.SlideHeadersFootersContainer) {
- hdd = (HeadersFootersContainer) ch[i];
+ for (Record ch : _documentRecord.getChildRecords()) {
+ if (ch instanceof HeadersFootersContainer
+ && ((HeadersFootersContainer) ch).getOptions() == HeadersFootersContainer.SlideHeadersFootersContainer) {
+ hdd = (HeadersFootersContainer) ch;
break;
}
}
boolean ppt2007 = "___PPT12".equals(tag);
HeadersFootersContainer hdd = null;
- Record[] ch = _documentRecord.getChildRecords();
- for (int i = 0; i < ch.length; i++) {
- if (ch[i] instanceof HeadersFootersContainer
- && ((HeadersFootersContainer) ch[i]).getOptions() == HeadersFootersContainer.NotesHeadersFootersContainer) {
- hdd = (HeadersFootersContainer) ch[i];
+ for (Record ch : _documentRecord.getChildRecords()) {
+ if (ch instanceof HeadersFootersContainer
+ && ((HeadersFootersContainer) ch).getOptions() == HeadersFootersContainer.NotesHeadersFootersContainer) {
+ hdd = (HeadersFootersContainer) ch;
break;
}
}
}
protected int addPersistentObject(PositionDependentRecord slideRecord) {
- int slideRecordPos = _hslfSlideShow.appendRootLevelRecord((Record)slideRecord);
- _records = _hslfSlideShow.getRecords();
-
- // Add the new Slide into the PersistPtr stuff
- int offset = 0;
- int slideOffset = 0;
- PersistPtrHolder ptr = null;
- UserEditAtom usr = null;
- int i = 0;
- for (Record record : _records) {
- // Grab interesting records as they come past
- int recordType = (int)record.getRecordType();
- if (recordType == RecordTypes.PersistPtrIncrementalBlock.typeID) {
- ptr = (PersistPtrHolder)record;
- }
- if (recordType == RecordTypes.UserEditAtom.typeID) {
- usr = (UserEditAtom)record;
- }
+ slideRecord.setLastOnDiskOffset(HSLFSlideShow.UNSET_OFFSET);
+ _hslfSlideShow.appendRootLevelRecord((Record)slideRecord);
- if (i++ == slideRecordPos) {
- slideOffset = offset;
- }
-
- try {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- record.writeOut(out);
- offset += out.size();
- } catch (IOException e) {
- throw new HSLFException(e);
- }
- }
+ // For position dependent records, hold where they were and now are
+ // As we go along, update, and hand over, to any Position Dependent
+ // records we happen across
+ Map<RecordTypes.Type,PositionDependentRecord> interestingRecords =
+ new HashMap<RecordTypes.Type,PositionDependentRecord>();
+
+ try {
+ _hslfSlideShow.updateAndWriteDependantRecords(null,interestingRecords);
+ } catch (IOException e) {
+ throw new HSLFException(e);
+ }
+
+ PersistPtrHolder ptr = (PersistPtrHolder)interestingRecords.get(RecordTypes.PersistPtrIncrementalBlock);
+ UserEditAtom usr = (UserEditAtom)interestingRecords.get(RecordTypes.UserEditAtom);
// persist ID is UserEditAtom.maxPersistWritten + 1
int psrId = usr.getMaxPersistWritten() + 1;
// Add the new slide into the last PersistPtr
// (Also need to tell it where it is)
+ int slideOffset = slideRecord.getLastOnDiskOffset();
slideRecord.setLastOnDiskOffset(slideOffset);
ptr.addSlideLookup(psrId, slideOffset);
logger.log(POILogger.INFO, "New slide/object ended up at " + slideOffset);