ASF Bugzilla – Attachment 31069 Details for
Bug 55579
[PATCH] Patch for add/embed OLE objects into HSLF
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch for add/embed OLE objects into HSLF
hslf-embed-oleobject-merged.diff (text/plain), 18.66 KB, created by
Andreas Beeker
on 2013-11-23 19:41:31 UTC
(
hide
)
Description:
Patch for add/embed OLE objects into HSLF
Filename:
MIME Type:
Creator:
Andreas Beeker
Created:
2013-11-23 19:41:31 UTC
Size:
18.66 KB
patch
obsolete
>Index: src/java/org/apache/poi/hpsf/ClassID.java >=================================================================== >--- src/java/org/apache/poi/hpsf/ClassID.java (revision 1538068) >+++ src/java/org/apache/poi/hpsf/ClassID.java (working copy) >@@ -34,6 +34,12 @@ > public static final ClassID PPT_SHOW = new ClassID("{64818D10-4F9B-11CF-86EA-00AA00B929E8}"); > public static final ClassID XLS_WORKBOOK = new ClassID("{00020841-0000-0000-C000-000000000046}"); > public static final ClassID TXT_ONLY = new ClassID("{5e941d80-bf96-11cd-b579-08002b30bfeb}"); // ??? >+ public static final ClassID EXCEL97 = new ClassID("{00020820-0000-0000-C000-000000000046}"); >+ public static final ClassID EXCEL95 = new ClassID("{00020810-0000-0000-C000-000000000046}"); >+ public static final ClassID WORD97 = new ClassID("{00020906-0000-0000-C000-000000000046}"); >+ public static final ClassID WORD95 = new ClassID("{00020900-0000-0000-C000-000000000046}"); >+ public static final ClassID POWERPOINT97 = new ClassID("{64818D10-4F9B-11CF-86EA-00AA00B929E8}"); >+ public static final ClassID POWERPOINT95 = new ClassID("{EA7BAE70-FB3B-11CD-A903-00AA00510EA3}"); > > > /** >Index: src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java >=================================================================== >--- src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java (revision 1538068) >+++ src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java (working copy) >@@ -23,6 +23,8 @@ > import org.apache.poi.hslf.record.ExObjList; > import org.apache.poi.hslf.record.Record; > import org.apache.poi.hslf.record.ExEmbed; >+import org.apache.poi.hslf.record.RecordTypes; >+import org.apache.poi.util.LittleEndian; > import org.apache.poi.util.POILogger; > > >@@ -74,6 +76,42 @@ > } > > /** >+ * Set the unique identifier for the OLE object and >+ * register it in the necessary structures >+ * >+ * @param objectId the unique identifier for the OLE object >+ */ >+ public void setObjectID(int objectId){ >+ setEscherProperty(EscherProperties.BLIP__PICTUREID, objectId); >+ >+ EscherContainerRecord ecr = getSpContainer(); >+ EscherSpRecord spRecord = ecr.getChildById(EscherSpRecord.RECORD_ID); >+ spRecord.setFlags(spRecord.getFlags()|EscherSpRecord.FLAG_OLESHAPE); >+ >+ EscherContainerRecord uerCont = ecr.getChildById((short)RecordTypes.EscherClientData); >+ if (uerCont == null) { >+ uerCont = new EscherContainerRecord(); >+ ecr.addChildRecord(uerCont); >+ } >+ uerCont.setRecordId((short)RecordTypes.EscherClientData); >+ uerCont.setVersion((short)0x000F); // yes, we are still a container ... >+ >+ UnknownEscherRecord uer = uerCont.getChildById((short)RecordTypes.ExObjRefAtom.typeID); >+ if (uer == null) { >+ uer = new UnknownEscherRecord(); >+ uerCont.addChildRecord(uer); >+ } >+ >+ byte uerData[] = new byte[12]; >+ LittleEndian.putShort( uerData, 0, (short)0 ); // options = 0 >+ LittleEndian.putShort( uerData, 2, (short)RecordTypes.ExObjRefAtom.typeID); // recordId >+ LittleEndian.putInt( uerData, 4, 4 ); // remaining bytes >+ LittleEndian.putInt( uerData, 8, objectId ); // the data >+ uer.fillFields(uerData, 0, null); >+ } >+ >+ >+ /** > * Returns unique identifier for the OLE object. > * > * @return the unique identifier for the OLE object >Index: src/scratchpad/src/org/apache/poi/hslf/record/ExEmbedAtom.java >=================================================================== >--- src/scratchpad/src/org/apache/poi/hslf/record/ExEmbedAtom.java (revision 1540295) >+++ src/scratchpad/src/org/apache/poi/hslf/record/ExEmbedAtom.java (working copy) >@@ -70,7 +70,7 @@ > */ > protected ExEmbedAtom() { > _header = new byte[8]; >- _data = new byte[7]; >+ _data = new byte[8]; > > LittleEndian.putShort(_header, 2, (short)getRecordType()); > LittleEndian.putInt(_header, 4, _data.length); >@@ -95,7 +95,7 @@ > System.arraycopy(source,start+8,_data,0,len-8); > > // Must be at least 4 bytes long >- if(_data.length < 7) { >+ if(_data.length < 8) { > throw new IllegalArgumentException("The length of the data for a ExEmbedAtom must be at least 4 bytes, but was only " + _data.length); > } > } >@@ -120,6 +120,10 @@ > return _data[4] != 0; > } > >+ public void setCantLockServerB(boolean cantBeLocked) { >+ _data[4] = (byte)(cantBeLocked ? 1 : 0); >+ } >+ > /** > * Gets whether it is not required to send the dimensions to the embedded object. > * >Index: src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java >=================================================================== >--- src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java (revision 1538068) >+++ src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java (working copy) >@@ -18,6 +18,7 @@ > package org.apache.poi.hslf.usermodel; > > import java.awt.Dimension; >+import java.io.ByteArrayInputStream; > import java.io.ByteArrayOutputStream; > import java.io.File; > import java.io.FileInputStream; >@@ -30,6 +31,7 @@ > import org.apache.poi.ddf.EscherContainerRecord; > import org.apache.poi.ddf.EscherOptRecord; > import org.apache.poi.ddf.EscherRecord; >+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; >@@ -38,6 +40,8 @@ > import org.apache.poi.hslf.model.Slide; > import org.apache.poi.hslf.record.*; > import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet; >+import org.apache.poi.poifs.filesystem.DirectoryNode; >+import org.apache.poi.poifs.filesystem.POIFSFileSystem; > import org.apache.poi.util.POILogFactory; > import org.apache.poi.util.POILogger; > >@@ -723,53 +727,10 @@ > > // Add the core records for this new Slide to the record tree > org.apache.poi.hslf.record.Slide slideRecord = slide.getSlideRecord(); >- int slideRecordPos = _hslfSlideShow.appendRootLevelRecord(slideRecord); >- _records = _hslfSlideShow.getRecords(); >- >- // Add the new Slide into the PersistPtr stuff >- int offset = 0; >- int slideOffset = 0; >- PersistPtrHolder ptr = null; >- UserEditAtom usr = null; >- for (int i = 0; i < _records.length; i++) { >- Record record = _records[i]; >- ByteArrayOutputStream out = new ByteArrayOutputStream(); >- try { >- record.writeOut(out); >- } catch (IOException e) { >- throw new HSLFException(e); >- } >- >- // Grab interesting records as they come past >- if (_records[i].getRecordType() == RecordTypes.PersistPtrIncrementalBlock.typeID) { >- ptr = (PersistPtrHolder) _records[i]; >- } >- if (_records[i].getRecordType() == RecordTypes.UserEditAtom.typeID) { >- usr = (UserEditAtom) _records[i]; >- } >- >- if (i == slideRecordPos) { >- slideOffset = offset; >- } >- offset += out.size(); >- } >- >- // persist ID is UserEditAtom.maxPersistWritten + 1 >- int psrId = usr.getMaxPersistWritten() + 1; >+ int psrId = addPersistentObject(slideRecord); > sp.setRefID(psrId); > slideRecord.setSheetId(psrId); >- >- // Last view is now of the slide >- usr.setLastViewType((short) UserEditAtom.LAST_VIEW_SLIDE_VIEW); >- usr.setMaxPersistWritten(psrId); // increment the number of persit >- // objects >- >- // Add the new slide into the last PersistPtr >- // (Also need to tell it where it is) >- slideRecord.setLastOnDiskOffset(slideOffset); >- ptr.addSlideLookup(sp.getRefID(), slideOffset); >- logger.log(POILogger.INFO, "New slide ended up at " + slideOffset); >- >+ > slide.setMasterSheet(_masters[0]); > // All done and added > return slide; >@@ -978,16 +939,6 @@ > * @return 0-based index of the movie > */ > public int addMovie(String path, int type) { >- ExObjList lst = (ExObjList) _documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID); >- if (lst == null) { >- lst = new ExObjList(); >- _documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom()); >- } >- >- ExObjListAtom objAtom = lst.getExObjListAtom(); >- // increment the object ID seed >- int objectId = (int) objAtom.getObjectIDSeed() + 1; >- objAtom.setObjectIDSeed(objectId); > ExMCIMovie mci; > switch (type) { > case MovieShape.MOVIE_MPEG: >@@ -1000,11 +951,13 @@ > throw new IllegalArgumentException("Unsupported Movie: " + type); > } > >- lst.appendChildRecord(mci); > ExVideoContainer exVideo = mci.getExVideo(); >- exVideo.getExMediaAtom().setObjectId(objectId); > exVideo.getExMediaAtom().setMask(0xE80000); > exVideo.getPathAtom().setText(path); >+ >+ int objectId = addToObjListAtom(mci); >+ exVideo.getExMediaAtom().setObjectId(objectId); >+ > return objectId; > } > >@@ -1019,27 +972,18 @@ > * @return 0-based index of the control > */ > public int addControl(String name, String progId) { >- ExObjList lst = (ExObjList) _documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID); >- if (lst == null) { >- lst = new ExObjList(); >- _documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom()); >- } >- ExObjListAtom objAtom = lst.getExObjListAtom(); >- // increment the object ID seed >- int objectId = (int) objAtom.getObjectIDSeed() + 1; >- objAtom.setObjectIDSeed(objectId); > ExControl ctrl = new ExControl(); >+ ctrl.setProgId(progId); >+ ctrl.setMenuName(name); >+ ctrl.setClipboardName(name); >+ > ExOleObjAtom oleObj = ctrl.getExOleObjAtom(); >- oleObj.setObjID(objectId); > oleObj.setDrawAspect(ExOleObjAtom.DRAW_ASPECT_VISIBLE); > oleObj.setType(ExOleObjAtom.TYPE_CONTROL); > oleObj.setSubType(ExOleObjAtom.SUBTYPE_DEFAULT); >- >- ctrl.setProgId(progId); >- ctrl.setMenuName(name); >- ctrl.setClipboardName(name); >- lst.addChildAfter(ctrl, objAtom); >- >+ >+ int objectId = addToObjListAtom(ctrl); >+ oleObj.setObjID(objectId); > return objectId; > } > >@@ -1049,28 +993,166 @@ > * @return 0-based index of the hyperlink > */ > public int addHyperlink(Hyperlink link) { >- ExObjList lst = (ExObjList) _documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID); >- if (lst == null) { >- lst = new ExObjList(); >- _documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom()); >- } >- ExObjListAtom objAtom = lst.getExObjListAtom(); >- // increment the object ID seed >- int objectId = (int) objAtom.getObjectIDSeed() + 1; >- objAtom.setObjectIDSeed(objectId); >- > ExHyperlink ctrl = new ExHyperlink(); > ExHyperlinkAtom obj = ctrl.getExHyperlinkAtom(); >- obj.setNumber(objectId); > if(link.getType() == Hyperlink.LINK_SLIDENUMBER) { > ctrl.setLinkURL(link.getAddress(), 0x30); > } else { > ctrl.setLinkURL(link.getAddress()); > } > ctrl.setLinkTitle(link.getTitle()); >- lst.addChildAfter(ctrl, objAtom); >+ >+ int objectId = addToObjListAtom(ctrl); > link.setId(objectId); >+ obj.setNumber(objectId); >+ >+ return objectId; >+ } >+ >+ /** >+ * Add a embedded object to this presentation >+ * >+ * @return 0-based index of the embedded object >+ */ >+ public int addEmbed(POIFSFileSystem poiData) { >+ DirectoryNode root = poiData.getRoot(); >+ >+ // prepare embedded data >+ if (new ClassID().equals(root.getStorageClsid())) { >+ // need to set class id >+ Map<String,ClassID> olemap = getOleMap(); >+ ClassID classID = null; >+ for (Map.Entry<String,ClassID> entry : olemap.entrySet()) { >+ if (root.hasEntry(entry.getKey())) { >+ classID = entry.getValue(); >+ break; >+ } >+ } >+ if (classID == null) { >+ throw new IllegalArgumentException("Unsupported embedded document"); >+ } >+ >+ root.setStorageClsid(classID); >+ } >+ >+ ExEmbed exEmbed = new ExEmbed(); >+ // remove unneccessary infos, so we don't need to specify the type >+ // of the ole object multiple times >+ Record children[] = exEmbed.getChildRecords(); >+ exEmbed.removeChild(children[2]); >+ exEmbed.removeChild(children[3]); >+ exEmbed.removeChild(children[4]); >+ >+ ExEmbedAtom eeEmbed = exEmbed.getExEmbedAtom(); >+ eeEmbed.setCantLockServerB(true); > >+ ExOleObjAtom eeAtom = exEmbed.getExOleObjAtom(); >+ eeAtom.setDrawAspect(ExOleObjAtom.DRAW_ASPECT_VISIBLE); >+ eeAtom.setType(ExOleObjAtom.TYPE_EMBEDDED); >+ // eeAtom.setSubType(ExOleObjAtom.SUBTYPE_EXCEL); >+ // should be ignored?!?, see MS-PPT ExOleObjAtom, but Libre Office sets it ... >+ eeAtom.setOptions(1226240); >+ >+ ExOleObjStg exOleObjStg = new ExOleObjStg(); >+ try { >+ final String OLESTREAM_NAME = "\u0001Ole"; >+ if (!root.hasEntry(OLESTREAM_NAME)) { >+ // the following data was taken from an example libre office document >+ // beside this "\u0001Ole" record there were several other records, e.g. CompObj, >+ // OlePresXXX, but it seems, that they aren't neccessary >+ byte oleBytes[] = { 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; >+ poiData.createDocument(new ByteArrayInputStream(oleBytes), OLESTREAM_NAME); >+ } >+ >+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); >+ poiData.writeFilesystem(bos); >+ exOleObjStg.setData(bos.toByteArray()); >+ } catch (IOException e) { >+ throw new HSLFException(e); >+ } >+ >+ int psrId = addPersistentObject(exOleObjStg); >+ exOleObjStg.setPersistId(psrId); >+ eeAtom.setObjStgDataRef(psrId); >+ >+ int objectId = addToObjListAtom(exEmbed); >+ eeAtom.setObjID(objectId); > return objectId; > } >+ >+ protected int addToObjListAtom(RecordContainer exObj) { >+ ExObjList lst = (ExObjList) _documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID); >+ if (lst == null) { >+ lst = new ExObjList(); >+ _documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom()); >+ } >+ ExObjListAtom objAtom = lst.getExObjListAtom(); >+ // increment the object ID seed >+ int objectId = (int) objAtom.getObjectIDSeed() + 1; >+ objAtom.setObjectIDSeed(objectId); >+ >+ lst.addChildAfter(exObj, objAtom); >+ >+ return objectId; >+ } >+ >+ protected static Map<String,ClassID> getOleMap() { >+ Map<String,ClassID> olemap = new HashMap<String,ClassID>(); >+ olemap.put("PowerPoint Document", ClassID.PPT_SHOW); >+ olemap.put("Workbook", ClassID.EXCEL97); // as per BIFF8 spec >+ olemap.put("WORKBOOK", ClassID.EXCEL97); // Typically from third party programs >+ olemap.put("BOOK", ClassID.EXCEL97); // Typically odd Crystal Reports exports >+ // ... to be continued >+ return olemap; >+ } >+ >+ 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; >+ } >+ >+ if (i++ == slideRecordPos) { >+ slideOffset = offset; >+ } >+ >+ try { >+ ByteArrayOutputStream out = new ByteArrayOutputStream(); >+ record.writeOut(out); >+ offset += out.size(); >+ } catch (IOException e) { >+ throw new HSLFException(e); >+ } >+ } >+ >+ // persist ID is UserEditAtom.maxPersistWritten + 1 >+ int psrId = usr.getMaxPersistWritten() + 1; >+ >+ // Last view is now of the slide >+ usr.setLastViewType((short) UserEditAtom.LAST_VIEW_SLIDE_VIEW); >+ // increment the number of persistent objects >+ usr.setMaxPersistWritten(psrId); >+ >+ // Add the new slide into the last PersistPtr >+ // (Also need to tell it where it is) >+ slideRecord.setLastOnDiskOffset(slideOffset); >+ ptr.addSlideLookup(psrId, slideOffset); >+ logger.log(POILogger.INFO, "New slide/object ended up at " + slideOffset); >+ >+ return psrId; >+ } > } >Index: src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java >=================================================================== >--- src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java (revision 1538068) >+++ src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java (working copy) >@@ -17,6 +17,14 @@ > > package org.apache.poi.hslf.model; > >+import java.awt.geom.Rectangle2D; >+import java.io.ByteArrayInputStream; >+import java.io.ByteArrayOutputStream; >+import java.io.File; >+import java.io.FileOutputStream; >+import java.io.InputStream; >+import java.util.Arrays; >+ > import junit.framework.TestCase; > > import org.apache.poi.hslf.HSLFSlideShow; >@@ -26,6 +34,8 @@ > import org.apache.poi.hssf.usermodel.HSSFSheet; > import org.apache.poi.hssf.usermodel.HSSFWorkbook; > import org.apache.poi.hwpf.HWPFDocument; >+import org.apache.poi.poifs.filesystem.POIFSFileSystem; >+import org.apache.poi.util.IOUtils; > import org.apache.poi.POIDataSamples; > > public final class TestOleEmbedding extends TestCase { >@@ -82,4 +92,44 @@ > } > assertEquals("Expected 2 OLE shapes", 2, cnt); > } >+ >+ public void testEmbedding() throws Exception { >+ HSLFSlideShow _hslfSlideShow = HSLFSlideShow.create(); >+ SlideShow ppt = new SlideShow(_hslfSlideShow); >+ >+ File pict = POIDataSamples.getSlideShowInstance().getFile("clock.jpg"); >+ int pictId = ppt.addPicture(pict, Picture.JPEG); >+ >+ InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("Employee.xls"); >+ POIFSFileSystem poiData = new POIFSFileSystem(is); >+ is.close(); >+ >+ int oleObjectId = ppt.addEmbed(poiData); >+ >+ Slide slide = ppt.createSlide(); >+ OLEShape oleShape1 = new OLEShape(pictId); >+ oleShape1.setObjectID(oleObjectId); >+ slide.addShape(oleShape1); >+ oleShape1.setAnchor(new Rectangle2D.Double(100,100,100,100)); >+ >+ if (false) { >+ FileOutputStream fos = new FileOutputStream("embed.ppt"); >+ ppt.write(fos); >+ fos.close(); >+ } >+ >+ ByteArrayOutputStream bos = new ByteArrayOutputStream(); >+ ppt.write(bos); >+ >+ ppt = new SlideShow(new ByteArrayInputStream(bos.toByteArray())); >+ OLEShape comp = (OLEShape)ppt.getSlides()[0].getShapes()[0]; >+ byte compData[] = IOUtils.toByteArray(comp.getObjectData().getData()); >+ >+ bos.reset(); >+ poiData.writeFilesystem(bos); >+ byte expData[] = bos.toByteArray(); >+ >+ assertTrue(Arrays.equals(expData, compData)); >+ >+ } > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 55579
:
30870
| 31069