]> source.dussan.org Git - poi.git/commitdiff
Bug 48593 - [PATCH] Multiple Saves Causes Slide Corruption
authorAndreas Beeker <kiwiwings@apache.org>
Fri, 27 Dec 2013 00:22:19 +0000 (00:22 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Fri, 27 Dec 2013 00:22:19 +0000 (00:22 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1553610 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java
src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjStg.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
src/scratchpad/testcases/org/apache/poi/hslf/HSLFTestDataSamples.java [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hslf/TestReWrite.java

index 0e9984b2ca442907e3003e6deb7b46947330aa90..e7fb4bbe5818958103c6034410fcf76dff11284f 100644 (file)
@@ -29,6 +29,7 @@ import java.util.Arrays;
 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;
@@ -40,12 +41,14 @@ import org.apache.poi.hslf.record.PersistPtrHolder;
 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;
@@ -59,6 +62,8 @@ import org.apache.poi.util.POILogger;
  * @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());
 
@@ -346,6 +351,7 @@ public final class HSLFSlideShow extends POIDocument {
             int offset = pos;
 
             // Image signature
+            @SuppressWarnings("unused")
             int signature = LittleEndian.getUShort(pictstream, pos);
             pos += LittleEndian.SHORT_SIZE;
             // Image type + 0xF018
@@ -392,7 +398,88 @@ public final class HSLFSlideShow extends POIDocument {
         }
        }
 
+       /**
+     * 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.
@@ -426,49 +513,13 @@ public final class HSLFSlideShow extends POIDocument {
         // 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();
 
@@ -476,15 +527,6 @@ public final class HSLFSlideShow extends POIDocument {
         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");
 
@@ -506,7 +548,7 @@ public final class HSLFSlideShow extends POIDocument {
 
         // 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
@@ -612,9 +654,9 @@ public final class HSLFSlideShow extends POIDocument {
     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()]);
index c3997dc5862ff4d5bada0b0929c82e686d92e9ba..b78ccdc8232d2f85e668112b038e14e448e51f68 100644 (file)
 
 package org.apache.poi.hslf.record;
 
-import java.io.*;
-import java.util.zip.InflaterInputStream;
-import java.util.zip.DeflaterOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.Hashtable;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
 
 import org.apache.poi.util.BoundedInputStream;
 import org.apache.poi.util.LittleEndian;
@@ -120,7 +124,7 @@ public class ExOleObjStg extends RecordAtom implements PositionDependentRecord,
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         //first four bytes is the length of the raw data
         byte[] b = new byte[4];
-        LittleEndian.putInt(b, data.length);
+        LittleEndian.putInt(b, 0, data.length);
         out.write(b);
 
         DeflaterOutputStream def = new DeflaterOutputStream(out);
index edb46d06c192f735c88d1ff9768d97860368595c..9011583494661a82c64502512e4479f2ae60faf4 100644 (file)
@@ -25,7 +25,12 @@ import java.io.FileInputStream;
 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;
@@ -35,11 +40,43 @@ import org.apache.poi.hpsf.ClassID;
 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;
@@ -58,15 +95,12 @@ public final class SlideShow {
        // 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;
@@ -97,10 +131,9 @@ public final class SlideShow {
        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);
             }
@@ -135,25 +168,23 @@ public final class SlideShow {
         */
        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));
                                }
                        }
@@ -165,54 +196,48 @@ public final class SlideShow {
 
                // 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 {
@@ -296,9 +321,8 @@ public final class SlideShow {
                        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,
@@ -313,11 +337,8 @@ public final class SlideShow {
                                }
                        }
 
-                       _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
@@ -326,14 +347,14 @@ public final class SlideShow {
                // 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
@@ -346,8 +367,8 @@ public final class SlideShow {
 
                                        // 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 "
@@ -686,9 +707,8 @@ public final class SlideShow {
                // (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
@@ -850,19 +870,16 @@ public final class SlideShow {
         *         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;
        }
 
        /**
@@ -885,11 +902,10 @@ public final class SlideShow {
                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;
                        }
                }
@@ -912,11 +928,10 @@ public final class SlideShow {
                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;
                        }
                }
@@ -1107,37 +1122,23 @@ public final class SlideShow {
     }
 
     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;
@@ -1149,6 +1150,7 @@ public final class SlideShow {
 
                // 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);
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/HSLFTestDataSamples.java b/src/scratchpad/testcases/org/apache/poi/hslf/HSLFTestDataSamples.java
new file mode 100644 (file)
index 0000000..6740708
--- /dev/null
@@ -0,0 +1,74 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hslf;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.hslf.usermodel.SlideShow;
+
+public class HSLFTestDataSamples {
+
+       private static final POIDataSamples _inst = POIDataSamples.getSlideShowInstance();
+
+       public static InputStream openSampleFileStream(String sampleFileName) {
+               return _inst.openResourceAsStream(sampleFileName);
+       }
+       public static File getSampleFile(String sampleFileName) {
+          return _inst.getFile(sampleFileName);
+       }
+       public static byte[] getTestDataFileContent(String fileName) {
+               return _inst.readFile(fileName);
+       }
+
+       /**
+        * Writes a slideshow to a <tt>ByteArrayOutputStream</tt> and reads it back
+        * from a <tt>ByteArrayInputStream</tt>.<p/>
+        * Useful for verifying that the serialisation round trip
+        */
+       public static HSLFSlideShow writeOutAndReadBack(HSLFSlideShow original) {
+               try {
+                       ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
+                       original.write(baos);
+                       ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+                       return new HSLFSlideShow(bais);
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+       /**
+        * Writes a slideshow to a <tt>ByteArrayOutputStream</tt> and reads it back
+        * from a <tt>ByteArrayInputStream</tt>.<p/>
+        * Useful for verifying that the serialisation round trip
+        */
+       public static SlideShow writeOutAndReadBack(SlideShow original) {
+               try {
+                       ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
+                       original.write(baos);
+                       ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+                       return new SlideShow(bais);
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+}
index ff918ad03d71ef66edf20e5d2a3af1bf6ffb2513..1398e747e13a13ad49145965e136089207c6f192 100644 (file)
 package org.apache.poi.hslf;
 
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+
 import junit.framework.TestCase;
 
-import org.apache.poi.hslf.usermodel.SlideShow;
-import org.apache.poi.poifs.filesystem.*;
 import org.apache.poi.POIDataSamples;
-
-import java.io.ByteArrayOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.FileNotFoundException;
+import org.apache.poi.hslf.usermodel.SlideShow;
+import org.apache.poi.poifs.filesystem.DocumentEntry;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 
 /**
  * Tests that HSLFSlideShow writes the powerpoint bit of data back out
@@ -160,4 +161,16 @@ public final class TestReWrite extends TestCase {
                        assertEquals(_oData[i], _nData[i]);
                }
        }
+    
+    public void test48593() throws Exception {
+               SlideShow slideShow = new SlideShow();
+               slideShow.createSlide();
+               slideShow = HSLFTestDataSamples.writeOutAndReadBack(slideShow);
+               slideShow.createSlide();
+               slideShow = HSLFTestDataSamples.writeOutAndReadBack(slideShow);
+               slideShow.createSlide();
+               slideShow = HSLFTestDataSamples.writeOutAndReadBack(slideShow);
+               slideShow.createSlide();
+               slideShow = HSLFTestDataSamples.writeOutAndReadBack(slideShow);
+    }
 }