Bug 48593 - [PATCH] Multiple Saves Causes Slide Corruption

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1553610 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2013-12-27 00:22:19 +00:00
parent 7f22915265
commit a30d2870c8
5 changed files with 300 additions and 165 deletions

View 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,6 +398,87 @@ 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
@ -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>();
// records we happen across
updateAndWriteDependantRecords(baos, null);
// 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);
}
// 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()]);

View File

@ -17,10 +17,14 @@
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);

View 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();
slideRecord.setLastOnDiskOffset(HSLFSlideShow.UNSET_OFFSET);
_hslfSlideShow.appendRootLevelRecord((Record)slideRecord);
// 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;
}
// 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>();
if (i++ == slideRecordPos) {
slideOffset = offset;
}
try {
_hslfSlideShow.updateAndWriteDependantRecords(null,interestingRecords);
} catch (IOException e) {
throw new HSLFException(e);
}
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
record.writeOut(out);
offset += out.size();
} 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);

View File

@ -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);
}
}
}

View File

@ -18,15 +18,16 @@
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);
}
}