<li><link href="#Graphics2D">Shapes and Graphics2D</link></li>
<li><link href="#Render">How to convert slides into images</link></li>
<li><link href="#HeadersFooters">Headers / Footers</link></li>
+ <li><link href="#Movies">How to embed movies</link></li>
</ul>
</section>
<section><title>Features</title>
hdd.setFootersText("Created by POI-HSLF");
</source>
</section>
+ <anchor id="Movies"/>
+ <section><title>How to embed movies</title>
+ <source>
+
+ SlideShow ppt = new SlideShow();
+ Slide slide = ppt.createSlide();
+
+ //UNC or local Returns UNC or local path to a video file
+ String moviePath = "card.mpg";
+ int movieIdx = ppt.addMovie(moviePath, MovieShape.MOVIE_MPEG);
+
+ String thumbnailPath = "card.png";
+ int thumbnailIdx = ppt.addPicture(new File(thumbnailPath), Picture.PNG);
+ MovieShape shape = new MovieShape(movieIdx, thumbnailIdx);
+ shape.setAnchor(new Rectangle2D.Float(300,225,120,90));
+ slide.addShape(shape);
+
+ FileOutputStream out = new FileOutputStream("hslf-movie.ppt");
+ ppt.write(out);
+ out.close();
+ </source>
+ </section>
</section>
</section>
</body>
package org.apache.poi.hslf.blip;
import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogger;
import org.apache.poi.hslf.model.Picture;
import org.apache.poi.hslf.model.Shape;
import org.apache.poi.hslf.exceptions.HSLFException;
Header header = new Header();
header.wmfsize = data.length - aldus.getSize();
header.bounds = new java.awt.Rectangle((short)aldus.left, (short)aldus.top, (short)aldus.right-(short)aldus.left, (short)aldus.bottom-(short)aldus.top);
- //coefficiaent to translate from WMF dpi to 96pdi
+ //coefficient to translate from WMF dpi to 96pdi
int coeff = 96*Shape.EMU_PER_POINT/aldus.inch;
header.size = new java.awt.Dimension(header.bounds.width*coeff, header.bounds.height*coeff);
header.zipsize = compressed.length;
* <li>short Checksum; Checksum value for previous 10 shorts
* </ul>
*/
- public static class AldusHeader{
+ public class AldusHeader{
public static final int APMHEADER_KEY = 0x9AC6CDD7;
public int handle;
reserved = LittleEndian.getInt(data, pos); pos += LittleEndian.INT_SIZE;
checksum = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
- if (checksum != getChecksum())
- throw new HSLFException("WMF checksum does not match the header data");
+ if (checksum != getChecksum()){
+ logger.log(POILogger.WARN, "WMF checksum does not match the header data");
+ }
}
/**
dump(data, pos, size, padding);
} else {
//dump first 100 bytes of the atom data
- dump(out, data, pos, Math.min(size, 100), padding, true);
+ dump(out, data, pos, size, padding, true);
}
padding--;
write(out, "</"+recname + ">" + CR, padding);
--- /dev/null
+package org.apache.poi.hslf.model;\r
+\r
+import org.apache.poi.ddf.*;\r
+import org.apache.poi.hslf.record.*;\r
+import org.apache.poi.hslf.exceptions.HSLFException;\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.UnsupportedEncodingException;\r
+import java.util.Iterator;\r
+\r
+/**\r
+ * Represents an ActiveX control in a PowerPoint document.\r
+ *\r
+ * TODO: finish\r
+ * @author Yegor Kozlov\r
+ */\r
+public class ActiveXShape extends Picture {\r
+ public static final int DEFAULT_ACTIVEX_THUMBNAIL = -1;\r
+\r
+ /**\r
+ * Create a new <code>Picture</code>\r
+ *\r
+ * @param pictureIdx the index of the picture\r
+ */\r
+ public ActiveXShape(int movieIdx, int pictureIdx){\r
+ super(pictureIdx, null);\r
+ setActiveXIndex(movieIdx);\r
+ }\r
+\r
+ /**\r
+ * Create a <code>Picture</code> object\r
+ *\r
+ * @param escherRecord the <code>EscherSpContainer</code> record which holds information about\r
+ * this picture in the <code>Slide</code>\r
+ * @param parent the parent shape of this picture\r
+ */\r
+ protected ActiveXShape(EscherContainerRecord escherRecord, Shape parent){\r
+ super(escherRecord, parent);\r
+ }\r
+\r
+ /**\r
+ * Create a new Placeholder and initialize internal structures\r
+ *\r
+ * @return the created <code>EscherContainerRecord</code> which holds shape data\r
+ */\r
+ protected EscherContainerRecord createSpContainer(int idx, boolean isChild) {\r
+ _escherContainer = super.createSpContainer(idx, isChild);\r
+\r
+ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);\r
+ spRecord.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE | EscherSpRecord.FLAG_OLESHAPE);\r
+\r
+ setShapeType(ShapeTypes.HostControl);\r
+ setEscherProperty(EscherProperties.BLIP__PICTUREID, idx);\r
+ setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001);\r
+ setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80008);\r
+ setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);\r
+ setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, -1);\r
+\r
+ EscherClientDataRecord cldata = new EscherClientDataRecord();\r
+ cldata.setOptions((short)0xF);\r
+ _escherContainer.getChildRecords().add(cldata);\r
+\r
+ OEShapeAtom oe = new OEShapeAtom();\r
+\r
+ //convert hslf into ddf\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ try {\r
+ oe.writeOut(out);\r
+ } catch(Exception e){\r
+ throw new HSLFException(e);\r
+ }\r
+ cldata.setRemainingData(out.toByteArray());\r
+\r
+ return _escherContainer;\r
+ }\r
+\r
+ /**\r
+ * Assign a control to this shape\r
+ *\r
+ * @see {@link org.apache.poi.hslf.usermodel.SlideShow#addMovie(String, int)}\r
+ * @param idx the index of the movie\r
+ */\r
+ public void setActiveXIndex(int idx){\r
+ EscherContainerRecord spContainer = getSpContainer();\r
+ for (Iterator it = spContainer.getChildRecords().iterator(); it.hasNext();) {\r
+ EscherRecord obj = (EscherRecord) it.next();\r
+ if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {\r
+ EscherClientDataRecord clientRecord = (EscherClientDataRecord)obj;\r
+ byte[] recdata = clientRecord.getRemainingData();\r
+ LittleEndian.putInt(recdata, 8, idx);\r
+ }\r
+ }\r
+ }\r
+\r
+ public int getControlIndex(){\r
+ int idx = -1;\r
+ OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);\r
+ if(oe != null) idx = oe.getOptions();\r
+ return idx;\r
+ }\r
+\r
+ /**\r
+ * Set a property of this ActiveX control\r
+ * @param key\r
+ * @param value\r
+ */\r
+ public void setProperty(String key, String value){\r
+\r
+ }\r
+\r
+ /**\r
+ * Document-level container that specifies information about an ActiveX control\r
+ *\r
+ * @return container that specifies information about an ActiveX control\r
+ */\r
+ public ExControl getExControl(){\r
+ int idx = getControlIndex();\r
+ ExControl ctrl = null;\r
+ Document doc = getSheet().getSlideShow().getDocumentRecord();\r
+ ExObjList lst = (ExObjList)doc.findFirstOfType(RecordTypes.ExObjList.typeID);\r
+ if(lst != null){\r
+ Record[] ch = lst.getChildRecords();\r
+ for (int i = 0; i < ch.length; i++) {\r
+ if(ch[i] instanceof ExControl){\r
+ ExControl c = (ExControl)ch[i];\r
+ if(c.getExOleObjAtom().getObjID() == idx){\r
+ ctrl = c;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return ctrl;\r
+ }\r
+\r
+ protected void afterInsert(Sheet sheet){\r
+ ExControl ctrl = getExControl();\r
+ ctrl.getExControlAtom().setSlideId(sheet._getSheetNumber());\r
+\r
+ try {\r
+ String name = ctrl.getProgId() + "-" + getControlIndex();\r
+ byte[] data = (name + '\u0000').getBytes("UTF-16LE");\r
+ EscherComplexProperty prop = new EscherComplexProperty(EscherProperties.GROUPSHAPE__SHAPENAME, false, data);\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+ opt.addEscherProperty(prop);\r
+ } catch (UnsupportedEncodingException e){\r
+ throw new HSLFException(e);\r
+ }\r
+\r
+ }\r
+}\r
--- /dev/null
+package org.apache.poi.hslf.model;\r
+\r
+import org.apache.poi.ddf.*;\r
+import org.apache.poi.hslf.record.*;\r
+import org.apache.poi.hslf.exceptions.HSLFException;\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.util.Iterator;\r
+\r
+/**\r
+ * Represents a movie in a PowerPoint document.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class MovieShape extends Picture {\r
+ public static final int DEFAULT_MOVIE_THUMBNAIL = -1;\r
+\r
+ public static final int MOVIE_MPEG = 1;\r
+ public static final int MOVIE_AVI = 2;\r
+\r
+ /**\r
+ * Create a new <code>Picture</code>\r
+ *\r
+ * @param pictureIdx the index of the picture\r
+ */\r
+ public MovieShape(int movieIdx, int pictureIdx){\r
+ super(pictureIdx, null);\r
+ setMovieIndex(movieIdx);\r
+ setAutoPlay(true);\r
+ }\r
+\r
+ /**\r
+ * Create a new <code>Picture</code>\r
+ *\r
+ * @param idx the index of the picture\r
+ * @param parent the parent shape\r
+ */\r
+ public MovieShape(int movieIdx, int idx, Shape parent) {\r
+ super(idx, parent);\r
+ setMovieIndex(movieIdx);\r
+ }\r
+\r
+ /**\r
+ * Create a <code>Picture</code> object\r
+ *\r
+ * @param escherRecord the <code>EscherSpContainer</code> record which holds information about\r
+ * this picture in the <code>Slide</code>\r
+ * @param parent the parent shape of this picture\r
+ */\r
+ protected MovieShape(EscherContainerRecord escherRecord, Shape parent){\r
+ super(escherRecord, parent);\r
+ }\r
+\r
+ /**\r
+ * Create a new Placeholder and initialize internal structures\r
+ *\r
+ * @return the created <code>EscherContainerRecord</code> which holds shape data\r
+ */\r
+ protected EscherContainerRecord createSpContainer(int idx, boolean isChild) {\r
+ _escherContainer = super.createSpContainer(idx, isChild);\r
+\r
+ setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x1000100);\r
+ setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x10001);\r
+\r
+ EscherClientDataRecord cldata = new EscherClientDataRecord();\r
+ cldata.setOptions((short)0xF);\r
+ _escherContainer.getChildRecords().add(cldata);\r
+\r
+ OEShapeAtom oe = new OEShapeAtom();\r
+ InteractiveInfo info = new InteractiveInfo();\r
+ InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom();\r
+ infoAtom.setAction(InteractiveInfoAtom.ACTION_MEDIA);\r
+ infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_NULL);\r
+\r
+ AnimationInfo an = new AnimationInfo();\r
+ AnimationInfoAtom anAtom = an.getAnimationInfoAtom();\r
+ anAtom.setFlag(AnimationInfoAtom.Automatic, true);\r
+\r
+ //convert hslf into ddf\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ try {\r
+ oe.writeOut(out);\r
+ an.writeOut(out);\r
+ info.writeOut(out);\r
+ } catch(Exception e){\r
+ throw new HSLFException(e);\r
+ }\r
+ cldata.setRemainingData(out.toByteArray());\r
+\r
+ return _escherContainer;\r
+ }\r
+\r
+ /**\r
+ * Assign a movie to this shape\r
+ *\r
+ * @see {@link org.apache.poi.hslf.usermodel.SlideShow#addMovie(String, int)}\r
+ * @param idx the index of the movie\r
+ */\r
+ public void setMovieIndex(int idx){\r
+ OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);\r
+ oe.setOptions(idx);\r
+\r
+ AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);\r
+ if(an != null) {\r
+ AnimationInfoAtom ai = an.getAnimationInfoAtom();\r
+ ai.setDimColor(0x07000000);\r
+ ai.setFlag(AnimationInfoAtom.Automatic, true);\r
+ ai.setFlag(AnimationInfoAtom.Play, true);\r
+ ai.setFlag(AnimationInfoAtom.Synchronous, true);\r
+ ai.setOrderID(idx + 1);\r
+ }\r
+ }\r
+\r
+ public void setAutoPlay(boolean flag){\r
+ AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);\r
+ if(an != null){\r
+ an.getAnimationInfoAtom().setFlag(AnimationInfoAtom.Automatic, flag);\r
+ updateClientData();\r
+ }\r
+ }\r
+\r
+ public boolean isAutoPlay(){\r
+ AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);\r
+ if(an != null){\r
+ return an.getAnimationInfoAtom().getFlag(AnimationInfoAtom.Automatic);\r
+ }\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Returns UNC or local path to a video file\r
+ *\r
+ * @return UNC or local path to a video file\r
+ */\r
+ public String getPath(){\r
+ OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);\r
+ int idx = oe.getOptions();\r
+\r
+ SlideShow ppt = getSheet().getSlideShow();\r
+ ExObjList lst = (ExObjList)ppt.getDocumentRecord().findFirstOfType(RecordTypes.ExObjList.typeID);\r
+ if(lst == null) return null;\r
+\r
+ Record[] r = lst.getChildRecords();\r
+ for (int i = 0; i < r.length; i++) {\r
+ if(r[i] instanceof ExMCIMovie){\r
+ ExMCIMovie mci = (ExMCIMovie)r[i];\r
+ ExVideoContainer exVideo = mci.getExVideo();\r
+ int objectId = exVideo.getExMediaAtom().getObjectId();\r
+ if(objectId == idx){\r
+ return exVideo.getPathAtom().getText();\r
+ }\r
+ }\r
+\r
+ }\r
+ return null;\r
+ }\r
+}\r
import org.apache.poi.ddf.*;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
+import org.apache.poi.hslf.record.*;
import java.util.List;
+import java.util.Iterator;
/**
* Create a <code>Shape</code> object depending on its type
public static ShapeGroup createShapeGroup(EscherContainerRecord spContainer, Shape parent){
ShapeGroup group = null;
- UnknownEscherRecord opt = (UnknownEscherRecord)Shape.getEscherChild((EscherContainerRecord)spContainer.getChild(0), (short)0xF122);
+ EscherRecord opt = Shape.getEscherChild((EscherContainerRecord)spContainer.getChild(0), (short)0xF122);
if(opt != null){
try {
EscherPropertyFactory f = new EscherPropertyFactory();
- List props = f.createProperties( opt.getData(), 0, opt.getInstance() );
+ List props = f.createProperties( opt.serialize(), 8, opt.getInstance() );
EscherSimpleProperty p = (EscherSimpleProperty)props.get(0);
if(p.getPropertyNumber() == 0x39F && p.getPropertyValue() == 1){
- group = new ShapeGroup(spContainer, parent);
+ group = new Table(spContainer, parent);
} else {
group = new ShapeGroup(spContainer, parent);
}
}
public static Shape createSimpeShape(EscherContainerRecord spContainer, Shape parent){
- Shape shape;
+ Shape shape = null;
EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID);
int type = spRecord.getOptions() >> 4;
case ShapeTypes.TextBox:
shape = new TextBox(spContainer, parent);
break;
- case ShapeTypes.HostControl:
+ case ShapeTypes.HostControl:
case ShapeTypes.PictureFrame: {
- EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
- EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.BLIP__PICTUREID);
- if(prop != null)
- shape = new OLEShape(spContainer, parent); //presence of BLIP__PICTUREID indicates it is an embedded object
- else
- shape = new Picture(spContainer, parent);
+ InteractiveInfo info = (InteractiveInfo)getClientDataRecord(spContainer, RecordTypes.InteractiveInfo.typeID);
+ OEShapeAtom oes = (OEShapeAtom)getClientDataRecord(spContainer, RecordTypes.OEShapeAtom.typeID);
+ if(info != null && info.getInteractiveInfoAtom() != null){
+ switch(info.getInteractiveInfoAtom().getAction()){
+ case InteractiveInfoAtom.ACTION_OLE:
+ shape = new OLEShape(spContainer, parent);
+ break;
+ case InteractiveInfoAtom.ACTION_MEDIA:
+ shape = new MovieShape(spContainer, parent);
+ break;
+ default:
+ break;
+ }
+ } else if (oes != null){
+ shape = new OLEShape(spContainer, parent);
+ }
+
+ if(shape == null) shape = new Picture(spContainer, parent);
break;
}
case ShapeTypes.Line:
return shape;
}
+
+ protected static Record getClientDataRecord(EscherContainerRecord spContainer, int recordType) {
+ Record oep = null;
+ for (Iterator it = spContainer.getChildRecords().iterator(); it.hasNext();) {
+ EscherRecord obj = (EscherRecord) it.next();
+ if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
+ byte[] data = obj.serialize();
+ Record[] records = Record.findChildRecords(data, 8, data.length - 8);
+ for (int j = 0; j < records.length; j++) {
+ if (records[j].getRecordType() == recordType) {
+ return records[j];
+ }
+ }
+ }
+ }
+ return oep;
+ }
+
}
import org.apache.poi.util.LittleEndian;
import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.hslf.record.Record;
+import org.apache.poi.hslf.exceptions.HSLFException;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
+import java.io.ByteArrayOutputStream;
/**
* An abstract simple (non-group) shape.
*/
public class SimpleShape extends Shape {
+ /**
+ * Records stored in EscherClientDataRecord
+ */
+ protected Record[] _clientRecords;
+ protected EscherClientDataRecord _clientData;
+
/**
* Create a SimpleShape object and initialize it from the supplied Record container.
*
* @param recordType type of the record to search
*/
protected Record getClientDataRecord(int recordType) {
- Record oep = null;
- EscherContainerRecord spContainer = getSpContainer();
- for (Iterator it = spContainer.getChildRecords().iterator(); it.hasNext();) {
- EscherRecord obj = (EscherRecord) it.next();
- if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
- byte[] data = obj.serialize();
- Record[] records = Record.findChildRecords(data, 8, data.length - 8);
- for (int j = 0; j < records.length; j++) {
- if (records[j].getRecordType() == recordType) {
- return records[j];
- }
- }
+
+ Record[] records = getClientRecords();
+ if(records != null) for (int i = 0; i < records.length; i++) {
+ if(records[i].getRecordType() == recordType){
+ return records[i];
+ }
+ }
+ return null;
+ }
+
+ protected Record[] getClientRecords() {
+ if(_clientData == null){
+ EscherRecord r = Shape.getEscherChild(getSpContainer(), EscherClientDataRecord.RECORD_ID);
+ //ddf can return EscherContainerRecord with recordId=EscherClientDataRecord.RECORD_ID
+ //convert in to EscherClientDataRecord on the fly
+ if(!(r instanceof EscherClientDataRecord)){
+ byte[] data = r.serialize();
+ r = new EscherClientDataRecord();
+ r.fillFields(data, 0, new DefaultEscherRecordFactory());
}
+ _clientData = (EscherClientDataRecord)r;
}
- return oep;
+ if(_clientData != null && _clientRecords == null){
+ byte[] data = _clientData.getRemainingData();
+ _clientRecords = Record.findChildRecords(data, 0, data.length);
+ }
+ return _clientRecords;
}
+ protected void updateClientData() {
+ if(_clientData != null && _clientRecords != null){
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try {
+ for (int i = 0; i < _clientRecords.length; i++) {
+ _clientRecords[i].writeOut(out);
+ }
+ } catch(Exception e){
+ throw new HSLFException(e);
+ }
+ _clientData.setRemainingData(out.toByteArray());
+ }
+ }
}
* @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape\r
* @param parent the parent of the shape\r
*/\r
- protected Table(EscherContainerRecord escherRecord, Shape parent) {\r
+ public Table(EscherContainerRecord escherRecord, Shape parent) {\r
super(escherRecord, parent);\r
}\r
\r
\r
import java.text.AttributedString;\r
import java.text.AttributedCharacterIterator;\r
+import java.text.BreakIterator;\r
import java.awt.font.TextAttribute;\r
import java.awt.font.LineBreakMeasurer;\r
import java.awt.font.TextLayout;\r
+import java.awt.font.FontRenderContext;\r
import java.awt.*;\r
import java.awt.geom.Rectangle2D;\r
import java.awt.geom.Point2D;\r
}\r
\r
public void paint(Graphics2D graphics){\r
+ Rectangle2D anchor = _shape.getLogicalAnchor2D();\r
+ TextElement[] elem = getTextElements((float)anchor.getWidth(), graphics.getFontRenderContext());\r
+ if(elem == null) return;\r
+\r
+ float textHeight = 0;\r
+ for (int i = 0; i < elem.length; i++) {\r
+ textHeight += elem[i].ascent + elem[i].descent;\r
+ }\r
+\r
+ int valign = _shape.getVerticalAlignment();\r
+ double y0 = anchor.getY();\r
+ switch (valign){\r
+ case TextShape.AnchorTopBaseline:\r
+ case TextShape.AnchorTop:\r
+ y0 += _shape.getMarginTop();\r
+ break;\r
+ case TextShape.AnchorBottom:\r
+ y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom();\r
+ break;\r
+ default:\r
+ case TextShape.AnchorMiddle:\r
+ float delta = (float)anchor.getHeight() - textHeight - _shape.getMarginTop() - _shape.getMarginBottom();\r
+ y0 += _shape.getMarginTop() + delta/2;\r
+ break;\r
+ }\r
+\r
+ //finally draw the text fragments\r
+ for (int i = 0; i < elem.length; i++) {\r
+ y0 += elem[i].ascent;\r
+\r
+ Point2D.Double pen = new Point2D.Double();\r
+ pen.y = y0;\r
+ switch (elem[i]._align) {\r
+ default:\r
+ case TextShape.AlignLeft:\r
+ pen.x = anchor.getX() + _shape.getMarginLeft();\r
+ break;\r
+ case TextShape.AlignCenter:\r
+ pen.x = anchor.getX() + _shape.getMarginLeft() +\r
+ (anchor.getWidth() - elem[i].advance - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;\r
+ break;\r
+ case TextShape.AlignRight:\r
+ pen.x = anchor.getX() + _shape.getMarginLeft() +\r
+ (anchor.getWidth() - elem[i].advance - _shape.getMarginLeft() - _shape.getMarginRight());\r
+ break;\r
+ }\r
+ if(elem[i]._bullet != null){\r
+ graphics.drawString(elem[i]._bullet.getIterator(), (float)(pen.x + elem[i]._bulletOffset), (float)pen.y);\r
+ }\r
+ AttributedCharacterIterator chIt = elem[i]._text.getIterator();\r
+ if(chIt.getEndIndex() > chIt.getBeginIndex()) {\r
+ graphics.drawString(chIt, (float)(pen.x + elem[i]._textOffset), (float)pen.y);\r
+ }\r
+ y0 += elem[i].descent;\r
+ }\r
+ }\r
+\r
+ public TextElement[] getTextElements(float textWidth, FontRenderContext frc){\r
TextRun run = _shape.getTextRun();\r
- if (run == null) return;\r
+ if (run == null) return null;\r
\r
String text = run.getText();\r
- if (text == null || text.equals("")) return;\r
+ if (text == null || text.equals("")) return null;\r
\r
AttributedString at = getAttributedString(run);\r
\r
int paragraphStart = it.getBeginIndex();\r
int paragraphEnd = it.getEndIndex();\r
\r
- Rectangle2D anchor = _shape.getLogicalAnchor2D();\r
-\r
- float textHeight = 0;\r
ArrayList lines = new ArrayList();\r
- LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext());\r
+ LineBreakMeasurer measurer = new LineBreakMeasurer(it, frc);\r
measurer.setPosition(paragraphStart);\r
while (measurer.getPosition() < paragraphEnd) {\r
int startIndex = measurer.getPosition();\r
break;\r
}\r
\r
- float wrappingWidth = (float)anchor.getWidth() - _shape.getMarginLeft() - _shape.getMarginRight();\r
+ float wrappingWidth = textWidth - _shape.getMarginLeft() - _shape.getMarginRight();\r
int bulletOffset = rt.getBulletOffset();\r
int textOffset = rt.getTextOffset();\r
int indent = rt.getIndentLevel();\r
if(text_val != 0) textOffset = text_val;\r
}\r
\r
- wrappingWidth -= textOffset;\r
+ if(bulletOffset > 0 || prStart || startIndex == 0) wrappingWidth -= textOffset;\r
\r
if (_shape.getWordWrap() == TextShape.WrapNone) {\r
wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;\r
TextLayout textLayout = measurer.nextLayout(wrappingWidth + 1,\r
nextBreak == -1 ? paragraphEnd : nextBreak, true);\r
if (textLayout == null) {\r
- textLayout = measurer.nextLayout((float)anchor.getWidth(),\r
+ textLayout = measurer.nextLayout(textWidth,\r
nextBreak == -1 ? paragraphEnd : nextBreak, false);\r
}\r
if(textLayout == null){\r
el.advance = textLayout.getAdvance();\r
el._textOffset = textOffset;\r
el._text = new AttributedString(it, startIndex, endIndex);\r
+ el.textStartIndex = startIndex;\r
+ el.textEndIndex = endIndex;\r
\r
if (prStart){\r
int sp = rt.getSpaceBefore();\r
}\r
el.descent = descent;\r
\r
- textHeight += el.ascent + el.descent;\r
-\r
if(rt.isBullet() && (prStart || startIndex == 0)){\r
it.setIndex(startIndex);\r
\r
lines.add(el);\r
}\r
\r
- int valign = _shape.getVerticalAlignment();\r
- double y0 = anchor.getY();\r
- switch (valign){\r
- case TextShape.AnchorTopBaseline:\r
- case TextShape.AnchorTop:\r
- y0 += _shape.getMarginTop();\r
- break;\r
- case TextShape.AnchorBottom:\r
- y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom();\r
- break;\r
- default:\r
- case TextShape.AnchorMiddle:\r
- float delta = (float)anchor.getHeight() - textHeight - _shape.getMarginTop() - _shape.getMarginBottom();\r
- y0 += _shape.getMarginTop() + delta/2;\r
- break;\r
- }\r
-\r
//finally draw the text fragments\r
- for (int i = 0; i < lines.size(); i++) {\r
- TextElement elem = (TextElement)lines.get(i);\r
- y0 += elem.ascent;\r
-\r
- Point2D.Double pen = new Point2D.Double();\r
- pen.y = y0;\r
- switch (elem._align) {\r
- default:\r
- case TextShape.AlignLeft:\r
- pen.x = anchor.getX() + _shape.getMarginLeft();\r
- break;\r
- case TextShape.AlignCenter:\r
- pen.x = anchor.getX() + _shape.getMarginLeft() +\r
- (anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;\r
- break;\r
- case TextShape.AlignRight:\r
- pen.x = anchor.getX() + _shape.getMarginLeft() +\r
- (anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight());\r
- break;\r
- }\r
- if(elem._bullet != null){\r
- graphics.drawString(elem._bullet.getIterator(), (float)(pen.x + elem._bulletOffset), (float)pen.y);\r
- }\r
- AttributedCharacterIterator chIt = elem._text.getIterator();\r
- if(chIt.getEndIndex() > chIt.getBeginIndex()) {\r
- graphics.drawString(chIt, (float)(pen.x + elem._textOffset), (float)pen.y);\r
- }\r
- y0 += elem.descent;\r
- }\r
+ TextElement[] elems = new TextElement[lines.size()];\r
+ return (TextElement[])lines.toArray(elems);\r
}\r
\r
-\r
public static class TextElement {\r
public AttributedString _text;\r
public int _textOffset;\r
public int _align;\r
public float ascent, descent;\r
public float advance;\r
+ public int textStartIndex, textEndIndex;\r
}\r
}\r
import java.util.LinkedList;
import java.util.Vector;
+import java.util.List;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.record.*;
protected TextBytesAtom _byteAtom;
protected TextCharsAtom _charAtom;
protected StyleTextPropAtom _styleAtom;
- protected boolean _isUnicode;
+ protected TextRulerAtom _ruler;
+ protected boolean _isUnicode;
protected RichTextRun[] _rtRuns;
private SlideShow slideShow;
private Sheet sheet;
pStyles = _styleAtom.getParagraphStyles();
cStyles = _styleAtom.getCharacterStyles();
}
-
- // Handle case of no current style, with a default
- if(pStyles.size() == 0 || cStyles.size() == 0) {
- _rtRuns = new RichTextRun[1];
- _rtRuns[0] = new RichTextRun(this, 0, runRawText.length());
- } else {
- // Build up Rich Text Runs, one for each
- // character/paragraph style pair
- Vector rtrs = new Vector();
-
- int pos = 0;
-
- int curP = 0;
- int curC = 0;
- int pLenRemain = -1;
- int cLenRemain = -1;
-
- // Build one for each run with the same style
- while(pos <= runRawText.length() && curP < pStyles.size() && curC < cStyles.size()) {
- // Get the Props to use
- TextPropCollection pProps = (TextPropCollection)pStyles.get(curP);
- TextPropCollection cProps = (TextPropCollection)cStyles.get(curC);
-
- int pLen = pProps.getCharactersCovered();
- int cLen = cProps.getCharactersCovered();
-
- // Handle new pass
- boolean freshSet = false;
- if(pLenRemain == -1 && cLenRemain == -1) { freshSet = true; }
- if(pLenRemain == -1) { pLenRemain = pLen; }
- if(cLenRemain == -1) { cLenRemain = cLen; }
-
- // So we know how to build the eventual run
- int runLen = -1;
- boolean pShared = false;
- boolean cShared = false;
-
- // Same size, new styles - neither shared
- if(pLen == cLen && freshSet) {
- runLen = cLen;
- pShared = false;
- cShared = false;
- curP++;
- curC++;
- pLenRemain = -1;
- cLenRemain = -1;
- } else {
- // Some sharing
-
- // See if we are already in a shared block
- if(pLenRemain < pLen) {
- // Existing shared p block
- pShared = true;
-
- // Do we end with the c block, or either side of it?
- if(pLenRemain == cLenRemain) {
- // We end at the same time
- cShared = false;
- runLen = pLenRemain;
- curP++;
- curC++;
- pLenRemain = -1;
- cLenRemain = -1;
- } else if(pLenRemain < cLenRemain) {
- // We end before the c block
- cShared = true;
- runLen = pLenRemain;
- curP++;
- cLenRemain -= pLenRemain;
- pLenRemain = -1;
- } else {
- // We end after the c block
- cShared = false;
- runLen = cLenRemain;
- curC++;
- pLenRemain -= cLenRemain;
- cLenRemain = -1;
- }
- } else if(cLenRemain < cLen) {
- // Existing shared c block
- cShared = true;
-
- // Do we end with the p block, or either side of it?
- if(pLenRemain == cLenRemain) {
- // We end at the same time
- pShared = false;
- runLen = cLenRemain;
- curP++;
- curC++;
- pLenRemain = -1;
- cLenRemain = -1;
- } else if(cLenRemain < pLenRemain) {
- // We end before the p block
- pShared = true;
- runLen = cLenRemain;
- curC++;
- pLenRemain -= cLenRemain;
- cLenRemain = -1;
- } else {
- // We end after the p block
- pShared = false;
- runLen = pLenRemain;
- curP++;
- cLenRemain -= pLenRemain;
- pLenRemain = -1;
- }
- } else {
- // Start of a shared block
- if(pLenRemain < cLenRemain) {
- // Shared c block
- pShared = false;
- cShared = true;
- runLen = pLenRemain;
- curP++;
- cLenRemain -= pLenRemain;
- pLenRemain = -1;
- } else {
- // Shared p block
- pShared = true;
- cShared = false;
- runLen = cLenRemain;
- curC++;
- pLenRemain -= cLenRemain;
- cLenRemain = -1;
- }
- }
- }
-
- // Wind on
- int prevPos = pos;
- pos += runLen;
- // Adjust for end-of-run extra 1 length
- if(pos > runRawText.length()) {
- runLen--;
- }
-
- // Save
- RichTextRun rtr = new RichTextRun(this, prevPos, runLen, pProps, cProps, pShared, cShared);
- rtrs.add(rtr);
- }
-
- // Build the array
- _rtRuns = new RichTextRun[rtrs.size()];
- rtrs.copyInto(_rtRuns);
- }
+ buildRichTextRuns(pStyles, cStyles, runRawText);
}
-
- // Update methods follow
+ public void buildRichTextRuns(LinkedList pStyles, LinkedList cStyles, String runRawText){
+
+ // Handle case of no current style, with a default
+ if(pStyles.size() == 0 || cStyles.size() == 0) {
+ _rtRuns = new RichTextRun[1];
+ _rtRuns[0] = new RichTextRun(this, 0, runRawText.length());
+ } else {
+ // Build up Rich Text Runs, one for each
+ // character/paragraph style pair
+ Vector rtrs = new Vector();
+
+ int pos = 0;
+
+ int curP = 0;
+ int curC = 0;
+ int pLenRemain = -1;
+ int cLenRemain = -1;
+
+ // Build one for each run with the same style
+ while(pos <= runRawText.length() && curP < pStyles.size() && curC < cStyles.size()) {
+ // Get the Props to use
+ TextPropCollection pProps = (TextPropCollection)pStyles.get(curP);
+ TextPropCollection cProps = (TextPropCollection)cStyles.get(curC);
+
+ int pLen = pProps.getCharactersCovered();
+ int cLen = cProps.getCharactersCovered();
+
+ // Handle new pass
+ boolean freshSet = false;
+ if(pLenRemain == -1 && cLenRemain == -1) { freshSet = true; }
+ if(pLenRemain == -1) { pLenRemain = pLen; }
+ if(cLenRemain == -1) { cLenRemain = cLen; }
+
+ // So we know how to build the eventual run
+ int runLen = -1;
+ boolean pShared = false;
+ boolean cShared = false;
+
+ // Same size, new styles - neither shared
+ if(pLen == cLen && freshSet) {
+ runLen = cLen;
+ pShared = false;
+ cShared = false;
+ curP++;
+ curC++;
+ pLenRemain = -1;
+ cLenRemain = -1;
+ } else {
+ // Some sharing
+
+ // See if we are already in a shared block
+ if(pLenRemain < pLen) {
+ // Existing shared p block
+ pShared = true;
+
+ // Do we end with the c block, or either side of it?
+ if(pLenRemain == cLenRemain) {
+ // We end at the same time
+ cShared = false;
+ runLen = pLenRemain;
+ curP++;
+ curC++;
+ pLenRemain = -1;
+ cLenRemain = -1;
+ } else if(pLenRemain < cLenRemain) {
+ // We end before the c block
+ cShared = true;
+ runLen = pLenRemain;
+ curP++;
+ cLenRemain -= pLenRemain;
+ pLenRemain = -1;
+ } else {
+ // We end after the c block
+ cShared = false;
+ runLen = cLenRemain;
+ curC++;
+ pLenRemain -= cLenRemain;
+ cLenRemain = -1;
+ }
+ } else if(cLenRemain < cLen) {
+ // Existing shared c block
+ cShared = true;
+
+ // Do we end with the p block, or either side of it?
+ if(pLenRemain == cLenRemain) {
+ // We end at the same time
+ pShared = false;
+ runLen = cLenRemain;
+ curP++;
+ curC++;
+ pLenRemain = -1;
+ cLenRemain = -1;
+ } else if(cLenRemain < pLenRemain) {
+ // We end before the p block
+ pShared = true;
+ runLen = cLenRemain;
+ curC++;
+ pLenRemain -= cLenRemain;
+ cLenRemain = -1;
+ } else {
+ // We end after the p block
+ pShared = false;
+ runLen = pLenRemain;
+ curP++;
+ cLenRemain -= pLenRemain;
+ pLenRemain = -1;
+ }
+ } else {
+ // Start of a shared block
+ if(pLenRemain < cLenRemain) {
+ // Shared c block
+ pShared = false;
+ cShared = true;
+ runLen = pLenRemain;
+ curP++;
+ cLenRemain -= pLenRemain;
+ pLenRemain = -1;
+ } else {
+ // Shared p block
+ pShared = true;
+ cShared = false;
+ runLen = cLenRemain;
+ curC++;
+ pLenRemain -= cLenRemain;
+ cLenRemain = -1;
+ }
+ }
+ }
+
+ // Wind on
+ int prevPos = pos;
+ pos += runLen;
+ // Adjust for end-of-run extra 1 length
+ if(pos > runRawText.length()) {
+ runLen--;
+ }
+
+ // Save
+ RichTextRun rtr = new RichTextRun(this, prevPos, runLen, pProps, cProps, pShared, cShared);
+ rtrs.add(rtr);
+ }
+
+ // Build the array
+ _rtRuns = new RichTextRun[rtrs.size()];
+ rtrs.copyInto(_rtRuns);
+ }
+
+ }
+
+ // Update methods follow
/**
* Adds the supplied text onto the end of the TextRun,
* @param run
* @param s
*/
- public synchronized void changeTextInRichTextRun(RichTextRun run, String s) {
+ public void changeTextInRichTextRun(RichTextRun run, String s) {
// Figure out which run it is
int runID = -1;
for(int i=0; i<_rtRuns.length; i++) {
* as the the first character has.
* If you care about styling, do setText on a RichTextRun instead
*/
- public synchronized void setRawText(String s) {
+ public void setRawText(String s) {
// Save the new text to the atoms
storeText(s);
RichTextRun fst = _rtRuns[0];
* Changes the text.
* Converts '\r' into '\n'
*/
- public synchronized void setText(String s) {
+ public void setText(String s) {
String text = normalize(s);
setRawText(text);
}
* Ensure a StyleTextPropAtom is present for this run,
* by adding if required. Normally for internal TextRun use.
*/
- public synchronized void ensureStyleAtomPresent() {
+ public void ensureStyleAtomPresent() {
if(_styleAtom != null) {
// All there
return;
}
public TextRulerAtom getTextRuler(){
- for (int i = 0; i < _records.length; i++) {
- if(_records[i] instanceof TextRulerAtom) return (TextRulerAtom)_records[i];
+ if(_ruler == null){
+ if(_records != null) for (int i = 0; i < _records.length; i++) {
+ if(_records[i] instanceof TextRulerAtom) {
+ _ruler = (TextRulerAtom)_records[i];
+ break;
+ }
+ }
+
}
- return null;
+ return _ruler;
}
+ public TextRulerAtom createTextRuler(){
+ _ruler = getTextRuler();
+ if(_ruler == null){
+ _ruler = TextRulerAtom.getParagraphInstance();
+ _headerAtom.getParentRecord().appendChildRecord(_ruler);
+ }
+ return _ruler;
+ }
+
/**
* Returns a new string with line breaks converted into internal ppt representation
*/
public Record[] getRecords(){
return _records;
}
+
}
_txtbox.appendChildRecord(sta);
_txtrun = new TextRun(tha,tca,sta);
+ _txtrun._records = new Record[]{tha, tca, sta};
_txtrun.setText("");
_escherContainer.addChildRecord(_txtbox.getEscherRecord());
--- /dev/null
+/*\r
+* Licensed to the Apache Software Foundation (ASF) under one or more\r
+* contributor license agreements. See the NOTICE file distributed with\r
+* this work for additional information regarding copyright ownership.\r
+* The ASF licenses this file to You under the Apache License, Version 2.0\r
+* (the "License"); you may not use this file except in compliance with\r
+* the License. You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*/\r
+package org.apache.poi.hslf.record;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+import org.apache.poi.util.POILogger;\r
+\r
+/**\r
+ * A container record that specifies information about animation information for a shape.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class AnimationInfo extends RecordContainer {\r
+ private byte[] _header;\r
+\r
+ // Links to our more interesting children\r
+ private AnimationInfoAtom animationAtom;\r
+\r
+ /**\r
+ * Set things up, and find our more interesting children\r
+ */\r
+ protected AnimationInfo(byte[] source, int start, int len) {\r
+ // Grab the header\r
+ _header = new byte[8];\r
+ System.arraycopy(source,start,_header,0,8);\r
+\r
+ // Find our children\r
+ _children = Record.findChildRecords(source,start+8,len-8);\r
+ findInterestingChildren();\r
+ }\r
+\r
+ /**\r
+ * Go through our child records, picking out the ones that are\r
+ * interesting, and saving those for use by the easy helper\r
+ * methods.\r
+ */ \r
+ private void findInterestingChildren() {\r
+\r
+ // First child should be the ExMediaAtom\r
+ if(_children[0] instanceof AnimationInfoAtom) {\r
+ animationAtom = (AnimationInfoAtom)_children[0];\r
+ } else {\r
+ logger.log(POILogger.ERROR, "First child record wasn't a AnimationInfoAtom, was of type " + _children[0].getRecordType());\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Create a new AnimationInfo, with blank fields\r
+ */\r
+ public AnimationInfo() {\r
+ // Setup our header block\r
+ _header = new byte[8];\r
+ _header[0] = 0x0f; // We are a container record\r
+ LittleEndian.putShort(_header, 2, (short)getRecordType());\r
+ \r
+ _children = new Record[1];\r
+ _children[0] = animationAtom = new AnimationInfoAtom();\r
+ }\r
+\r
+ /**\r
+ * We are of type 4103\r
+ */\r
+ public long getRecordType() { return RecordTypes.AnimationInfo.typeID; }\r
+\r
+ /**\r
+ * Write the contents of the record back, so it can be written\r
+ * to disk\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ writeOut(_header[0],_header[1],getRecordType(),_children,out);\r
+ }\r
+\r
+ /**\r
+ * Returns the AnimationInfo\r
+ */\r
+ public AnimationInfoAtom getAnimationInfoAtom() {\r
+ return animationAtom;\r
+ }\r
+\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.util.Date;\r
+\r
+import org.apache.poi.hslf.util.SystemTimeUtils;\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+/**\r
+ * An atom record that specifies the animation information for a shape.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class AnimationInfoAtom extends RecordAtom\r
+{\r
+\r
+ /**\r
+ * whether the animation plays in the reverse direction\r
+ */\r
+ public static final int Reverse = 1;\r
+ /**\r
+ * whether the animation starts automatically\r
+ */\r
+ public static final int Automatic = 4;\r
+ /**\r
+ * whether the animation has an associated sound\r
+ */\r
+ public static final int Sound = 16;\r
+ /**\r
+ * whether all playing sounds are stopped when this animation begins\r
+ */\r
+ public static final int StopSound = 64;\r
+ /**\r
+ * whether an associated sound, media or action verb is activated when the shape is clicked.\r
+ */\r
+ public static final int Play = 256;\r
+ /**\r
+ * specifies that the animation, while playing, stops other slide show actions.\r
+ */\r
+ public static final int Synchronous = 1024;\r
+ /**\r
+ * whether the shape is hidden while the animation is not playing\r
+ */\r
+ public static final int Hide = 4096;\r
+ /**\r
+ * whether the background of the shape is animated\r
+ */\r
+ public static final int AnimateBg = 16384;\r
+\r
+ /**\r
+ * Record header.\r
+ */\r
+ private byte[] _header;\r
+\r
+ /**\r
+ * record data\r
+ */\r
+ private byte[] _recdata;\r
+\r
+ /**\r
+ * Constructs a brand new link related atom record.\r
+ */\r
+ protected AnimationInfoAtom() {\r
+ _recdata = new byte[28];\r
+\r
+ _header = new byte[8];\r
+ LittleEndian.putShort(_header, 0, (short)0x01);\r
+ LittleEndian.putShort(_header, 2, (short)getRecordType());\r
+ LittleEndian.putInt(_header, 4, _recdata.length);\r
+ }\r
+\r
+ /**\r
+ * Constructs the link related atom record from its\r
+ * source data.\r
+ *\r
+ * @param source the source data as a byte array.\r
+ * @param start the start offset into the byte array.\r
+ * @param len the length of the slice in the byte array.\r
+ */\r
+ protected AnimationInfoAtom(byte[] source, int start, int len) {\r
+ // Get the header\r
+ _header = new byte[8];\r
+ System.arraycopy(source,start,_header,0,8);\r
+\r
+ // Grab the record data\r
+ _recdata = new byte[len-8];\r
+ System.arraycopy(source,start+8,_recdata,0,len-8);\r
+ }\r
+\r
+ /**\r
+ * Gets the record type.\r
+ * @return the record type.\r
+ */\r
+ public long getRecordType() {\r
+ return RecordTypes.AnimationInfoAtom.typeID;\r
+ }\r
+\r
+ /**\r
+ * Write the contents of the record back, so it can be written\r
+ * to disk\r
+ *\r
+ * @param out the output stream to write to.\r
+ * @throws java.io.IOException if an error occurs.\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ out.write(_header);\r
+ out.write(_recdata);\r
+ }\r
+\r
+ /**\r
+ * A rgb structure that specifies a color for the dim effect after the animation is complete.\r
+ *\r
+ * @return color for the dim effect after the animation is complete\r
+ */\r
+ public int getDimColor(){\r
+ return LittleEndian.getInt(_recdata, 0);\r
+ }\r
+\r
+ /**\r
+ * A rgb structure that specifies a color for the dim effect after the animation is complete.\r
+ *\r
+ * @param rgb color for the dim effect after the animation is complete\r
+ */\r
+ public void setDimColor(int rgb){\r
+ LittleEndian.putInt(_recdata, 0, rgb);\r
+ }\r
+\r
+ /**\r
+ * A bit mask specifying options for displaying headers and footers\r
+ *\r
+ * @return A bit mask specifying options for displaying headers and footers\r
+ */\r
+ public int getMask(){\r
+ return LittleEndian.getInt(_recdata, 4);\r
+ }\r
+\r
+ /**\r
+ * A bit mask specifying options for displaying video\r
+ *\r
+ * @param mask A bit mask specifying options for displaying video\r
+ */\r
+ public void setMask(int mask){\r
+ LittleEndian.putInt(_recdata, 4, mask);\r
+ }\r
+\r
+ /**\r
+ * @param bit the bit to check\r
+ * @return whether the specified flag is set\r
+ */\r
+ public boolean getFlag(int bit){\r
+ return (getMask() & bit) != 0;\r
+ }\r
+\r
+ /**\r
+ * @param bit the bit to set\r
+ * @param value whether the specified bit is set\r
+ */\r
+ public void setFlag(int bit, boolean value){\r
+ int mask = getMask();\r
+ if(value) mask |= bit;\r
+ else mask &= ~bit;\r
+ setMask(mask);\r
+ }\r
+\r
+ /**\r
+ * A 4-byte unsigned integer that specifies a reference to a sound\r
+ * in the SoundCollectionContainer record to locate the embedded audio\r
+ *\r
+ * @return reference to a sound\r
+ */\r
+ public int getSoundIdRef(){\r
+ return LittleEndian.getInt(_recdata, 8);\r
+ }\r
+\r
+ /**\r
+ * A 4-byte unsigned integer that specifies a reference to a sound\r
+ * in the SoundCollectionContainer record to locate the embedded audio\r
+ *\r
+ * @param id reference to a sound\r
+ */\r
+ public void setSoundIdRef(int id){\r
+ LittleEndian.putInt(_recdata, 8, id);\r
+ }\r
+\r
+ /**\r
+ * A signed integer that specifies the delay time, in milliseconds, before the animation starts to play.\r
+ * If {@link Automatic} is 0x1, this value MUST be greater than or equal to 0; otherwise, this field MUST be ignored.\r
+ */\r
+ public int getDelayTime(){\r
+ return LittleEndian.getInt(_recdata, 12);\r
+ }\r
+ /**\r
+ * A signed integer that specifies the delay time, in milliseconds, before the animation starts to play.\r
+ * If {@link Automatic} is 0x1, this value MUST be greater than or equal to 0; otherwise, this field MUST be ignored.\r
+ */\r
+ public void setDelayTime(int id){\r
+ LittleEndian.putInt(_recdata, 12, id);\r
+ }\r
+\r
+ /**\r
+ * A signed integer that specifies the order of the animation in the slide.\r
+ * It MUST be greater than or equal to -2. The value -2 specifies that this animation follows the order of\r
+ * the corresponding placeholder shape on the main master slide or title master slide.\r
+ * The value -1 SHOULD NOT <105> be used.\r
+ */\r
+ public int getOrderID(){\r
+ return LittleEndian.getInt(_recdata, 16);\r
+ }\r
+\r
+ /**\r
+ * A signed integer that specifies the order of the animation in the slide.\r
+ * It MUST be greater than or equal to -2. The value -2 specifies that this animation follows the order of\r
+ * the corresponding placeholder shape on the main master slide or title master slide.\r
+ * The value -1 SHOULD NOT <105> be used.\r
+ */\r
+ public void setOrderID(int id){\r
+ LittleEndian.putInt(_recdata, 16, id);\r
+ }\r
+\r
+ /**\r
+ * An unsigned integer that specifies the number of slides that this animation continues playing.\r
+ * This field is utilized only in conjunction with media.\r
+ * The value 0xFFFFFFFF specifies that the animation plays for one slide.\r
+ */\r
+ public int getSlideCount(){\r
+ return LittleEndian.getInt(_recdata, 18);\r
+ }\r
+\r
+ /**\r
+ * An unsigned integer that specifies the number of slides that this animation continues playing.\r
+ * This field is utilized only in conjunction with media.\r
+ * The value 0xFFFFFFFF specifies that the animation plays for one slide.\r
+ */\r
+ public void setSlideCount(int id){\r
+ LittleEndian.putInt(_recdata, 18, id);\r
+ }\r
+\r
+ public String toString(){\r
+ StringBuffer buf = new StringBuffer();\r
+ buf.append("AnimationInfoAtom\n");\r
+ buf.append("\tDimColor: " + getDimColor() + "\n");\r
+ int mask = getMask();\r
+ buf.append("\tMask: " + mask + ", 0x"+Integer.toHexString(mask)+"\n");\r
+ buf.append("\t Reverse: " + getFlag(Reverse)+"\n");\r
+ buf.append("\t Automatic: " + getFlag(Automatic)+"\n");\r
+ buf.append("\t Sound: " + getFlag(Sound)+"\n");\r
+ buf.append("\t StopSound: " + getFlag(StopSound)+"\n");\r
+ buf.append("\t Play: " + getFlag(Play)+"\n");\r
+ buf.append("\t Synchronous: " + getFlag(Synchronous)+"\n");\r
+ buf.append("\t Hide: " + getFlag(Hide)+"\n");\r
+ buf.append("\t AnimateBg: " + getFlag(AnimateBg)+"\n");\r
+ buf.append("\tSoundIdRef: " + getSoundIdRef() + "\n");\r
+ buf.append("\tDelayTime: " + getDelayTime() + "\n");\r
+ buf.append("\tOrderID: " + getOrderID() + "\n");\r
+ buf.append("\tSlideCount: " + getSlideCount() + "\n");\r
+ return buf.toString();\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+* Licensed to the Apache Software Foundation (ASF) under one or more\r
+* contributor license agreements. See the NOTICE file distributed with\r
+* this work for additional information regarding copyright ownership.\r
+* The ASF licenses this file to You under the Apache License, Version 2.0\r
+* (the "License"); you may not use this file except in compliance with\r
+* the License. You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*/\r
+package org.apache.poi.hslf.record;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+import org.apache.poi.util.POILogger;\r
+\r
+/**\r
+ * A container record that specifies information about a movie stored externally.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class ExAviMovie extends ExMCIMovie {\r
+\r
+ /**\r
+ * Set things up, and find our more interesting children\r
+ */\r
+ protected ExAviMovie(byte[] source, int start, int len) {\r
+ super(source, start, len);\r
+ }\r
+\r
+ /**\r
+ * Create a new ExAviMovie, with blank fields\r
+ */\r
+ public ExAviMovie() {\r
+ super();\r
+\r
+ }\r
+ /**\r
+ * We are of type 4102\r
+ */\r
+ public long getRecordType() {\r
+ return RecordTypes.ExAviMovie.typeID;\r
+ }\r
+\r
+}\r
import org.apache.poi.util.POILogger;\r
\r
/**\r
- * Container for OLE Control object. It contains:\r
+ * A container record that specifies information about an ActiveX control. It contains:\r
* <p>\r
* 1. ExControlAtom (4091)\r
* 2. ExOleObjAtom (4035)\r
*/\r
public class ExControl extends ExEmbed {\r
\r
- // Links to our more interesting children\r
- private ExControlAtom ctrlAtom;\r
-\r
/**\r
* Set things up, and find our more interesting children\r
*\r
public ExControl() {\r
super();\r
\r
- _children[0] = ctrlAtom = new ExControlAtom();\r
+ _children[0] = embedAtom = new ExControlAtom();\r
}\r
\r
/**\r
*/\r
public ExControlAtom getExControlAtom()\r
{\r
- return ctrlAtom;\r
+ return (ExControlAtom)_children[0];\r
}\r
\r
/**\r
public long getRecordType() {\r
return RecordTypes.ExControl.typeID;\r
}\r
-\r
- protected RecordAtom getEmbedAtom(Record[] children){\r
- RecordAtom atom = null;\r
- if(_children[0] instanceof ExControlAtom) {\r
- atom = (ExControlAtom)_children[0];\r
- } else {\r
- logger.log(POILogger.ERROR, "First child record wasn't a ExControlAtom, was of type " + _children[0].getRecordType());\r
- }\r
- return atom;\r
- }\r
}\r
import org.apache.poi.util.LittleEndian;\r
\r
/**\r
- * Contains a long integer, slideID, which stores the unique slide identifier of the slide\r
- * where this control resides.\r
+ * An atom record that specifies an ActiveX control.\r
*\r
* @author Yegor Kozlov\r
*/\r
_id = LittleEndian.getInt(source, start + 8);\r
}\r
\r
+ /**\r
+ * An integer that specifies which presentation slide is associated with the ActiveX control.\r
+ * <p>\r
+ * It MUST be 0x00000000 or equal to the value of the slideId field of a SlidePersistAtom record.\r
+ * The value 0x00000000 specifies a null reference.\r
+ * </p>\r
+ *\r
+ * @return an integer that specifies which presentation slide is associated with the ActiveX control\r
+ */\r
public int getSlideId() {\r
return _id;\r
}\r
\r
+ /**\r
+ * Sets which presentation slide is associated with the ActiveX control.\r
+ *\r
+ * @param id an integer that specifies which presentation slide is associated with the ActiveX control\r
+ * <p>\r
+ * It MUST be 0x00000000 or equal to the value of the slideId field of a SlidePersistAtom record.\r
+ * The value 0x00000000 specifies a null reference.\r
+ * </p>\r
+ */\r
+ public void setSlideId(int id) {\r
+ _id = id;\r
+ }\r
+\r
/**\r
* Gets the record type.\r
* @return the record type.\r
private byte[] _header;
// Links to our more interesting children
- private RecordAtom embedAtom;
+ protected RecordAtom embedAtom;
private ExOleObjAtom oleObjAtom;
private CString menuName;
private CString progId;
// Setup our child records
CString cs1 = new CString();
+ cs1.setOptions(0x1 << 4);
CString cs2 = new CString();
+ cs2.setOptions(0x2 << 4);
CString cs3 = new CString();
-// cs1.setOptions(0x00);
-// cs2.setOptions(0x10);
+ cs3.setOptions(0x3 << 4);
_children[0] = new ExEmbedAtom();
_children[1] = new ExOleObjAtom();
_children[2] = cs1;
private void findInterestingChildren() {
// First child should be the ExHyperlinkAtom
- embedAtom = getEmbedAtom(_children);
+ if(_children[0] instanceof ExEmbedAtom) {
+ embedAtom = (ExEmbedAtom)_children[0];
+ } else {
+ logger.log(POILogger.ERROR, "First child record wasn't a ExEmbedAtom, was of type " + _children[0].getRecordType());
+ }
// Second child should be the ExOleObjAtom
if (_children[1] instanceof ExOleObjAtom) {
for (int i = 2; i < _children.length; i++) {
if (_children[i] instanceof CString){
- if (menuName == null) menuName = (CString)_children[i];
- else if (progId == null) progId = (CString)_children[i];
- else if (clipboardName == null) clipboardName = (CString)_children[i];
- } else {
- logger.log(POILogger.ERROR, "Record after atoms wasn't a CString, was of type " + _children[i].getRecordType());
+ CString cs = (CString)_children[i];
+ int opts = cs.getOptions() >> 4;
+ switch(opts){
+ case 0x1: menuName = cs; break;
+ case 0x2: progId = cs; break;
+ case 0x3: clipboardName = cs; break;
+ }
}
}
}
- protected RecordAtom getEmbedAtom(Record[] children){
- RecordAtom atom = null;
- if(_children[0] instanceof ExEmbedAtom) {
- atom = (ExEmbedAtom)_children[0];
- } else {
- logger.log(POILogger.ERROR, "First child record wasn't a ExEmbedAtom, was of type " + _children[0].getRecordType());
- }
- return atom;
- }
-
/**
* Gets the {@link ExEmbedAtom}.
*
return menuName == null ? null : menuName.getText();
}
+ public void setMenuName(String s)
+ {
+ if(menuName != null) menuName.setText(s);
+ }
+
/**
* Gets the OLE Programmatic Identifier.
*
return progId == null ? null : progId.getText();
}
+ public void setProgId(String s)
+ {
+ if(progId != null) progId.setText(s);
+ }
/**
* Gets the name that appears in the paste special dialog.
*
return clipboardName == null ? null : clipboardName.getText();
}
+ public void setClipboardName(String s)
+ {
+ if(clipboardName != null) clipboardName.setText(s);
+ }
/**
* Returns the type (held as a little endian in bytes 3 and 4)
* that this class handles.
--- /dev/null
+/*\r
+* Licensed to the Apache Software Foundation (ASF) under one or more\r
+* contributor license agreements. See the NOTICE file distributed with\r
+* this work for additional information regarding copyright ownership.\r
+* The ASF licenses this file to You under the Apache License, Version 2.0\r
+* (the "License"); you may not use this file except in compliance with\r
+* the License. You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*/\r
+package org.apache.poi.hslf.record;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+import org.apache.poi.util.POILogger;\r
+\r
+/**\r
+ * A container record that specifies information about a movie stored externally.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class ExMCIMovie extends RecordContainer {\r
+ private byte[] _header;\r
+\r
+ //An ExVideoContainer record that specifies information about the MCI movie\r
+ private ExVideoContainer exVideo;\r
+\r
+ /**\r
+ * Set things up, and find our more interesting children\r
+ */\r
+ protected ExMCIMovie(byte[] source, int start, int len) {\r
+ // Grab the header\r
+ _header = new byte[8];\r
+ System.arraycopy(source, start, _header, 0, 8);\r
+\r
+ // Find our children\r
+ _children = Record.findChildRecords(source, start + 8, len - 8);\r
+ findInterestingChildren();\r
+ }\r
+\r
+ /**\r
+ * Create a new ExMCIMovie, with blank fields\r
+ */\r
+ public ExMCIMovie() {\r
+ _header = new byte[8];\r
+ // Setup our header block\r
+ _header[0] = 0x0f; // We are a container record\r
+ LittleEndian.putShort(_header, 2, (short) getRecordType());\r
+\r
+ exVideo = new ExVideoContainer();\r
+ _children = new Record[]{exVideo};\r
+\r
+ }\r
+\r
+ /**\r
+ * Go through our child records, picking out the ones that are\r
+ * interesting, and saving those for use by the easy helper\r
+ * methods.\r
+ */\r
+ private void findInterestingChildren() {\r
+\r
+ // First child should be the ExVideoContainer\r
+ if (_children[0] instanceof ExVideoContainer) {\r
+ exVideo = (ExVideoContainer) _children[0];\r
+ } else {\r
+ logger.log(POILogger.ERROR, "First child record wasn't a ExVideoContainer, was of type " + _children[0].getRecordType());\r
+ }\r
+ }\r
+\r
+ /**\r
+ * We are of type 4103\r
+ */\r
+ public long getRecordType() {\r
+ return RecordTypes.ExMCIMovie.typeID;\r
+ }\r
+\r
+ /**\r
+ * Write the contents of the record back, so it can be written\r
+ * to disk\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ writeOut(_header[0], _header[1], getRecordType(), _children, out);\r
+ }\r
+\r
+ /**\r
+ * Returns the ExVideoContainer that specifies information about the MCI movie\r
+ */\r
+ public ExVideoContainer getExVideo() {\r
+ return exVideo; }\r
+\r
+\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.util.Date;\r
+\r
+import org.apache.poi.hslf.util.SystemTimeUtils;\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+/**\r
+ * An atom record that specifies information about external audio or video data.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class ExMediaAtom extends RecordAtom\r
+{\r
+\r
+ /**\r
+ * A bit that specifies whether the audio or video data is repeated continuously during playback.\r
+ */\r
+ public static final int fLoop = 1;\r
+ /**\r
+ * A bit that specifies whether the audio or video data is rewound after playing.\r
+ */\r
+ public static final int fRewind = 2;\r
+ /**\r
+ * A bit that specifies whether the audio data is recorded narration for the slide show. It MUST be FALSE if this ExMediaAtom record is contained by an ExVideoContainer record.\r
+ */\r
+ public static final int fNarration = 4;\r
+\r
+ /**\r
+ * Record header.\r
+ */\r
+ private byte[] _header;\r
+\r
+ /**\r
+ * record data\r
+ */\r
+ private byte[] _recdata;\r
+\r
+ /**\r
+ * Constructs a brand new link related atom record.\r
+ */\r
+ protected ExMediaAtom() {\r
+ _recdata = new byte[8];\r
+\r
+ _header = new byte[8];\r
+ LittleEndian.putShort(_header, 2, (short)getRecordType());\r
+ LittleEndian.putInt(_header, 4, _recdata.length);\r
+ }\r
+\r
+ /**\r
+ * Constructs the link related atom record from its\r
+ * source data.\r
+ *\r
+ * @param source the source data as a byte array.\r
+ * @param start the start offset into the byte array.\r
+ * @param len the length of the slice in the byte array.\r
+ */\r
+ protected ExMediaAtom(byte[] source, int start, int len) {\r
+ // Get the header\r
+ _header = new byte[8];\r
+ System.arraycopy(source,start,_header,0,8);\r
+\r
+ // Grab the record data\r
+ _recdata = new byte[len-8];\r
+ System.arraycopy(source,start+8,_recdata,0,len-8);\r
+ }\r
+\r
+ /**\r
+ * Gets the record type.\r
+ * @return the record type.\r
+ */\r
+ public long getRecordType() { return RecordTypes.ExMediaAtom.typeID; }\r
+\r
+ /**\r
+ * Write the contents of the record back, so it can be written\r
+ * to disk\r
+ *\r
+ * @param out the output stream to write to.\r
+ * @throws java.io.IOException if an error occurs.\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ out.write(_header);\r
+ out.write(_recdata);\r
+ }\r
+\r
+ /**\r
+ * A 4-byte unsigned integer that specifies an ID for an external object.\r
+ *\r
+ * @return A 4-byte unsigned integer that specifies an ID for an external object.\r
+ */\r
+ public int getObjectId(){\r
+ return LittleEndian.getInt(_recdata, 0);\r
+ }\r
+\r
+ /**\r
+ * A 4-byte unsigned integer that specifies an ID for an external object.\r
+ *\r
+ * @param id A 4-byte unsigned integer that specifies an ID for an external object.\r
+ */\r
+ public void setObjectId(int id){\r
+ LittleEndian.putInt(_recdata, 0, id);\r
+ }\r
+\r
+ /**\r
+ * A bit mask specifying options for displaying headers and footers\r
+ *\r
+ * @return A bit mask specifying options for displaying headers and footers\r
+ */\r
+ public int getMask(){\r
+ return LittleEndian.getInt(_recdata, 4);\r
+ }\r
+\r
+ /**\r
+ * A bit mask specifying options for displaying video\r
+ *\r
+ * @param mask A bit mask specifying options for displaying video\r
+ */\r
+ public void setMask(int mask){\r
+ LittleEndian.putInt(_recdata, 4, mask);\r
+ }\r
+\r
+ /**\r
+ * @param bit the bit to check\r
+ * @return whether the specified flag is set\r
+ */\r
+ public boolean getFlag(int bit){\r
+ return (getMask() & bit) != 0;\r
+ }\r
+\r
+ /**\r
+ * @param bit the bit to set\r
+ * @param value whether the specified bit is set\r
+ */\r
+ public void setFlag(int bit, boolean value){\r
+ int mask = getMask();\r
+ if(value) mask |= bit;\r
+ else mask &= ~bit;\r
+ setMask(mask);\r
+ }\r
+\r
+ public String toString(){\r
+ StringBuffer buf = new StringBuffer();\r
+ buf.append("ExMediaAtom\n");\r
+ buf.append("\tObjectId: " + getObjectId() + "\n");\r
+ buf.append("\tMask : " + getMask() + "\n");\r
+ buf.append("\t fLoop : " + getFlag(fLoop) + "\n");\r
+ buf.append("\t fRewind : " + getFlag(fRewind) + "\n");\r
+ buf.append("\t fNarration : " + getFlag(fNarration) + "\n");\r
+ return buf.toString();\r
+ }\r
+\r
+}\r
*/
public class ExOleObjAtom extends RecordAtom {
+ /**
+ * The object) is displayed as an embedded object inside of a container,
+ */
public static final int DRAW_ASPECT_VISIBLE = 1;
+ /**
+ * The object is displayed as a thumbnail image.
+ */
+ public static final int DRAW_ASPECT_THUMBNAIL = 2;
+ /**
+ * The object is displayed as an icon.
+ */
public static final int DRAW_ASPECT_ICON = 4;
+ /**
+ * The object is displayed on the screen as though it were printed to a printer.
+ */
+ public static final int DRAW_ASPECT_DOCPRINT = 8;
+ /**
+ * An embedded OLE object; the object is serialized and saved within the file.
+ */
public static final int TYPE_EMBEDDED = 0;
+ /**
+ * A linked OLE object; the object is saved outside of the file.
+ */
public static final int TYPE_LINKED = 1;
+ /**
+ * The OLE object is an ActiveX control.
+ */
+ public static final int TYPE_CONTROL = 2;
public static final int SUBTYPE_DEFAULT = 0;
public static final int SUBTYPE_CLIPART_GALLERY = 1;
/**
* Constructs a brand new link related atom record.
*/
- protected ExOleObjAtom() {
+ public ExOleObjAtom() {
_header = new byte[8];
- _data = new byte[18];
+ _data = new byte[24];
+ LittleEndian.putShort(_header, 0, (short)1); //MUST be 0x1
LittleEndian.putShort(_header, 2, (short)getRecordType());
LittleEndian.putInt(_header, 4, _data.length);
-
- // I hope it is fine for the other values to be zero.
}
/**
return LittleEndian.getInt(_data, 0);
}
+ /**
+ * Sets whether the object can be completely seen, or if only the
+ * icon is visible.
+ *
+ * @param aspect the draw aspect, one of the {@code DRAW_ASPECT_*} constants.
+ */
+ public void setDrawAspect(int aspect) {
+ LittleEndian.putInt(_data, 0, aspect);
+ }
+
/**
* Gets whether the object is embedded or linked.
*
return LittleEndian.getInt(_data, 4);
}
+ /**
+ * Sets whether the object is embedded or linked.
+ *
+ * @param type the type, one of the {@code TYPE_EMBEDDED_*} constants.
+ */
+ public void setType(int type) {
+ LittleEndian.putInt(_data, 4, type);
+ }
+
/**
* Gets the unique identifier for the OLE object.
*
return LittleEndian.getInt(_data, 8);
}
+ /**
+ * Sets the unique identifier for the OLE object.
+ *
+ * @param id the object ID.
+ */
+ public void setObjID(int id) {
+ LittleEndian.putInt(_data, 8, id);
+ }
+
/**
* Gets the type of OLE object.
*
return LittleEndian.getInt(_data, 12);
}
+ /**
+ * Sets the type of OLE object.
+ *
+ * @param type the sub-type, one of the {@code SUBTYPE_*} constants.
+ */
+ public void setSubType(int type) {
+ LittleEndian.putInt(_data, 12, type);
+ }
+
/**
* Gets the reference to the persistent object
*
return LittleEndian.getInt(_data, 16);
}
+ /**
+ * Sets the reference to the persistent object
+ *
+ * @param ref the reference to the persistent object, corresponds with an
+ * {@code ExOleObjStg} storage container.
+ */
+ public void setObjStgDataRef(int ref) {
+ LittleEndian.putInt(_data, 16, ref);
+ }
+
/**
* Gets whether the object's image is blank.
*
return LittleEndian.getInt(_data, 20) != 0;
}
+ /**
+ * Gets misc options (the last four bytes in the atom).
+ *
+ * @return {@code true} if the object's image is blank.
+ */
+ public int getOptions() {
+ // Even though this is a mere boolean, KOffice's code says it's an int.
+ return LittleEndian.getInt(_data, 20);
+ }
+
+ /**
+ * Sets misc options (the last four bytes in the atom).
+ */
+ public void setOptions(int opts) {
+ // Even though this is a mere boolean, KOffice's code says it's an int.
+ LittleEndian.putInt(_data, 20, opts);
+ }
+
/**
* Returns the type (held as a little endian in bytes 3 and 4)
* that this class handles.
out.write(_header);
out.write(_data);
}
+
+ public String toString(){
+ StringBuffer buf = new StringBuffer();
+ buf.append("ExOleObjAtom\n");
+ buf.append(" drawAspect: " + getDrawAspect() + "\n");
+ buf.append(" type: " + getType() + "\n");
+ buf.append(" objID: " + getObjID() + "\n");
+ buf.append(" subType: " + getSubType() + "\n");
+ buf.append(" objStgDataRef: " + getObjStgDataRef() + "\n");
+ buf.append(" options: " + getOptions() + "\n");
+ return buf.toString();
+ }
}
import java.io.*;
import java.util.zip.InflaterInputStream;
import java.util.zip.DeflaterOutputStream;
+import java.util.Hashtable;
import org.apache.poi.util.LittleEndian;
*
* @author Daniel Noll
*/
-public class ExOleObjStg extends RecordAtom implements PersistRecord {
+public class ExOleObjStg extends RecordAtom implements PositionDependentRecord, PersistRecord {
private int _persistId; // Found from PersistPtrHolder
/**
* Constructs a new empty storage container.
*/
- protected ExOleObjStg() {
+ public ExOleObjStg() {
_header = new byte[8];
_data = new byte[0];
+ LittleEndian.putShort(_header, 0, (short)0x10);
LittleEndian.putShort(_header, 2, (short)getRecordType());
LittleEndian.putInt(_header, 4, _data.length);
}
return new InflaterInputStream(compressedStream);
}
+ public byte[] getRawData() {
+ return _data;
+ }
+
/**
* Sets the embedded data.
*
public void setPersistId(int id) {
_persistId = id;
}
+
+ /** Our location on the disk, as of the last write out */
+ protected int myLastOnDiskOffset;
+
+ /** Fetch our location on the disk, as of the last write out */
+ public int getLastOnDiskOffset() { return myLastOnDiskOffset; }
+
+ /**
+ * Update the Record's idea of where on disk it lives, after a write out.
+ * Use with care...
+ */
+ public void setLastOnDiskOffset(int offset) {
+ myLastOnDiskOffset = offset;
+ }
+
+ public void updateOtherRecordReferences(Hashtable oldToNewReferencesLookup) {
+ return;
+ }
+
}
--- /dev/null
+/*\r
+* Licensed to the Apache Software Foundation (ASF) under one or more\r
+* contributor license agreements. See the NOTICE file distributed with\r
+* this work for additional information regarding copyright ownership.\r
+* The ASF licenses this file to You under the Apache License, Version 2.0\r
+* (the "License"); you may not use this file except in compliance with\r
+* the License. You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*/\r
+package org.apache.poi.hslf.record;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+import org.apache.poi.util.POILogger;\r
+\r
+/**\r
+ * A container record that specifies information about external video data.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class ExVideoContainer extends RecordContainer {\r
+ private byte[] _header;\r
+\r
+ // Links to our more interesting children\r
+ private ExMediaAtom mediaAtom;\r
+ //the UNC or local path to a video file.\r
+ private CString pathAtom;\r
+\r
+ /**\r
+ * Set things up, and find our more interesting children\r
+ */\r
+ protected ExVideoContainer(byte[] source, int start, int len) {\r
+ // Grab the header\r
+ _header = new byte[8];\r
+ System.arraycopy(source,start,_header,0,8);\r
+\r
+ // Find our children\r
+ _children = Record.findChildRecords(source,start+8,len-8);\r
+ findInterestingChildren();\r
+ }\r
+\r
+ /**\r
+ * Go through our child records, picking out the ones that are\r
+ * interesting, and saving those for use by the easy helper\r
+ * methods.\r
+ */ \r
+ private void findInterestingChildren() {\r
+\r
+ // First child should be the ExMediaAtom\r
+ if(_children[0] instanceof ExMediaAtom) {\r
+ mediaAtom = (ExMediaAtom)_children[0];\r
+ } else {\r
+ logger.log(POILogger.ERROR, "First child record wasn't a ExMediaAtom, was of type " + _children[0].getRecordType());\r
+ }\r
+ if(_children[1] instanceof CString) {\r
+ pathAtom = (CString)_children[1];\r
+ } else {\r
+ logger.log(POILogger.ERROR, "Second child record wasn't a CString, was of type " + _children[1].getRecordType());\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Create a new ExVideoContainer, with blank fields\r
+ */\r
+ public ExVideoContainer() {\r
+ // Setup our header block\r
+ _header = new byte[8];\r
+ _header[0] = 0x0f; // We are a container record\r
+ LittleEndian.putShort(_header, 2, (short)getRecordType());\r
+ \r
+ _children = new Record[2];\r
+ _children[0] = mediaAtom = new ExMediaAtom();\r
+ _children[1] = pathAtom = new CString();\r
+ }\r
+\r
+ /**\r
+ * We are of type 4103\r
+ */\r
+ public long getRecordType() { return RecordTypes.ExVideoContainer.typeID; }\r
+\r
+ /**\r
+ * Write the contents of the record back, so it can be written\r
+ * to disk\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ writeOut(_header[0],_header[1],getRecordType(),_children,out);\r
+ }\r
+\r
+ /**\r
+ * Returns the ExMediaAtom of this link\r
+ */\r
+ public ExMediaAtom getExMediaAtom() { return mediaAtom; }\r
+\r
+ /**\r
+ * Returns the Path Atom (CString) of this link\r
+ */\r
+ public CString getPathAtom() { return pathAtom; }\r
+\r
+}\r
/**
* Action Table
*/
- public static final int ACTION_NONE = 0;
- public static final int ACTION_MACRO = 1;
- public static final int ACTION_RUNPROGRAM = 2;
- public static final int ACTION_JUMP = 3;
- public static final int ACTION_HYPERLINK = 4;
- public static final int ACTION_OLE = 5;
- public static final int ACTION_MEDIA = 6;
- public static final int ACTION_CUSTOMSHOW = 7;
+ public static final byte ACTION_NONE = 0;
+ public static final byte ACTION_MACRO = 1;
+ public static final byte ACTION_RUNPROGRAM = 2;
+ public static final byte ACTION_JUMP = 3;
+ public static final byte ACTION_HYPERLINK = 4;
+ public static final byte ACTION_OLE = 5;
+ public static final byte ACTION_MEDIA = 6;
+ public static final byte ACTION_CUSTOMSHOW = 7;
/**
* Jump Table
*/
- public static final int JUMP_NONE = 0;
- public static final int JUMP_NEXTSLIDE = 1;
- public static final int JUMP_PREVIOUSSLIDE = 2;
- public static final int JUMP_FIRSTSLIDE = 3;
- public static final int JUMP_LASTSLIDE = 4;
- public static final int JUMP_LASTSLIDEVIEWED = 5;
- public static final int JUMP_ENDSHOW = 6;
-
+ public static final byte JUMP_NONE = 0;
+ public static final byte JUMP_NEXTSLIDE = 1;
+ public static final byte JUMP_PREVIOUSSLIDE = 2;
+ public static final byte JUMP_FIRSTSLIDE = 3;
+ public static final byte JUMP_LASTSLIDE = 4;
+ public static final byte JUMP_LASTSLIDEVIEWED = 5;
+ public static final byte JUMP_ENDSHOW = 6;
+ /**
+ * Types of hyperlinks
+ */
+ public static final byte LINK_NextSlide = 0x00;
+ public static final byte LINK_PreviousSlide = 0x01;
+ public static final byte LINK_FirstSlide = 0x02;
+ public static final byte LINK_LastSlide = 0x03;
+ public static final byte LINK_CustomShow = 0x06;
+ public static final byte LINK_SlideNumber = 0x07;
+ public static final byte LINK_Url = 0x08;
+ public static final byte LINK_OtherPresentation = 0x09;
+ public static final byte LINK_OtherFile = 0x0A;
+ public static final byte LINK_NULL = (byte)0xFF;
/**
* Record header.
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.util.Date;\r
+\r
+import org.apache.poi.hslf.util.SystemTimeUtils;\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+/**\r
+ * Atom that contains information that describes shape client data.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class OEShapeAtom extends RecordAtom\r
+{\r
+\r
+ /**\r
+ * Record header.\r
+ */\r
+ private byte[] _header;\r
+\r
+ /**\r
+ * record data\r
+ */\r
+ private byte[] _recdata;\r
+\r
+ /**\r
+ * Constructs a brand new link related atom record.\r
+ */\r
+ public OEShapeAtom() {\r
+ _recdata = new byte[4];\r
+\r
+ _header = new byte[8];\r
+ LittleEndian.putShort(_header, 2, (short)getRecordType());\r
+ LittleEndian.putInt(_header, 4, _recdata.length);\r
+ }\r
+\r
+ /**\r
+ * Constructs the link related atom record from its\r
+ * source data.\r
+ *\r
+ * @param source the source data as a byte array.\r
+ * @param start the start offset into the byte array.\r
+ * @param len the length of the slice in the byte array.\r
+ */\r
+ protected OEShapeAtom(byte[] source, int start, int len) {\r
+ // Get the header\r
+ _header = new byte[8];\r
+ System.arraycopy(source,start,_header,0,8);\r
+\r
+ // Grab the record data\r
+ _recdata = new byte[len-8];\r
+ System.arraycopy(source,start+8,_recdata,0,len-8);\r
+ }\r
+\r
+ /**\r
+ * Gets the record type.\r
+ * @return the record type.\r
+ */\r
+ public long getRecordType() { return RecordTypes.OEShapeAtom.typeID; }\r
+\r
+ /**\r
+ * Write the contents of the record back, so it can be written\r
+ * to disk\r
+ *\r
+ * @param out the output stream to write to.\r
+ * @throws java.io.IOException if an error occurs.\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ out.write(_header);\r
+ out.write(_recdata);\r
+ }\r
+\r
+ /**\r
+ * shape flags.\r
+ *\r
+ * @return shape flags.\r
+ */\r
+ public int getOptions(){\r
+ return LittleEndian.getInt(_recdata, 0);\r
+ }\r
+\r
+ /**\r
+ * shape flags.\r
+ *\r
+ * @param id shape flags.\r
+ */\r
+ public void setOptions(int id){\r
+ LittleEndian.putInt(_recdata, 0, id);\r
+ }\r
+}\r
public static final Type BookmarkSeedAtom = new Type(2025,null);
public static final Type ColorSchemeAtom = new Type(2032,ColorSchemeAtom.class);
public static final Type ExObjRefAtom = new Type(3009,null);
- public static final Type OEShapeAtom = new Type(3009,null);
+ public static final Type OEShapeAtom = new Type(3009,OEShapeAtom.class);
public static final Type OEPlaceholderAtom = new Type(3011,OEPlaceholderAtom.class);
public static final Type GPopublicintAtom = new Type(3024,null);
public static final Type GRatioAtom = new Type(3031,null);
public static final Type DateTimeMCAtom = new Type(4087,null);
public static final Type GenericDateMCAtom = new Type(4088,null);
public static final Type FooterMCAtom = new Type(4090,null);
- public static final Type ExControlAtom = new Type(4091,null);
- public static final Type ExMediaAtom = new Type(4100,null);
- public static final Type ExVideo = new Type(4101,null);
- public static final Type ExAviMovie = new Type(4102,null);
- public static final Type ExMCIMovie = new Type(4103,null);
+ public static final Type ExControlAtom = new Type(4091,ExControlAtom.class);
+ public static final Type ExMediaAtom = new Type(4100,ExMediaAtom.class);
+ public static final Type ExVideoContainer = new Type(4101,ExVideoContainer.class);
+ public static final Type ExAviMovie = new Type(4102,ExAviMovie.class);
+ public static final Type ExMCIMovie = new Type(4103,ExMCIMovie.class);
public static final Type ExMIDIAudio = new Type(4109,null);
public static final Type ExCDAudio = new Type(4110,null);
public static final Type ExWAVAudioEmbedded = new Type(4111,null);
public static final Type ExOleObjStg = new Type(4113,ExOleObjStg.class);
public static final Type ExCDAudioAtom = new Type(4114,null);
public static final Type ExWAVAudioEmbeddedAtom = new Type(4115,null);
- public static final Type AnimationInfoAtom = new Type(4116,null);
+ public static final Type AnimationInfo = new Type(4116,AnimationInfo.class);
+ public static final Type AnimationInfoAtom = new Type(4081,AnimationInfoAtom.class);
public static final Type RTFDateTimeMCAtom = new Type(4117,null);
public static final Type ProgTags = new Type(5000,DummyPositionSensitiveRecordWithChildren.class);
public static final Type ProgStringTag = new Type(5001,null);
rawContents = baos.toByteArray();
}
-
- /**
+
+ public void setRawContents(byte[] bytes) {
+ rawContents = bytes;
+ reserved = new byte[0];
+ initialised = false;
+ }
+
+ /**
* Create a new Paragraph TextPropCollection, and add it to the list
* @param charactersCovered The number of characters this TextPropCollection will cover
* @return the new TextPropCollection, which will then be in the list
/**\r
* Constructs a new empty ruler atom.\r
*/\r
- protected TextRulerAtom() {\r
+ public TextRulerAtom() {\r
_header = new byte[8];\r
_data = new byte[0];\r
\r
public int[] getBulletOffsets(){\r
return bulletOffsets;\r
}\r
+\r
+ public static TextRulerAtom getParagraphInstance(){\r
+ byte[] data = new byte[] {\r
+ 0x00, 0x00, (byte)0xA6, 0x0F, 0x0A, 0x00, 0x00, 0x00,\r
+ 0x10, 0x03, 0x00, 0x00, (byte)0xF9, 0x00, 0x41, 0x01, 0x41, 0x01\r
+ };\r
+ TextRulerAtom ruler = new TextRulerAtom(data, 0, data.length);\r
+ return ruler;\r
+ }\r
+\r
+ public void setParagraphIndent(short tetxOffset, short bulletOffset){\r
+ LittleEndian.putShort(_data, 4, tetxOffset);\r
+ LittleEndian.putShort(_data, 6, bulletOffset);\r
+ LittleEndian.putShort(_data, 8, bulletOffset);\r
+ }\r
}\r
*/
public void setBulletFont(int idx) {
setParaTextPropVal("bullet.font", idx);
+ setFlag(false, ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true);
}
/**
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.List;
+import java.util.*;
import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.ddf.EscherContainerRecord;
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.record.Document;
-import org.apache.poi.hslf.record.DocumentAtom;
-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.ParentAwareRecord;
-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.SlidePersistAtom;
-import org.apache.poi.hslf.record.UserEditAtom;
+import org.apache.poi.hslf.model.Notes;
+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.util.ArrayUtil;
import org.apache.poi.util.POILogFactory;
* Create a blank <code>Slide</code>.
*
* @return the created <code>Slide</code>
- * @throws IOException
*/
- public Slide createSlide() throws IOException {
+ public Slide createSlide() {
SlideListWithText slist = null;
// We need to add the records to the SLWT that deals
for (int i = 0; i < _records.length; i++) {
Record record = _records[i];
ByteArrayOutputStream out = new ByteArrayOutputStream();
- record.writeOut(out);
+ try {
+ record.writeOut(out);
+ } catch (IOException e){
+ throw new HSLFException(e);
+ }
- // Grab interesting records as they come past
+ // Grab interesting records as they come past
if(_records[i].getRecordType() == RecordTypes.PersistPtrIncrementalBlock.typeID){
ptr = (PersistPtrHolder)_records[i];
}
}
}
+ /**
+ * Add a movie in this presentation
+ *
+ * @param path the path or url to the movie
+ * @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:
+ mci = new ExMCIMovie();
+ break;
+ case MovieShape.MOVIE_AVI:
+ mci = new ExAviMovie();
+ break;
+ default:
+ 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);
+ return objectId;
+ }
+
+ /**
+ * Add a control in this presentation
+ *
+ * @param name name of the control, e.g. "Shockwave Flash Object"
+ * @param progId OLE Programmatic Identifier, e.g. "ShockwaveFlash.ShockwaveFlash.9"
+ * @return 0-based index of the control
+ */
+ public int addControl(String name, String progId) {
+ ExObjList lst = _documentRecord.getExObjList();
+ 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();
+ 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);
+
+ return objectId;
+ }
}
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.model;\r
+\r
+import junit.framework.TestCase;\r
+\r
+import java.io.*;\r
+import java.awt.*;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hslf.HSLFSlideShow;\r
+\r
+/**\r
+ * Test <code>MovieShape</code> object.\r
+ * \r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestMovieShape extends TestCase {\r
+\r
+ protected String cwd = System.getProperty("HSLF.testdata.path");\r
+\r
+ public void testCreate() throws Exception {\r
+ SlideShow ppt = new SlideShow();\r
+\r
+ Slide slide = ppt.createSlide();\r
+\r
+ String path = cwd + "/test-movie.mpg";\r
+ int movieIdx = ppt.addMovie(path, MovieShape.MOVIE_MPEG);\r
+ int thumbnailIdx = ppt.addPicture(new File(cwd, "tomcat.png"), Picture.PNG);\r
+\r
+ MovieShape shape = new MovieShape(movieIdx, thumbnailIdx);\r
+ shape.setAnchor(new Rectangle2D.Float(300,225,120,90));\r
+ slide.addShape(shape);\r
+\r
+ assertEquals(path, shape.getPath());\r
+ assertTrue(shape.isAutoPlay());\r
+ shape.setAutoPlay(false);\r
+ assertFalse(shape.isAutoPlay());\r
+\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ ppt.write(out);\r
+\r
+ ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));\r
+ slide = ppt.getSlides()[0];\r
+ shape = (MovieShape)slide.getShapes()[0];\r
+ assertEquals(path, shape.getPath());\r
+ assertFalse(shape.isAutoPlay());\r
+\r
+ }\r
+\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.model;\r
+\r
+import junit.framework.TestCase;\r
+\r
+import java.io.*;\r
+import java.awt.*;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hslf.HSLFSlideShow;\r
+\r
+/**\r
+ * Test <code>Table</code> object.\r
+ * \r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestTable extends TestCase {\r
+\r
+ /**\r
+ * Test that ShapeFactory works properly and returns <code>Table</code>\r
+ */\r
+ public void testShapeFactory() throws Exception {\r
+ SlideShow ppt = new SlideShow();\r
+\r
+ Slide slide = ppt.createSlide();\r
+\r
+ Table tbl = new Table(2, 5);\r
+ slide.addShape(tbl);\r
+\r
+ assertTrue(slide.getShapes()[0] instanceof Table);\r
+ Table tbl2 = (Table)slide.getShapes()[0];\r
+ assertEquals(tbl.getNumberOfColumns(), tbl2.getNumberOfColumns());\r
+ assertEquals(tbl.getNumberOfRows(), tbl2.getNumberOfRows());\r
+\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ ppt.write(out);\r
+ out.close();\r
+\r
+ ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));\r
+ slide = ppt.getSlides()[0];\r
+ assertTrue(slide.getShapes()[0] instanceof Table);\r
+ Table tbl3 = (Table)slide.getShapes()[0];\r
+ assertEquals(tbl.getNumberOfColumns(), tbl3.getNumberOfColumns());\r
+ assertEquals(tbl.getNumberOfRows(), tbl3.getNumberOfRows());\r
+ }\r
+\r
+}\r
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+\r
+import junit.framework.TestCase;\r
+import java.io.ByteArrayOutputStream;\r
+import java.util.Arrays;\r
+\r
+import org.apache.poi.util.HexDump;\r
+\r
+/**\r
+ * Tests that {@link HeadersFootersAtom} works properly\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestAnimationInfoAtom extends TestCase {\r
+ // From a real file\r
+ /*\r
+ <AnimationInfoAtom info="1" type="4081" size="28" offset="4015" header="01 00 F1 0F 1C 00 00 00 ">\r
+ 00 00 00 07 04 05 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00\r
+ 00 00 00\r
+ </AnimationInfoAtom>\r
+ */\r
+ private byte[] data = new byte[] {\r
+ 0x01, 0x00, (byte)0xF1, 0x0F, 0x1C, 0x00, 0x00, 0x00,\r
+ 0x00, 0x00, 0x00, 0x07, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r
+ };\r
+\r
+ public void testRead() throws Exception {\r
+ AnimationInfoAtom record = new AnimationInfoAtom(data, 0, data.length);\r
+ assertEquals(RecordTypes.AnimationInfoAtom.typeID, record.getRecordType());\r
+ assertTrue(record.getFlag(AnimationInfoAtom.Automatic));\r
+ assertTrue(record.getFlag(AnimationInfoAtom.Play));\r
+ assertTrue(record.getFlag(AnimationInfoAtom.Synchronous));\r
+ assertFalse(record.getFlag(AnimationInfoAtom.Reverse));\r
+ assertFalse(record.getFlag(AnimationInfoAtom.Sound));\r
+ assertFalse(record.getFlag(AnimationInfoAtom.StopSound));\r
+ assertFalse(record.getFlag(AnimationInfoAtom.Hide));\r
+ assertFalse(record.getFlag(AnimationInfoAtom.AnimateBg));\r
+ assertEquals(0x07000000, record.getDimColor());\r
+ assertEquals(0, record.getSoundIdRef());\r
+ assertEquals(0, record.getDelayTime());\r
+ assertEquals(2, record.getOrderID());\r
+ assertEquals(0, record.getSlideCount());\r
+ }\r
+\r
+ public void testWrite() throws Exception {\r
+ AnimationInfoAtom record = new AnimationInfoAtom(data, 0, data.length);\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+ public void testNewRecord() throws Exception {\r
+ AnimationInfoAtom record = new AnimationInfoAtom();\r
+ record.setDimColor(0x07000000);\r
+ record.setOrderID(2);\r
+ record.setFlag(AnimationInfoAtom.Automatic, true);\r
+ record.setFlag(AnimationInfoAtom.Play, true);\r
+ record.setFlag(AnimationInfoAtom.Synchronous, true);\r
+\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+\r
+import junit.framework.TestCase;\r
+import java.io.ByteArrayOutputStream;\r
+import java.util.Arrays;\r
+\r
+/**\r
+ * Tests that {@link org.apache.poi.hslf.record.ExControl} works properly\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestExControl extends TestCase {\r
+\r
+ // From a real file (embedded SWF control)\r
+ /*\r
+ <ExControl info="15" type="4078" size="218" offset="76" header="0F 00 EE 0F DA 00 00 00 ">\r
+ <ExControlAtom info="0" type="4091" size="4" offset="84" header="00 00 FB 0F 04 00 00 00 ">\r
+ 00 01 00 00\r
+ </ExControlAtom>\r
+ <ExOleObjAtom info="1" type="4035" size="24" offset="96" header="01 00 C3 0F 18 00 00 00 ">\r
+ 01 00 00 00 02 00 00 00 01 00 00 00 00 00 00 00 02 00 00 00 00 96 13 00\r
+ </ExOleObjAtom>\r
+ <CString info="16" type="4026" size="44" offset="128" header="10 00 BA 0F 2C 00 00 00 ">\r
+ 53 00 68 00 6F 00 63 00 6B 00 77 00 61 00 76 00 65 00 20 00 46 00 6C 00 61\r
+ 00 73 00 68 00 20 00 4F 00 62 00 6A 00 65 00 63 00 74 00\r
+ </CString>\r
+ <CString info="32" type="4026" size="62" offset="180" header="20 00 BA 0F 3E 00 00 00 ">\r
+ 53 00 68 00 6F 00 63 00 6B 00 77 00 61 00 76 00 65 00 46 00 6C 00 61 00 73\r
+ 00 68 00 2E 00 53 00 68 00 6F 00 63 00 6B 00 77 00 61 00 76 00 65 00 46 00\r
+ 6C 00 61 00 73 00 68 00 2E 00 39 00\r
+ </CString>\r
+ <CString info="48" type="4026" size="44" offset="250" header="30 00 BA 0F 2C 00 00 00 ">\r
+ 53 00 68 00 6F 00 63 00 6B 00 77 00 61 00 76 00 65 00 20 00 46 00 6C 00 61\r
+ 00 73 00 68 00 20 00 4F 00 62 00 6A 00 65 00 63 00 74 00\r
+ </CString>\r
+ </ExControl>\r
+ */\r
+ private byte[] data = new byte[] {\r
+ 0x0F, 0x00, (byte)0xEE, 0x0F, (byte)0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)0xFB, 0x0F, 0x04, 0x00, 0x00, 0x00,\r
+ 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, (byte)0xC3, 0x0F, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,\r
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, (byte)0x96, 0x13, 0x00,\r
+ 0x10, 0x00, (byte)0xBA, 0x0F, 0x2C, 0x00, 0x00, 0x00, 0x53, 0x00, 0x68, 0x00, 0x6F, 0x00, 0x63, 0x00, 0x6B, 0x00,\r
+ 0x77, 0x00, 0x61, 0x00, 0x76, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68,\r
+ 0x00, 0x20, 0x00, 0x4F, 0x00, 0x62, 0x00, 0x6A, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x20, 0x00, (byte)0xBA,\r
+ 0x0F, 0x3E, 0x00, 0x00, 0x00, 0x53, 0x00, 0x68, 0x00, 0x6F, 0x00, 0x63, 0x00, 0x6B, 0x00, 0x77, 0x00, 0x61, 0x00,\r
+ 0x76, 0x00, 0x65, 0x00, 0x46, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x2E, 0x00, 0x53, 0x00, 0x68,\r
+ 0x00, 0x6F, 0x00, 0x63, 0x00, 0x6B, 0x00, 0x77, 0x00, 0x61, 0x00, 0x76, 0x00, 0x65, 0x00, 0x46, 0x00, 0x6C, 0x00,\r
+ 0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x2E, 0x00, 0x39, 0x00, 0x30, 0x00, (byte)0xBA, 0x0F, 0x2C, 0x00, 0x00, 0x00,\r
+ 0x53, 0x00, 0x68, 0x00, 0x6F, 0x00, 0x63, 0x00, 0x6B, 0x00, 0x77, 0x00, 0x61, 0x00, 0x76, 0x00, 0x65, 0x00, 0x20,\r
+ 0x00, 0x46, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x20, 0x00, 0x4F, 0x00, 0x62, 0x00, 0x6A, 0x00,\r
+ 0x65, 0x00, 0x63, 0x00, 0x74, 0x00\r
+ };\r
+\r
+ public void testRead() throws Exception {\r
+ ExControl record = new ExControl(data, 0, data.length);\r
+ assertEquals(RecordTypes.ExControl.typeID, record.getRecordType());\r
+\r
+ assertNotNull(record.getExControlAtom());\r
+ assertEquals(256, record.getExControlAtom().getSlideId());\r
+\r
+ ExOleObjAtom oleObj = record.getExOleObjAtom();\r
+ assertNotNull(oleObj);\r
+ assertEquals(oleObj.getDrawAspect(), ExOleObjAtom.DRAW_ASPECT_VISIBLE);\r
+ assertEquals(oleObj.getType(), ExOleObjAtom.TYPE_CONTROL);\r
+ assertEquals(oleObj.getSubType(), ExOleObjAtom.SUBTYPE_DEFAULT);\r
+\r
+ assertEquals("Shockwave Flash Object", record.getMenuName());\r
+ assertEquals("ShockwaveFlash.ShockwaveFlash.9", record.getProgId());\r
+ assertEquals("Shockwave Flash Object", record.getClipboardName());\r
+ }\r
+\r
+ public void testWrite() throws Exception {\r
+ ExControl record = new ExControl(data, 0, data.length);\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+ public void testNewRecord() throws Exception {\r
+ ExControl record = new ExControl();\r
+ ExControlAtom ctrl = record.getExControlAtom();\r
+ ctrl.setSlideId(256);\r
+\r
+ ExOleObjAtom oleObj = record.getExOleObjAtom();\r
+ oleObj.setDrawAspect(ExOleObjAtom.DRAW_ASPECT_VISIBLE);\r
+ oleObj.setType(ExOleObjAtom.TYPE_CONTROL);\r
+ oleObj.setObjID(1);\r
+ oleObj.setSubType(ExOleObjAtom.SUBTYPE_DEFAULT);\r
+ oleObj.setObjStgDataRef(2);\r
+ oleObj.setOptions(1283584);\r
+\r
+ record.setMenuName("Shockwave Flash Object");\r
+ record.setProgId("ShockwaveFlash.ShockwaveFlash.9");\r
+ record.setClipboardName("Shockwave Flash Object");\r
+\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertEquals(data.length, b.length);\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+\r
+import junit.framework.TestCase;\r
+import java.io.ByteArrayOutputStream;\r
+import java.util.Arrays;\r
+\r
+/**\r
+ * Tests that {@link org.apache.poi.hslf.record.HeadersFootersAtom} works properly\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestExMediaAtom extends TestCase {\r
+ // From a real file\r
+ private byte[] data = new byte[] {\r
+ 0x00, 0x00, (byte)0x04, 0x10, 0x08, 0x00, 0x00, 00,\r
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\r
+\r
+ public void testRead() throws Exception {\r
+ ExMediaAtom record = new ExMediaAtom(data, 0, data.length);\r
+ assertEquals(RecordTypes.ExMediaAtom.typeID, record.getRecordType());\r
+\r
+ assertEquals(1, record.getObjectId());\r
+ assertFalse(record.getFlag(ExMediaAtom.fLoop));\r
+ assertFalse(record.getFlag(ExMediaAtom.fNarration));\r
+ assertFalse(record.getFlag(ExMediaAtom.fRewind));\r
+ }\r
+\r
+ public void testWrite() throws Exception {\r
+ ExMediaAtom record = new ExMediaAtom(data, 0, data.length);\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+ public void testNewRecord() throws Exception {\r
+ ExMediaAtom ref = new ExMediaAtom(data, 0, data.length);\r
+ System.out.println(ref.getMask());\r
+\r
+ ExMediaAtom record = new ExMediaAtom();\r
+ record.setObjectId(1);\r
+ record.setFlag(HeadersFootersAtom.fHasDate, false);\r
+ record.setFlag(HeadersFootersAtom.fHasTodayDate, false);\r
+ record.setFlag(HeadersFootersAtom.fHasFooter, false);\r
+\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+ public void testFlags() throws Exception {\r
+ ExMediaAtom record = new ExMediaAtom();\r
+\r
+ //in a new record all the bits are 0\r
+ for(int i = 0; i < 3; i++) assertFalse(record.getFlag(1 << i));\r
+\r
+ record.setFlag(ExMediaAtom.fLoop, true);\r
+ assertTrue(record.getFlag(ExMediaAtom.fLoop));\r
+\r
+ record.setFlag(ExMediaAtom.fNarration, true);\r
+ assertTrue(record.getFlag(ExMediaAtom.fNarration));\r
+\r
+ record.setFlag(ExMediaAtom.fNarration, false);\r
+ assertFalse(record.getFlag(ExMediaAtom.fNarration));\r
+\r
+ record.setFlag(ExMediaAtom.fNarration, false);\r
+ assertFalse(record.getFlag(ExMediaAtom.fNarration));\r
+\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+\r
+import junit.framework.TestCase;\r
+import java.io.ByteArrayOutputStream;\r
+import java.util.Arrays;\r
+\r
+/**\r
+ * Tests that {@link ExOleObjAtom} works properly\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestExOleObjAtom extends TestCase {\r
+ // From a real file (embedded SWF control)\r
+ private byte[] data = new byte[] {\r
+ 0x01, 0x00, (byte)0xC3, 0x0F, 0x18, 0x00, 0x00, 0x00,\r
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\r
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, (byte)0x96, 0x13, 0x00 };\r
+\r
+ public void testRead() throws Exception {\r
+ ExOleObjAtom record = new ExOleObjAtom(data, 0, data.length);\r
+ assertEquals(RecordTypes.ExOleObjAtom.typeID, record.getRecordType());\r
+ System.out.println(record);\r
+\r
+ assertEquals(record.getDrawAspect(), ExOleObjAtom.DRAW_ASPECT_VISIBLE);\r
+ assertEquals(record.getType(), ExOleObjAtom.TYPE_CONTROL);\r
+ assertEquals(record.getObjID(), 1);\r
+ assertEquals(record.getSubType(), ExOleObjAtom.SUBTYPE_DEFAULT);\r
+ assertEquals(record.getObjStgDataRef(), 2);\r
+ assertEquals(record.getOptions(), 1283584); //ther meaning is unknown\r
+ }\r
+\r
+ public void testWrite() throws Exception {\r
+ ExOleObjAtom record = new ExOleObjAtom(data, 0, data.length);\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+ public void testNewRecord() throws Exception {\r
+ ExOleObjAtom record = new ExOleObjAtom();\r
+ record.setDrawAspect(ExOleObjAtom.DRAW_ASPECT_VISIBLE);\r
+ record.setType(ExOleObjAtom.TYPE_CONTROL);\r
+ record.setObjID(1);\r
+ record.setSubType(ExOleObjAtom.SUBTYPE_DEFAULT);\r
+ record.setObjStgDataRef(2);\r
+ record.setOptions(1283584);\r
+\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+\r
+import junit.framework.TestCase;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.FileOutputStream;\r
+import java.io.InputStream;\r
+import java.io.IOException;\r
+import java.util.Arrays;\r
+\r
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;\r
+import org.apache.poi.poifs.filesystem.DirectoryNode;\r
+import org.apache.poi.poifs.filesystem.DocumentEntry;\r
+\r
+/**\r
+ * Tests that {@link ExOleObjStg} works properly\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestExOleObjStg extends TestCase {\r
+\r
+ // From a real file (embedded SWF control)\r
+ /*\r
+ <ExOleObjStg info="16" type="4113" size="347" offset="4322" header="10 00 11 10 5B 01 00 00 ">\r
+ 00 0E 00 00 78 9C BB 70 5E F0 C1 C2 8D 52 0F 19 D0 80 1D 03 33 C3 BF FF 9C\r
+ 0C 6C 48 62 8C 40 CC 04 E3 08 30 30 B0 40 C5 FE FD FF FF 1F 24 C4 0C C4 FF\r
+ 47 C1 90 02 41 0C F9 40 58 C2 A0 C0 E0 CA 90 07 A4 8B 18 2A D1 93 02 5E 20\r
+ C6 C0 0A 8F 73 50 5A C8 BB 5D 73 29 77 DD 79 C1 69 3B 5C 5C 83 43 50 D5 06\r
+ BC 48 2F 2B 66 38 C9 C8 0E 64 3B 30 42 C4 9C 81 B6 83 EC 4D 05 93 C5 24 D9\r
+ 0D 02 42 0C 4C 8C C8 FE 21 56 9F 02 23 C9 56 E1 04 E4 D8 4F 4D 40 89 FD A0\r
+ BC FB 17 4B BA F8 07 C5 A3 60 78 03 7A E6 FF 09 67 59 1B 41 F9 9F 95 61 34\r
+ FF 53 13 50 62 3F 4C 1F AC 1C 18 CD F7 23 0B C0 DA 74 A0 B6 1B A8 3D 37 1A\r
+ F7 23 0B A4 87 A6 85 0A 00 1B 64 6F 38 21 98 03 DA C2 E7 60 90 01 92 69 0C\r
+ 39 0C 65 0C 05 40 32 11 58 2F A4 02 6B 07 3D 60 19 5D 0E 14 27 4E 05 1F 90\r
+ 0C 67 C8 04 96 ED 29 C0 72 BE 1C C8 E3 06 E3 FF FF 39 18 B8 80 2C 0F A0 5C\r
+ 3A 43 06 58 2D A8 A7 E1 C3 10 02 97 87 B8 02 E6 1A 60 77 83 21 18 A8 12 64\r
+ 8A 23 D0 B6 1C B8 59 C8 AA 90 F5 F0 62 94 75 DC C0 DE 0A 37 5C 1D 33 54 35\r
+ 88 97 08 35 91 83 81 07 EC 27 10 BF 18 E8 9B E1 0F 00 BD 65 3D D4\r
+ </ExOleObjStg>\r
+ */\r
+ private byte[] data = new byte[] {\r
+ 0x10, 0x00, 0x11, 0x10, 0x5B, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x78, (byte)0x9C, (byte)0xBB, 0x70,\r
+ 0x5E, (byte)0xF0, (byte)0xC1, (byte)0xC2, (byte)0x8D, 0x52, 0x0F, 0x19, (byte)0xD0, (byte)0x80, 0x1D, 0x03,\r
+ 0x33, (byte)0xC3, (byte)0xBF, (byte)0xFF, (byte)0x9C, 0x0C, 0x6C, 0x48, 0x62, (byte)0x8C, 0x40, (byte)0xCC,\r
+ 0x04, (byte)0xE3, 0x08, 0x30, 0x30, (byte)0xB0, 0x40, (byte)0xC5, (byte)0xFE, (byte)0xFD, (byte)0xFF, (byte)0xFF,\r
+ 0x1F, 0x24, (byte)0xC4, (byte)0x0C, (byte)0xC4, (byte)0xFF, 0x47, (byte)0xC1, (byte)0x90, 0x02, 0x41, 0x0C,\r
+ (byte)0xF9, 0x40, 0x58, (byte)0xC2, (byte)0xA0, (byte)0xC0, (byte)0xE0, (byte)0xCA, (byte)0x90, 0x07, (byte)0xA4,\r
+ (byte)0x8B, 0x18, 0x2A, (byte)0xD1, (byte)0x93, 0x02, 0x5E, 0x20, (byte)0xC6, (byte)0xC0, 0x0A, (byte)0x8F,\r
+ 0x73, 0x50, 0x5A, (byte)0xC8, (byte)0xBB, 0x5D, 0x73, 0x29, 0x77, (byte)0xDD, 0x79, (byte)0xC1, 0x69, 0x3B,\r
+ 0x5C, 0x5C, (byte)0x83, 0x43, 0x50, (byte)0xD5, 0x06, (byte)0xBC, 0x48, 0x2F, 0x2B, 0x66, 0x38, (byte)0xC9,\r
+ (byte)0xC8, 0x0E, 0x64, 0x3B, 0x30, 0x42, (byte)0xC4, (byte)0x9C, (byte)0x81, (byte)0xB6, (byte)0x83, (byte)0xEC,\r
+ 0x4D, 0x05, (byte)0x93, (byte)0xC5, 0x24, (byte)0xD9, 0x0D, 0x02, 0x42, 0x0C, 0x4C, (byte)0x8C, (byte)0xC8,\r
+ (byte)0xFE, 0x21, 0x56, (byte)0x9F, 0x02, 0x23, (byte)0xC9, 0x56, (byte)0xE1, 0x04, (byte)0xE4, (byte)0xD8,\r
+ 0x4F, 0x4D, 0x40, (byte)0x89, (byte)0xFD, (byte)0xA0, (byte)0xBC, (byte)0xFB, 0x17, 0x4B, (byte)0xBA, (byte)0xF8,\r
+ 0x07, (byte)0xC5, (byte)0xA3, 0x60, 0x78, 0x03, 0x7A, (byte)0xE6, (byte)0xFF, 0x09, 0x67, 0x59, 0x1B, 0x41,\r
+ (byte)0xF9, (byte)0x9F, (byte)0x95, 0x61, 0x34, (byte)0xFF, 0x53, 0x13, 0x50, 0x62, 0x3F, 0x4C, 0x1F, (byte)0xAC,\r
+ 0x1C, 0x18, (byte)0xCD, (byte)0xF7, 0x23, 0x0B, (byte)0xC0, (byte)0xDA, 0x74, (byte)0xA0, (byte)0xB6, 0x1B,\r
+ (byte)0xA8, 0x3D, 0x37, 0x1A, (byte)0xF7, 0x23, 0x0B, (byte)0xA4, (byte)0x87, (byte)0xA6, (byte)0x85, 0x0A,\r
+ 0x00, 0x1B, 0x64, 0x6F, 0x38, 0x21, (byte)0x98, 0x03, (byte)0xDA, (byte)0xC2, (byte)0xE7, 0x60, (byte)0x90,\r
+ 0x01, (byte)0x92, 0x69, 0x0C, 0x39, 0x0C, 0x65, 0x0C, 0x05, 0x40, 0x32, 0x11, 0x58, 0x2F, (byte)0xA4, 0x02,\r
+ 0x6B, 0x07, 0x3D, 0x60, 0x19, 0x5D, 0x0E, 0x14, 0x27, 0x4E, 0x05, 0x1F, (byte)0x90, 0x0C, 0x67, (byte)0xC8,\r
+ 0x04, (byte)0x96, (byte)0xED, 0x29, (byte)0xC0, 0x72, (byte)0xBE, 0x1C, (byte)0xC8, (byte)0xE3, 0x06, (byte)0xE3,\r
+ (byte)0xFF, (byte)0xFF, 0x39, 0x18, (byte)0xB8, (byte)0x80, 0x2C, 0x0F, (byte)0xA0, 0x5C, 0x3A, 0x43, 0x06, 0x58,\r
+ 0x2D, (byte)0xA8, (byte)0xA7, (byte)0xE1, (byte)0xC3, 0x10, 0x02, (byte)0x97, (byte)0x87, (byte)0xB8, 0x02,\r
+ (byte)0xE6, 0x1A, 0x60, 0x77, (byte)0x83, 0x21, 0x18, (byte)0xA8, 0x12, 0x64, (byte)0x8A, 0x23, (byte)0xD0,\r
+ (byte)0xB6, 0x1C, (byte)0xB8, 0x59, (byte)0xC8, (byte)0xAA, (byte)0x90, (byte)0xF5, (byte)0xF0, 0x62, (byte)0x94,\r
+ 0x75, (byte)0xDC, (byte)0xC0, (byte)0xDE, 0x0A, 0x37, 0x5C, 0x1D, 0x33, 0x54, 0x35, (byte)0x88, (byte)0x97, 0x08,\r
+ 0x35, (byte)0x91, (byte)0x83, (byte)0x81, 0x07, (byte)0xEC, 0x27, 0x10, (byte)0xBF, 0x18, (byte)0xE8, (byte)0x9B,\r
+ (byte)0xE1, 0x0F, 0x00, (byte)0xBD, 0x65, 0x3D, (byte)0xD4\r
+ };\r
+\r
+ public void testRead() throws Exception {\r
+ ExOleObjStg record = new ExOleObjStg(data, 0, data.length);\r
+ assertEquals(RecordTypes.ExOleObjStg.typeID, record.getRecordType());\r
+\r
+ int len = record.getDataLength();\r
+ byte[] oledata = readAll(record.getData());\r
+ assertEquals(len, oledata.length);\r
+\r
+ POIFSFileSystem fs = new POIFSFileSystem(record.getData());\r
+ assertTrue("Constructed POIFS from ExOleObjStg data", true);\r
+ DocumentEntry doc = (DocumentEntry)fs.getRoot().getEntry("Contents");\r
+ assertNotNull(doc);\r
+ assertTrue("Fetched the Contents stream containing OLE properties", true);\r
+ }\r
+\r
+ public void testWrite() throws Exception {\r
+ ExOleObjStg record = new ExOleObjStg(data, 0, data.length);\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+ public void testNewRecord() throws Exception {\r
+ ExOleObjStg src = new ExOleObjStg(data, 0, data.length);\r
+ byte[] oledata = readAll(src.getData());\r
+\r
+ ExOleObjStg tgt = new ExOleObjStg();\r
+ tgt.setData(oledata);\r
+\r
+\r
+ assertEquals(src.getDataLength(), tgt.getDataLength());\r
+\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ tgt.writeOut(out);\r
+ byte[] b = out.toByteArray();\r
+\r
+ assertEquals(data.length, b.length);\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+ private byte[] readAll(InputStream is) throws IOException {\r
+ int pos;\r
+ byte[] chunk = new byte[1024];\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ while((pos = is.read(chunk)) > 0){\r
+ out.write(chunk, 0, pos);\r
+ }\r
+ return out.toByteArray();\r
+\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+\r
+import junit.framework.TestCase;\r
+import java.io.ByteArrayOutputStream;\r
+import java.util.Arrays;\r
+\r
+/**\r
+ * Tests that {@link HeadersFootersAtom} works properly\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestExVideoContainer extends TestCase {\r
+\r
+ // From a real file\r
+ private byte[] data = new byte[]{\r
+ 0x0F, 0x00, 0x05, 0x10, (byte) 0x9E, 0x00, 0x00, 0x00,\r
+ 0x00, 0x00, 0x04, 0x10, 0x08, 0x00, 0x00, 0x00,\r
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+ 0x00, 0x00, (byte)0xBA, 0x0F, (byte)0x86, 0x00, 0x00, 0x00,\r
+ 0x44, 0x00, 0x3A, 0x00, 0x5C, 0x00, 0x70, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x6A, 0x00, 0x65, 0x00,\r
+ 0x63, 0x00, 0x74, 0x00, 0x73, 0x00, 0x5C, 0x00, 0x53, 0x00, 0x63, 0x00, 0x68, 0x00, 0x75, 0x00,\r
+ 0x6C, 0x00, 0x65, 0x00, 0x72, 0x00, 0x41, 0x00, 0x47, 0x00, 0x5C, 0x00, 0x6D, 0x00, 0x63, 0x00,\r
+ 0x6F, 0x00, 0x6D, 0x00, 0x5F, 0x00, 0x76, 0x00, 0x5F, 0x00, 0x31, 0x00, 0x5F, 0x00, 0x30, 0x00,\r
+ 0x5F, 0x00, 0x34, 0x00, 0x5C, 0x00, 0x76, 0x00, 0x69, 0x00, 0x65, 0x00, 0x77, 0x00, 0x5C, 0x00,\r
+ 0x64, 0x00, 0x61, 0x00, 0x74, 0x00, 0x61, 0x00, 0x5C, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,\r
+ 0x74, 0x00, 0x73, 0x00, 0x5C, 0x00, 0x69, 0x00, 0x6D, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00,\r
+ 0x73, 0x00, 0x5C, 0x00, 0x63, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x73, 0x00, 0x2E, 0x00,\r
+ 0x6D, 0x00, 0x70, 0x00, 0x67, 0x00};\r
+\r
+\r
+\r
+\r
+ public void testRead() throws Exception {\r
+ ExVideoContainer record = new ExVideoContainer(data, 0, data.length);\r
+ assertEquals(RecordTypes.ExVideoContainer.typeID, record.getRecordType());\r
+\r
+ ExMediaAtom exMedia = record.getExMediaAtom();\r
+ assertEquals(1, exMedia.getObjectId());\r
+ assertNotNull(exMedia);\r
+ assertFalse(exMedia.getFlag(ExMediaAtom.fLoop));\r
+ assertFalse(exMedia.getFlag(ExMediaAtom.fNarration));\r
+ assertFalse(exMedia.getFlag(ExMediaAtom.fRewind));\r
+\r
+ CString path = record.getPathAtom();\r
+ assertNotNull(exMedia);\r
+ assertEquals("D:\\projects\\SchulerAG\\mcom_v_1_0_4\\view\\data\\tests\\images\\cards.mpg", path.getText());\r
+ }\r
+\r
+ public void testWrite() throws Exception {\r
+ ExVideoContainer record = new ExVideoContainer(data, 0, data.length);\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+\r
+ public void testNewRecord() throws Exception {\r
+ ExVideoContainer record = new ExVideoContainer();\r
+ record.getExMediaAtom().setObjectId(1);\r
+ record.getPathAtom().setText("D:\\projects\\SchulerAG\\mcom_v_1_0_4\\view\\data\\tests\\images\\cards.mpg");\r
+\r
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
+ record.writeOut(baos);\r
+ byte[] b = baos.toByteArray();\r
+\r
+ assertTrue(Arrays.equals(data, b));\r
+ }\r
+}
\ No newline at end of file
0x03, 0x69, 0x04, (byte)0xF6, 0x05, (byte)0xF6, 0x05\r
};\r
\r
+ private byte[] data_2 = new byte[] {\r
+ 0x00, 0x00, (byte)0xA6, 0x0F, 0x0A, 0x00, 0x00, 0x00,\r
+ 0x10, 0x03, 0x00, 0x00, (byte)0xF9, 0x00, 0x41, 0x01, 0x41, 0x01\r
+ };\r
\r
public void testReadRuler() throws Exception {\r
TextRulerAtom ruler = new TextRulerAtom(data_1, 0, data_1.length);\r
byte[] result = out.toByteArray();\r
assertTrue(Arrays.equals(result, data_1));\r
}\r
+\r
+ public void testRead2() throws Exception {\r
+ TextRulerAtom ruler = TextRulerAtom.getParagraphInstance();\r
+ ruler.setParagraphIndent((short)249, (short)321);\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ ruler.writeOut(out);\r
+\r
+ byte[] result = out.toByteArray();\r
+ assertTrue(Arrays.equals(result, data_2));\r
+\r
+ }\r
+\r
}\r