initial support for embedded movies and controls.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@690262 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2008-08-29 14:01:04 +00:00
parent 1b99ca6b52
commit e2b7f90cd7
38 changed files with 2694 additions and 337 deletions

View File

@ -47,6 +47,7 @@
<li><link href="#Graphics2D">Shapes and Graphics2D</link></li> <li><link href="#Graphics2D">Shapes and Graphics2D</link></li>
<li><link href="#Render">How to convert slides into images</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="#HeadersFooters">Headers / Footers</link></li>
<li><link href="#Movies">How to embed movies</link></li>
</ul> </ul>
</section> </section>
<section><title>Features</title> <section><title>Features</title>
@ -662,6 +663,28 @@
hdd.setFootersText("Created by POI-HSLF"); hdd.setFootersText("Created by POI-HSLF");
</source> </source>
</section> </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>
</section> </section>
</body> </body>

View File

@ -17,6 +17,7 @@
package org.apache.poi.hslf.blip; package org.apache.poi.hslf.blip;
import org.apache.poi.util.LittleEndian; 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.Picture;
import org.apache.poi.hslf.model.Shape; import org.apache.poi.hslf.model.Shape;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.exceptions.HSLFException;
@ -76,7 +77,7 @@ public class WMF extends Metafile {
Header header = new Header(); Header header = new Header();
header.wmfsize = data.length - aldus.getSize(); 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); 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; int coeff = 96*Shape.EMU_PER_POINT/aldus.inch;
header.size = new java.awt.Dimension(header.bounds.width*coeff, header.bounds.height*coeff); header.size = new java.awt.Dimension(header.bounds.width*coeff, header.bounds.height*coeff);
header.zipsize = compressed.length; header.zipsize = compressed.length;
@ -119,7 +120,7 @@ public class WMF extends Metafile {
* <li>short Checksum; Checksum value for previous 10 shorts * <li>short Checksum; Checksum value for previous 10 shorts
* </ul> * </ul>
*/ */
public static class AldusHeader{ public class AldusHeader{
public static final int APMHEADER_KEY = 0x9AC6CDD7; public static final int APMHEADER_KEY = 0x9AC6CDD7;
public int handle; public int handle;
@ -143,8 +144,9 @@ public class WMF extends Metafile {
reserved = LittleEndian.getInt(data, pos); pos += LittleEndian.INT_SIZE; reserved = LittleEndian.getInt(data, pos); pos += LittleEndian.INT_SIZE;
checksum = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE; checksum = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
if (checksum != getChecksum()) if (checksum != getChecksum()){
throw new HSLFException("WMF checksum does not match the header data"); logger.log(POILogger.WARN, "WMF checksum does not match the header data");
}
} }
/** /**

View File

@ -125,7 +125,7 @@ public class PPTXMLDump {
dump(data, pos, size, padding); dump(data, pos, size, padding);
} else { } else {
//dump first 100 bytes of the atom data //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--; padding--;
write(out, "</"+recname + ">" + CR, padding); write(out, "</"+recname + ">" + CR, padding);

View File

@ -0,0 +1,152 @@
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.util.LittleEndian;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
/**
* Represents an ActiveX control in a PowerPoint document.
*
* TODO: finish
* @author Yegor Kozlov
*/
public class ActiveXShape extends Picture {
public static final int DEFAULT_ACTIVEX_THUMBNAIL = -1;
/**
* Create a new <code>Picture</code>
*
* @param pictureIdx the index of the picture
*/
public ActiveXShape(int movieIdx, int pictureIdx){
super(pictureIdx, null);
setActiveXIndex(movieIdx);
}
/**
* Create a <code>Picture</code> object
*
* @param escherRecord the <code>EscherSpContainer</code> record which holds information about
* this picture in the <code>Slide</code>
* @param parent the parent shape of this picture
*/
protected ActiveXShape(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent);
}
/**
* Create a new Placeholder and initialize internal structures
*
* @return the created <code>EscherContainerRecord</code> which holds shape data
*/
protected EscherContainerRecord createSpContainer(int idx, boolean isChild) {
_escherContainer = super.createSpContainer(idx, isChild);
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
spRecord.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE | EscherSpRecord.FLAG_OLESHAPE);
setShapeType(ShapeTypes.HostControl);
setEscherProperty(EscherProperties.BLIP__PICTUREID, idx);
setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001);
setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80008);
setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, -1);
EscherClientDataRecord cldata = new EscherClientDataRecord();
cldata.setOptions((short)0xF);
_escherContainer.getChildRecords().add(cldata);
OEShapeAtom oe = new OEShapeAtom();
//convert hslf into ddf
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
oe.writeOut(out);
} catch(Exception e){
throw new HSLFException(e);
}
cldata.setRemainingData(out.toByteArray());
return _escherContainer;
}
/**
* Assign a control to this shape
*
* @see {@link org.apache.poi.hslf.usermodel.SlideShow#addMovie(String, int)}
* @param idx the index of the movie
*/
public void setActiveXIndex(int idx){
EscherContainerRecord spContainer = getSpContainer();
for (Iterator it = spContainer.getChildRecords().iterator(); it.hasNext();) {
EscherRecord obj = (EscherRecord) it.next();
if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
EscherClientDataRecord clientRecord = (EscherClientDataRecord)obj;
byte[] recdata = clientRecord.getRemainingData();
LittleEndian.putInt(recdata, 8, idx);
}
}
}
public int getControlIndex(){
int idx = -1;
OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
if(oe != null) idx = oe.getOptions();
return idx;
}
/**
* Set a property of this ActiveX control
* @param key
* @param value
*/
public void setProperty(String key, String value){
}
/**
* Document-level container that specifies information about an ActiveX control
*
* @return container that specifies information about an ActiveX control
*/
public ExControl getExControl(){
int idx = getControlIndex();
ExControl ctrl = null;
Document doc = getSheet().getSlideShow().getDocumentRecord();
ExObjList lst = (ExObjList)doc.findFirstOfType(RecordTypes.ExObjList.typeID);
if(lst != null){
Record[] ch = lst.getChildRecords();
for (int i = 0; i < ch.length; i++) {
if(ch[i] instanceof ExControl){
ExControl c = (ExControl)ch[i];
if(c.getExOleObjAtom().getObjID() == idx){
ctrl = c;
break;
}
}
}
}
return ctrl;
}
protected void afterInsert(Sheet sheet){
ExControl ctrl = getExControl();
ctrl.getExControlAtom().setSlideId(sheet._getSheetNumber());
try {
String name = ctrl.getProgId() + "-" + getControlIndex();
byte[] data = (name + '\u0000').getBytes("UTF-16LE");
EscherComplexProperty prop = new EscherComplexProperty(EscherProperties.GROUPSHAPE__SHAPENAME, false, data);
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
opt.addEscherProperty(prop);
} catch (UnsupportedEncodingException e){
throw new HSLFException(e);
}
}
}

View File

@ -0,0 +1,159 @@
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.util.LittleEndian;
import java.io.ByteArrayOutputStream;
import java.util.Iterator;
/**
* Represents a movie in a PowerPoint document.
*
* @author Yegor Kozlov
*/
public class MovieShape extends Picture {
public static final int DEFAULT_MOVIE_THUMBNAIL = -1;
public static final int MOVIE_MPEG = 1;
public static final int MOVIE_AVI = 2;
/**
* Create a new <code>Picture</code>
*
* @param pictureIdx the index of the picture
*/
public MovieShape(int movieIdx, int pictureIdx){
super(pictureIdx, null);
setMovieIndex(movieIdx);
setAutoPlay(true);
}
/**
* Create a new <code>Picture</code>
*
* @param idx the index of the picture
* @param parent the parent shape
*/
public MovieShape(int movieIdx, int idx, Shape parent) {
super(idx, parent);
setMovieIndex(movieIdx);
}
/**
* Create a <code>Picture</code> object
*
* @param escherRecord the <code>EscherSpContainer</code> record which holds information about
* this picture in the <code>Slide</code>
* @param parent the parent shape of this picture
*/
protected MovieShape(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent);
}
/**
* Create a new Placeholder and initialize internal structures
*
* @return the created <code>EscherContainerRecord</code> which holds shape data
*/
protected EscherContainerRecord createSpContainer(int idx, boolean isChild) {
_escherContainer = super.createSpContainer(idx, isChild);
setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x1000100);
setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x10001);
EscherClientDataRecord cldata = new EscherClientDataRecord();
cldata.setOptions((short)0xF);
_escherContainer.getChildRecords().add(cldata);
OEShapeAtom oe = new OEShapeAtom();
InteractiveInfo info = new InteractiveInfo();
InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom();
infoAtom.setAction(InteractiveInfoAtom.ACTION_MEDIA);
infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_NULL);
AnimationInfo an = new AnimationInfo();
AnimationInfoAtom anAtom = an.getAnimationInfoAtom();
anAtom.setFlag(AnimationInfoAtom.Automatic, true);
//convert hslf into ddf
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
oe.writeOut(out);
an.writeOut(out);
info.writeOut(out);
} catch(Exception e){
throw new HSLFException(e);
}
cldata.setRemainingData(out.toByteArray());
return _escherContainer;
}
/**
* Assign a movie to this shape
*
* @see {@link org.apache.poi.hslf.usermodel.SlideShow#addMovie(String, int)}
* @param idx the index of the movie
*/
public void setMovieIndex(int idx){
OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
oe.setOptions(idx);
AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
if(an != null) {
AnimationInfoAtom ai = an.getAnimationInfoAtom();
ai.setDimColor(0x07000000);
ai.setFlag(AnimationInfoAtom.Automatic, true);
ai.setFlag(AnimationInfoAtom.Play, true);
ai.setFlag(AnimationInfoAtom.Synchronous, true);
ai.setOrderID(idx + 1);
}
}
public void setAutoPlay(boolean flag){
AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
if(an != null){
an.getAnimationInfoAtom().setFlag(AnimationInfoAtom.Automatic, flag);
updateClientData();
}
}
public boolean isAutoPlay(){
AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
if(an != null){
return an.getAnimationInfoAtom().getFlag(AnimationInfoAtom.Automatic);
}
return false;
}
/**
* Returns UNC or local path to a video file
*
* @return UNC or local path to a video file
*/
public String getPath(){
OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
int idx = oe.getOptions();
SlideShow ppt = getSheet().getSlideShow();
ExObjList lst = (ExObjList)ppt.getDocumentRecord().findFirstOfType(RecordTypes.ExObjList.typeID);
if(lst == null) return null;
Record[] r = lst.getChildRecords();
for (int i = 0; i < r.length; i++) {
if(r[i] instanceof ExMCIMovie){
ExMCIMovie mci = (ExMCIMovie)r[i];
ExVideoContainer exVideo = mci.getExVideo();
int objectId = exVideo.getExMediaAtom().getObjectId();
if(objectId == idx){
return exVideo.getPathAtom().getText();
}
}
}
return null;
}
}

View File

@ -19,8 +19,10 @@ package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*; import org.apache.poi.ddf.*;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.hslf.record.*;
import java.util.List; import java.util.List;
import java.util.Iterator;
/** /**
* Create a <code>Shape</code> object depending on its type * Create a <code>Shape</code> object depending on its type
@ -45,14 +47,14 @@ public class ShapeFactory {
public static ShapeGroup createShapeGroup(EscherContainerRecord spContainer, Shape parent){ public static ShapeGroup createShapeGroup(EscherContainerRecord spContainer, Shape parent){
ShapeGroup group = null; 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){ if(opt != null){
try { try {
EscherPropertyFactory f = new EscherPropertyFactory(); 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); EscherSimpleProperty p = (EscherSimpleProperty)props.get(0);
if(p.getPropertyNumber() == 0x39F && p.getPropertyValue() == 1){ if(p.getPropertyNumber() == 0x39F && p.getPropertyValue() == 1){
group = new ShapeGroup(spContainer, parent); group = new Table(spContainer, parent);
} else { } else {
group = new ShapeGroup(spContainer, parent); group = new ShapeGroup(spContainer, parent);
} }
@ -68,7 +70,7 @@ public class ShapeFactory {
} }
public static Shape createSimpeShape(EscherContainerRecord spContainer, Shape parent){ public static Shape createSimpeShape(EscherContainerRecord spContainer, Shape parent){
Shape shape; Shape shape = null;
EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID); EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID);
int type = spRecord.getOptions() >> 4; int type = spRecord.getOptions() >> 4;
@ -76,14 +78,26 @@ public class ShapeFactory {
case ShapeTypes.TextBox: case ShapeTypes.TextBox:
shape = new TextBox(spContainer, parent); shape = new TextBox(spContainer, parent);
break; break;
case ShapeTypes.HostControl: case ShapeTypes.HostControl:
case ShapeTypes.PictureFrame: { case ShapeTypes.PictureFrame: {
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID); InteractiveInfo info = (InteractiveInfo)getClientDataRecord(spContainer, RecordTypes.InteractiveInfo.typeID);
EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.BLIP__PICTUREID); OEShapeAtom oes = (OEShapeAtom)getClientDataRecord(spContainer, RecordTypes.OEShapeAtom.typeID);
if(prop != null) if(info != null && info.getInteractiveInfoAtom() != null){
shape = new OLEShape(spContainer, parent); //presence of BLIP__PICTUREID indicates it is an embedded object switch(info.getInteractiveInfoAtom().getAction()){
else case InteractiveInfoAtom.ACTION_OLE:
shape = new Picture(spContainer, parent); 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; break;
} }
case ShapeTypes.Line: case ShapeTypes.Line:
@ -108,4 +122,22 @@ public class ShapeFactory {
return shape; 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;
}
} }

View File

@ -21,11 +21,13 @@ import org.apache.poi.ddf.*;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.hslf.record.ColorSchemeAtom; import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.exceptions.HSLFException;
import java.awt.*; import java.awt.*;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.util.Iterator; import java.util.Iterator;
import java.io.ByteArrayOutputStream;
/** /**
* An abstract simple (non-group) shape. * An abstract simple (non-group) shape.
@ -35,6 +37,12 @@ import java.util.Iterator;
*/ */
public class SimpleShape extends 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. * Create a SimpleShape object and initialize it from the supplied Record container.
* *
@ -293,21 +301,46 @@ public class SimpleShape extends Shape {
* @param recordType type of the record to search * @param recordType type of the record to search
*/ */
protected Record getClientDataRecord(int recordType) { protected Record getClientDataRecord(int recordType) {
Record oep = null;
EscherContainerRecord spContainer = getSpContainer(); Record[] records = getClientRecords();
for (Iterator it = spContainer.getChildRecords().iterator(); it.hasNext();) { if(records != null) for (int i = 0; i < records.length; i++) {
EscherRecord obj = (EscherRecord) it.next(); if(records[i].getRecordType() == recordType){
if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) { return records[i];
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; 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;
}
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());
}
}
} }

View File

@ -89,7 +89,7 @@ public class Table extends ShapeGroup {
* @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape * @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
* @param parent the parent of the shape * @param parent the parent of the shape
*/ */
protected Table(EscherContainerRecord escherRecord, Shape parent) { public Table(EscherContainerRecord escherRecord, Shape parent) {
super(escherRecord, parent); super(escherRecord, parent);
} }

View File

@ -23,9 +23,11 @@ import org.apache.poi.util.POILogFactory;
import java.text.AttributedString; import java.text.AttributedString;
import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator;
import java.text.BreakIterator;
import java.awt.font.TextAttribute; import java.awt.font.TextAttribute;
import java.awt.font.LineBreakMeasurer; import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout; import java.awt.font.TextLayout;
import java.awt.font.FontRenderContext;
import java.awt.*; import java.awt.*;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
@ -89,11 +91,69 @@ public class TextPainter {
} }
public void paint(Graphics2D graphics){ public void paint(Graphics2D graphics){
Rectangle2D anchor = _shape.getLogicalAnchor2D();
TextElement[] elem = getTextElements((float)anchor.getWidth(), graphics.getFontRenderContext());
if(elem == null) return;
float textHeight = 0;
for (int i = 0; i < elem.length; i++) {
textHeight += elem[i].ascent + elem[i].descent;
}
int valign = _shape.getVerticalAlignment();
double y0 = anchor.getY();
switch (valign){
case TextShape.AnchorTopBaseline:
case TextShape.AnchorTop:
y0 += _shape.getMarginTop();
break;
case TextShape.AnchorBottom:
y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom();
break;
default:
case TextShape.AnchorMiddle:
float delta = (float)anchor.getHeight() - textHeight - _shape.getMarginTop() - _shape.getMarginBottom();
y0 += _shape.getMarginTop() + delta/2;
break;
}
//finally draw the text fragments
for (int i = 0; i < elem.length; i++) {
y0 += elem[i].ascent;
Point2D.Double pen = new Point2D.Double();
pen.y = y0;
switch (elem[i]._align) {
default:
case TextShape.AlignLeft:
pen.x = anchor.getX() + _shape.getMarginLeft();
break;
case TextShape.AlignCenter:
pen.x = anchor.getX() + _shape.getMarginLeft() +
(anchor.getWidth() - elem[i].advance - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;
break;
case TextShape.AlignRight:
pen.x = anchor.getX() + _shape.getMarginLeft() +
(anchor.getWidth() - elem[i].advance - _shape.getMarginLeft() - _shape.getMarginRight());
break;
}
if(elem[i]._bullet != null){
graphics.drawString(elem[i]._bullet.getIterator(), (float)(pen.x + elem[i]._bulletOffset), (float)pen.y);
}
AttributedCharacterIterator chIt = elem[i]._text.getIterator();
if(chIt.getEndIndex() > chIt.getBeginIndex()) {
graphics.drawString(chIt, (float)(pen.x + elem[i]._textOffset), (float)pen.y);
}
y0 += elem[i].descent;
}
}
public TextElement[] getTextElements(float textWidth, FontRenderContext frc){
TextRun run = _shape.getTextRun(); TextRun run = _shape.getTextRun();
if (run == null) return; if (run == null) return null;
String text = run.getText(); String text = run.getText();
if (text == null || text.equals("")) return; if (text == null || text.equals("")) return null;
AttributedString at = getAttributedString(run); AttributedString at = getAttributedString(run);
@ -101,11 +161,8 @@ public class TextPainter {
int paragraphStart = it.getBeginIndex(); int paragraphStart = it.getBeginIndex();
int paragraphEnd = it.getEndIndex(); int paragraphEnd = it.getEndIndex();
Rectangle2D anchor = _shape.getLogicalAnchor2D();
float textHeight = 0;
ArrayList lines = new ArrayList(); ArrayList lines = new ArrayList();
LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext()); LineBreakMeasurer measurer = new LineBreakMeasurer(it, frc);
measurer.setPosition(paragraphStart); measurer.setPosition(paragraphStart);
while (measurer.getPosition() < paragraphEnd) { while (measurer.getPosition() < paragraphEnd) {
int startIndex = measurer.getPosition(); int startIndex = measurer.getPosition();
@ -120,7 +177,7 @@ public class TextPainter {
break; break;
} }
float wrappingWidth = (float)anchor.getWidth() - _shape.getMarginLeft() - _shape.getMarginRight(); float wrappingWidth = textWidth - _shape.getMarginLeft() - _shape.getMarginRight();
int bulletOffset = rt.getBulletOffset(); int bulletOffset = rt.getBulletOffset();
int textOffset = rt.getTextOffset(); int textOffset = rt.getTextOffset();
int indent = rt.getIndentLevel(); int indent = rt.getIndentLevel();
@ -138,7 +195,7 @@ public class TextPainter {
if(text_val != 0) textOffset = text_val; if(text_val != 0) textOffset = text_val;
} }
wrappingWidth -= textOffset; if(bulletOffset > 0 || prStart || startIndex == 0) wrappingWidth -= textOffset;
if (_shape.getWordWrap() == TextShape.WrapNone) { if (_shape.getWordWrap() == TextShape.WrapNone) {
wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width; wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;
@ -147,7 +204,7 @@ public class TextPainter {
TextLayout textLayout = measurer.nextLayout(wrappingWidth + 1, TextLayout textLayout = measurer.nextLayout(wrappingWidth + 1,
nextBreak == -1 ? paragraphEnd : nextBreak, true); nextBreak == -1 ? paragraphEnd : nextBreak, true);
if (textLayout == null) { if (textLayout == null) {
textLayout = measurer.nextLayout((float)anchor.getWidth(), textLayout = measurer.nextLayout(textWidth,
nextBreak == -1 ? paragraphEnd : nextBreak, false); nextBreak == -1 ? paragraphEnd : nextBreak, false);
} }
if(textLayout == null){ if(textLayout == null){
@ -173,6 +230,8 @@ public class TextPainter {
el.advance = textLayout.getAdvance(); el.advance = textLayout.getAdvance();
el._textOffset = textOffset; el._textOffset = textOffset;
el._text = new AttributedString(it, startIndex, endIndex); el._text = new AttributedString(it, startIndex, endIndex);
el.textStartIndex = startIndex;
el.textEndIndex = endIndex;
if (prStart){ if (prStart){
int sp = rt.getSpaceBefore(); int sp = rt.getSpaceBefore();
@ -203,8 +262,6 @@ public class TextPainter {
} }
el.descent = descent; el.descent = descent;
textHeight += el.ascent + el.descent;
if(rt.isBullet() && (prStart || startIndex == 0)){ if(rt.isBullet() && (prStart || startIndex == 0)){
it.setIndex(startIndex); it.setIndex(startIndex);
@ -236,56 +293,11 @@ public class TextPainter {
lines.add(el); lines.add(el);
} }
int valign = _shape.getVerticalAlignment();
double y0 = anchor.getY();
switch (valign){
case TextShape.AnchorTopBaseline:
case TextShape.AnchorTop:
y0 += _shape.getMarginTop();
break;
case TextShape.AnchorBottom:
y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom();
break;
default:
case TextShape.AnchorMiddle:
float delta = (float)anchor.getHeight() - textHeight - _shape.getMarginTop() - _shape.getMarginBottom();
y0 += _shape.getMarginTop() + delta/2;
break;
}
//finally draw the text fragments //finally draw the text fragments
for (int i = 0; i < lines.size(); i++) { TextElement[] elems = new TextElement[lines.size()];
TextElement elem = (TextElement)lines.get(i); return (TextElement[])lines.toArray(elems);
y0 += elem.ascent;
Point2D.Double pen = new Point2D.Double();
pen.y = y0;
switch (elem._align) {
default:
case TextShape.AlignLeft:
pen.x = anchor.getX() + _shape.getMarginLeft();
break;
case TextShape.AlignCenter:
pen.x = anchor.getX() + _shape.getMarginLeft() +
(anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;
break;
case TextShape.AlignRight:
pen.x = anchor.getX() + _shape.getMarginLeft() +
(anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight());
break;
}
if(elem._bullet != null){
graphics.drawString(elem._bullet.getIterator(), (float)(pen.x + elem._bulletOffset), (float)pen.y);
}
AttributedCharacterIterator chIt = elem._text.getIterator();
if(chIt.getEndIndex() > chIt.getBeginIndex()) {
graphics.drawString(chIt, (float)(pen.x + elem._textOffset), (float)pen.y);
}
y0 += elem.descent;
}
} }
public static class TextElement { public static class TextElement {
public AttributedString _text; public AttributedString _text;
public int _textOffset; public int _textOffset;
@ -294,5 +306,6 @@ public class TextPainter {
public int _align; public int _align;
public float ascent, descent; public float ascent, descent;
public float advance; public float advance;
public int textStartIndex, textEndIndex;
} }
} }

View File

@ -22,6 +22,7 @@ package org.apache.poi.hslf.model;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Vector; import java.util.Vector;
import java.util.List;
import org.apache.poi.hslf.model.textproperties.TextPropCollection; import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.record.*;
@ -45,7 +46,8 @@ public class TextRun
protected TextBytesAtom _byteAtom; protected TextBytesAtom _byteAtom;
protected TextCharsAtom _charAtom; protected TextCharsAtom _charAtom;
protected StyleTextPropAtom _styleAtom; protected StyleTextPropAtom _styleAtom;
protected boolean _isUnicode; protected TextRulerAtom _ruler;
protected boolean _isUnicode;
protected RichTextRun[] _rtRuns; protected RichTextRun[] _rtRuns;
private SlideShow slideShow; private SlideShow slideShow;
private Sheet sheet; private Sheet sheet;
@ -103,155 +105,159 @@ public class TextRun
pStyles = _styleAtom.getParagraphStyles(); pStyles = _styleAtom.getParagraphStyles();
cStyles = _styleAtom.getCharacterStyles(); cStyles = _styleAtom.getCharacterStyles();
} }
buildRichTextRuns(pStyles, cStyles, 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);
}
} }
public void buildRichTextRuns(LinkedList pStyles, LinkedList cStyles, String runRawText){
// Update methods follow
// 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, * Adds the supplied text onto the end of the TextRun,
@ -379,7 +385,7 @@ public class TextRun
* @param run * @param run
* @param s * @param s
*/ */
public synchronized void changeTextInRichTextRun(RichTextRun run, String s) { public void changeTextInRichTextRun(RichTextRun run, String s) {
// Figure out which run it is // Figure out which run it is
int runID = -1; int runID = -1;
for(int i=0; i<_rtRuns.length; i++) { for(int i=0; i<_rtRuns.length; i++) {
@ -457,7 +463,7 @@ public class TextRun
* as the the first character has. * as the the first character has.
* If you care about styling, do setText on a RichTextRun instead * 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 // Save the new text to the atoms
storeText(s); storeText(s);
RichTextRun fst = _rtRuns[0]; RichTextRun fst = _rtRuns[0];
@ -491,7 +497,7 @@ public class TextRun
* Changes the text. * Changes the text.
* Converts '\r' into '\n' * Converts '\r' into '\n'
*/ */
public synchronized void setText(String s) { public void setText(String s) {
String text = normalize(s); String text = normalize(s);
setRawText(text); setRawText(text);
} }
@ -500,7 +506,7 @@ public class TextRun
* Ensure a StyleTextPropAtom is present for this run, * Ensure a StyleTextPropAtom is present for this run,
* by adding if required. Normally for internal TextRun use. * by adding if required. Normally for internal TextRun use.
*/ */
public synchronized void ensureStyleAtomPresent() { public void ensureStyleAtomPresent() {
if(_styleAtom != null) { if(_styleAtom != null) {
// All there // All there
return; return;
@ -669,11 +675,26 @@ public class TextRun
} }
public TextRulerAtom getTextRuler(){ public TextRulerAtom getTextRuler(){
for (int i = 0; i < _records.length; i++) { if(_ruler == null){
if(_records[i] instanceof TextRulerAtom) return (TextRulerAtom)_records[i]; if(_records != null) for (int i = 0; i < _records.length; i++) {
} if(_records[i] instanceof TextRulerAtom) {
return null; _ruler = (TextRulerAtom)_records[i];
break;
}
}
}
return _ruler;
}
public TextRulerAtom createTextRuler(){
_ruler = getTextRuler();
if(_ruler == null){
_ruler = TextRulerAtom.getParagraphInstance();
_headerAtom.getParentRecord().appendChildRecord(_ruler);
}
return _ruler;
} }
/** /**
@ -692,4 +713,5 @@ public class TextRun
public Record[] getRecords(){ public Record[] getRecords(){
return _records; return _records;
} }
} }

View File

@ -133,6 +133,7 @@ public abstract class TextShape extends SimpleShape {
_txtbox.appendChildRecord(sta); _txtbox.appendChildRecord(sta);
_txtrun = new TextRun(tha,tca,sta); _txtrun = new TextRun(tha,tca,sta);
_txtrun._records = new Record[]{tha, tca, sta};
_txtrun.setText(""); _txtrun.setText("");
_escherContainer.addChildRecord(_txtbox.getEscherRecord()); _escherContainer.addChildRecord(_txtbox.getEscherRecord());

View File

@ -0,0 +1,97 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
/**
* A container record that specifies information about animation information for a shape.
*
* @author Yegor Kozlov
*/
public class AnimationInfo extends RecordContainer {
private byte[] _header;
// Links to our more interesting children
private AnimationInfoAtom animationAtom;
/**
* Set things up, and find our more interesting children
*/
protected AnimationInfo(byte[] source, int start, int len) {
// Grab the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
// Find our children
_children = Record.findChildRecords(source,start+8,len-8);
findInterestingChildren();
}
/**
* Go through our child records, picking out the ones that are
* interesting, and saving those for use by the easy helper
* methods.
*/
private void findInterestingChildren() {
// First child should be the ExMediaAtom
if(_children[0] instanceof AnimationInfoAtom) {
animationAtom = (AnimationInfoAtom)_children[0];
} else {
logger.log(POILogger.ERROR, "First child record wasn't a AnimationInfoAtom, was of type " + _children[0].getRecordType());
}
}
/**
* Create a new AnimationInfo, with blank fields
*/
public AnimationInfo() {
// Setup our header block
_header = new byte[8];
_header[0] = 0x0f; // We are a container record
LittleEndian.putShort(_header, 2, (short)getRecordType());
_children = new Record[1];
_children[0] = animationAtom = new AnimationInfoAtom();
}
/**
* We are of type 4103
*/
public long getRecordType() { return RecordTypes.AnimationInfo.typeID; }
/**
* Write the contents of the record back, so it can be written
* to disk
*/
public void writeOut(OutputStream out) throws IOException {
writeOut(_header[0],_header[1],getRecordType(),_children,out);
}
/**
* Returns the AnimationInfo
*/
public AnimationInfoAtom getAnimationInfoAtom() {
return animationAtom;
}
}

View File

@ -0,0 +1,278 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import org.apache.poi.hslf.util.SystemTimeUtils;
import org.apache.poi.util.LittleEndian;
/**
* An atom record that specifies the animation information for a shape.
*
* @author Yegor Kozlov
*/
public class AnimationInfoAtom extends RecordAtom
{
/**
* whether the animation plays in the reverse direction
*/
public static final int Reverse = 1;
/**
* whether the animation starts automatically
*/
public static final int Automatic = 4;
/**
* whether the animation has an associated sound
*/
public static final int Sound = 16;
/**
* whether all playing sounds are stopped when this animation begins
*/
public static final int StopSound = 64;
/**
* whether an associated sound, media or action verb is activated when the shape is clicked.
*/
public static final int Play = 256;
/**
* specifies that the animation, while playing, stops other slide show actions.
*/
public static final int Synchronous = 1024;
/**
* whether the shape is hidden while the animation is not playing
*/
public static final int Hide = 4096;
/**
* whether the background of the shape is animated
*/
public static final int AnimateBg = 16384;
/**
* Record header.
*/
private byte[] _header;
/**
* record data
*/
private byte[] _recdata;
/**
* Constructs a brand new link related atom record.
*/
protected AnimationInfoAtom() {
_recdata = new byte[28];
_header = new byte[8];
LittleEndian.putShort(_header, 0, (short)0x01);
LittleEndian.putShort(_header, 2, (short)getRecordType());
LittleEndian.putInt(_header, 4, _recdata.length);
}
/**
* Constructs the link related atom record from its
* source data.
*
* @param source the source data as a byte array.
* @param start the start offset into the byte array.
* @param len the length of the slice in the byte array.
*/
protected AnimationInfoAtom(byte[] source, int start, int len) {
// Get the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
// Grab the record data
_recdata = new byte[len-8];
System.arraycopy(source,start+8,_recdata,0,len-8);
}
/**
* Gets the record type.
* @return the record type.
*/
public long getRecordType() {
return RecordTypes.AnimationInfoAtom.typeID;
}
/**
* Write the contents of the record back, so it can be written
* to disk
*
* @param out the output stream to write to.
* @throws java.io.IOException if an error occurs.
*/
public void writeOut(OutputStream out) throws IOException {
out.write(_header);
out.write(_recdata);
}
/**
* A rgb structure that specifies a color for the dim effect after the animation is complete.
*
* @return color for the dim effect after the animation is complete
*/
public int getDimColor(){
return LittleEndian.getInt(_recdata, 0);
}
/**
* A rgb structure that specifies a color for the dim effect after the animation is complete.
*
* @param rgb color for the dim effect after the animation is complete
*/
public void setDimColor(int rgb){
LittleEndian.putInt(_recdata, 0, rgb);
}
/**
* A bit mask specifying options for displaying headers and footers
*
* @return A bit mask specifying options for displaying headers and footers
*/
public int getMask(){
return LittleEndian.getInt(_recdata, 4);
}
/**
* A bit mask specifying options for displaying video
*
* @param mask A bit mask specifying options for displaying video
*/
public void setMask(int mask){
LittleEndian.putInt(_recdata, 4, mask);
}
/**
* @param bit the bit to check
* @return whether the specified flag is set
*/
public boolean getFlag(int bit){
return (getMask() & bit) != 0;
}
/**
* @param bit the bit to set
* @param value whether the specified bit is set
*/
public void setFlag(int bit, boolean value){
int mask = getMask();
if(value) mask |= bit;
else mask &= ~bit;
setMask(mask);
}
/**
* A 4-byte unsigned integer that specifies a reference to a sound
* in the SoundCollectionContainer record to locate the embedded audio
*
* @return reference to a sound
*/
public int getSoundIdRef(){
return LittleEndian.getInt(_recdata, 8);
}
/**
* A 4-byte unsigned integer that specifies a reference to a sound
* in the SoundCollectionContainer record to locate the embedded audio
*
* @param id reference to a sound
*/
public void setSoundIdRef(int id){
LittleEndian.putInt(_recdata, 8, id);
}
/**
* A signed integer that specifies the delay time, in milliseconds, before the animation starts to play.
* If {@link Automatic} is 0x1, this value MUST be greater than or equal to 0; otherwise, this field MUST be ignored.
*/
public int getDelayTime(){
return LittleEndian.getInt(_recdata, 12);
}
/**
* A signed integer that specifies the delay time, in milliseconds, before the animation starts to play.
* If {@link Automatic} is 0x1, this value MUST be greater than or equal to 0; otherwise, this field MUST be ignored.
*/
public void setDelayTime(int id){
LittleEndian.putInt(_recdata, 12, id);
}
/**
* A signed integer that specifies the order of the animation in the slide.
* It MUST be greater than or equal to -2. The value -2 specifies that this animation follows the order of
* the corresponding placeholder shape on the main master slide or title master slide.
* The value -1 SHOULD NOT <105> be used.
*/
public int getOrderID(){
return LittleEndian.getInt(_recdata, 16);
}
/**
* A signed integer that specifies the order of the animation in the slide.
* It MUST be greater than or equal to -2. The value -2 specifies that this animation follows the order of
* the corresponding placeholder shape on the main master slide or title master slide.
* The value -1 SHOULD NOT <105> be used.
*/
public void setOrderID(int id){
LittleEndian.putInt(_recdata, 16, id);
}
/**
* An unsigned integer that specifies the number of slides that this animation continues playing.
* This field is utilized only in conjunction with media.
* The value 0xFFFFFFFF specifies that the animation plays for one slide.
*/
public int getSlideCount(){
return LittleEndian.getInt(_recdata, 18);
}
/**
* An unsigned integer that specifies the number of slides that this animation continues playing.
* This field is utilized only in conjunction with media.
* The value 0xFFFFFFFF specifies that the animation plays for one slide.
*/
public void setSlideCount(int id){
LittleEndian.putInt(_recdata, 18, id);
}
public String toString(){
StringBuffer buf = new StringBuffer();
buf.append("AnimationInfoAtom\n");
buf.append("\tDimColor: " + getDimColor() + "\n");
int mask = getMask();
buf.append("\tMask: " + mask + ", 0x"+Integer.toHexString(mask)+"\n");
buf.append("\t Reverse: " + getFlag(Reverse)+"\n");
buf.append("\t Automatic: " + getFlag(Automatic)+"\n");
buf.append("\t Sound: " + getFlag(Sound)+"\n");
buf.append("\t StopSound: " + getFlag(StopSound)+"\n");
buf.append("\t Play: " + getFlag(Play)+"\n");
buf.append("\t Synchronous: " + getFlag(Synchronous)+"\n");
buf.append("\t Hide: " + getFlag(Hide)+"\n");
buf.append("\t AnimateBg: " + getFlag(AnimateBg)+"\n");
buf.append("\tSoundIdRef: " + getSoundIdRef() + "\n");
buf.append("\tDelayTime: " + getDelayTime() + "\n");
buf.append("\tOrderID: " + getOrderID() + "\n");
buf.append("\tSlideCount: " + getSlideCount() + "\n");
return buf.toString();
}
}

View File

@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
/**
* A container record that specifies information about a movie stored externally.
*
* @author Yegor Kozlov
*/
public class ExAviMovie extends ExMCIMovie {
/**
* Set things up, and find our more interesting children
*/
protected ExAviMovie(byte[] source, int start, int len) {
super(source, start, len);
}
/**
* Create a new ExAviMovie, with blank fields
*/
public ExAviMovie() {
super();
}
/**
* We are of type 4102
*/
public long getRecordType() {
return RecordTypes.ExAviMovie.typeID;
}
}

View File

@ -24,7 +24,7 @@ import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
/** /**
* Container for OLE Control object. It contains: * A container record that specifies information about an ActiveX control. It contains:
* <p> * <p>
* 1. ExControlAtom (4091) * 1. ExControlAtom (4091)
* 2. ExOleObjAtom (4035) * 2. ExOleObjAtom (4035)
@ -40,9 +40,6 @@ import org.apache.poi.util.POILogger;
*/ */
public class ExControl extends ExEmbed { public class ExControl extends ExEmbed {
// Links to our more interesting children
private ExControlAtom ctrlAtom;
/** /**
* Set things up, and find our more interesting children * Set things up, and find our more interesting children
* *
@ -60,7 +57,7 @@ public class ExControl extends ExEmbed {
public ExControl() { public ExControl() {
super(); super();
_children[0] = ctrlAtom = new ExControlAtom(); _children[0] = embedAtom = new ExControlAtom();
} }
/** /**
@ -70,7 +67,7 @@ public class ExControl extends ExEmbed {
*/ */
public ExControlAtom getExControlAtom() public ExControlAtom getExControlAtom()
{ {
return ctrlAtom; return (ExControlAtom)_children[0];
} }
/** /**
@ -82,14 +79,4 @@ public class ExControl extends ExEmbed {
public long getRecordType() { public long getRecordType() {
return RecordTypes.ExControl.typeID; return RecordTypes.ExControl.typeID;
} }
protected RecordAtom getEmbedAtom(Record[] children){
RecordAtom atom = null;
if(_children[0] instanceof ExControlAtom) {
atom = (ExControlAtom)_children[0];
} else {
logger.log(POILogger.ERROR, "First child record wasn't a ExControlAtom, was of type " + _children[0].getRecordType());
}
return atom;
}
} }

View File

@ -23,8 +23,7 @@ import java.io.OutputStream;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
/** /**
* Contains a long integer, slideID, which stores the unique slide identifier of the slide * An atom record that specifies an ActiveX control.
* where this control resides.
* *
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
@ -67,10 +66,32 @@ public class ExControlAtom extends RecordAtom {
_id = LittleEndian.getInt(source, start + 8); _id = LittleEndian.getInt(source, start + 8);
} }
/**
* An integer that specifies which presentation slide is associated with the ActiveX control.
* <p>
* It MUST be 0x00000000 or equal to the value of the slideId field of a SlidePersistAtom record.
* The value 0x00000000 specifies a null reference.
* </p>
*
* @return an integer that specifies which presentation slide is associated with the ActiveX control
*/
public int getSlideId() { public int getSlideId() {
return _id; return _id;
} }
/**
* Sets which presentation slide is associated with the ActiveX control.
*
* @param id an integer that specifies which presentation slide is associated with the ActiveX control
* <p>
* It MUST be 0x00000000 or equal to the value of the slideId field of a SlidePersistAtom record.
* The value 0x00000000 specifies a null reference.
* </p>
*/
public void setSlideId(int id) {
_id = id;
}
/** /**
* Gets the record type. * Gets the record type.
* @return the record type. * @return the record type.

View File

@ -36,7 +36,7 @@ public class ExEmbed extends RecordContainer {
private byte[] _header; private byte[] _header;
// Links to our more interesting children // Links to our more interesting children
private RecordAtom embedAtom; protected RecordAtom embedAtom;
private ExOleObjAtom oleObjAtom; private ExOleObjAtom oleObjAtom;
private CString menuName; private CString menuName;
private CString progId; private CString progId;
@ -72,10 +72,11 @@ public class ExEmbed extends RecordContainer {
// Setup our child records // Setup our child records
CString cs1 = new CString(); CString cs1 = new CString();
cs1.setOptions(0x1 << 4);
CString cs2 = new CString(); CString cs2 = new CString();
cs2.setOptions(0x2 << 4);
CString cs3 = new CString(); CString cs3 = new CString();
// cs1.setOptions(0x00); cs3.setOptions(0x3 << 4);
// cs2.setOptions(0x10);
_children[0] = new ExEmbedAtom(); _children[0] = new ExEmbedAtom();
_children[1] = new ExOleObjAtom(); _children[1] = new ExOleObjAtom();
_children[2] = cs1; _children[2] = cs1;
@ -91,7 +92,11 @@ public class ExEmbed extends RecordContainer {
private void findInterestingChildren() { private void findInterestingChildren() {
// First child should be the ExHyperlinkAtom // 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 // Second child should be the ExOleObjAtom
if (_children[1] instanceof ExOleObjAtom) { if (_children[1] instanceof ExOleObjAtom) {
@ -102,25 +107,17 @@ public class ExEmbed extends RecordContainer {
for (int i = 2; i < _children.length; i++) { for (int i = 2; i < _children.length; i++) {
if (_children[i] instanceof CString){ if (_children[i] instanceof CString){
if (menuName == null) menuName = (CString)_children[i]; CString cs = (CString)_children[i];
else if (progId == null) progId = (CString)_children[i]; int opts = cs.getOptions() >> 4;
else if (clipboardName == null) clipboardName = (CString)_children[i]; switch(opts){
} else { case 0x1: menuName = cs; break;
logger.log(POILogger.ERROR, "Record after atoms wasn't a CString, was of type " + _children[i].getRecordType()); 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}. * Gets the {@link ExEmbedAtom}.
* *
@ -151,6 +148,11 @@ public class ExEmbed extends RecordContainer {
return menuName == null ? null : menuName.getText(); return menuName == null ? null : menuName.getText();
} }
public void setMenuName(String s)
{
if(menuName != null) menuName.setText(s);
}
/** /**
* Gets the OLE Programmatic Identifier. * Gets the OLE Programmatic Identifier.
* *
@ -161,6 +163,10 @@ public class ExEmbed extends RecordContainer {
return progId == null ? null : progId.getText(); 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. * Gets the name that appears in the paste special dialog.
* *
@ -171,6 +177,10 @@ public class ExEmbed extends RecordContainer {
return clipboardName == null ? null : clipboardName.getText(); 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) * Returns the type (held as a little endian in bytes 3 and 4)
* that this class handles. * that this class handles.

View File

@ -0,0 +1,100 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
/**
* A container record that specifies information about a movie stored externally.
*
* @author Yegor Kozlov
*/
public class ExMCIMovie extends RecordContainer {
private byte[] _header;
//An ExVideoContainer record that specifies information about the MCI movie
private ExVideoContainer exVideo;
/**
* Set things up, and find our more interesting children
*/
protected ExMCIMovie(byte[] source, int start, int len) {
// Grab the header
_header = new byte[8];
System.arraycopy(source, start, _header, 0, 8);
// Find our children
_children = Record.findChildRecords(source, start + 8, len - 8);
findInterestingChildren();
}
/**
* Create a new ExMCIMovie, with blank fields
*/
public ExMCIMovie() {
_header = new byte[8];
// Setup our header block
_header[0] = 0x0f; // We are a container record
LittleEndian.putShort(_header, 2, (short) getRecordType());
exVideo = new ExVideoContainer();
_children = new Record[]{exVideo};
}
/**
* Go through our child records, picking out the ones that are
* interesting, and saving those for use by the easy helper
* methods.
*/
private void findInterestingChildren() {
// First child should be the ExVideoContainer
if (_children[0] instanceof ExVideoContainer) {
exVideo = (ExVideoContainer) _children[0];
} else {
logger.log(POILogger.ERROR, "First child record wasn't a ExVideoContainer, was of type " + _children[0].getRecordType());
}
}
/**
* We are of type 4103
*/
public long getRecordType() {
return RecordTypes.ExMCIMovie.typeID;
}
/**
* Write the contents of the record back, so it can be written
* to disk
*/
public void writeOut(OutputStream out) throws IOException {
writeOut(_header[0], _header[1], getRecordType(), _children, out);
}
/**
* Returns the ExVideoContainer that specifies information about the MCI movie
*/
public ExVideoContainer getExVideo() {
return exVideo; }
}

View File

@ -0,0 +1,172 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import org.apache.poi.hslf.util.SystemTimeUtils;
import org.apache.poi.util.LittleEndian;
/**
* An atom record that specifies information about external audio or video data.
*
* @author Yegor Kozlov
*/
public class ExMediaAtom extends RecordAtom
{
/**
* A bit that specifies whether the audio or video data is repeated continuously during playback.
*/
public static final int fLoop = 1;
/**
* A bit that specifies whether the audio or video data is rewound after playing.
*/
public static final int fRewind = 2;
/**
* 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.
*/
public static final int fNarration = 4;
/**
* Record header.
*/
private byte[] _header;
/**
* record data
*/
private byte[] _recdata;
/**
* Constructs a brand new link related atom record.
*/
protected ExMediaAtom() {
_recdata = new byte[8];
_header = new byte[8];
LittleEndian.putShort(_header, 2, (short)getRecordType());
LittleEndian.putInt(_header, 4, _recdata.length);
}
/**
* Constructs the link related atom record from its
* source data.
*
* @param source the source data as a byte array.
* @param start the start offset into the byte array.
* @param len the length of the slice in the byte array.
*/
protected ExMediaAtom(byte[] source, int start, int len) {
// Get the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
// Grab the record data
_recdata = new byte[len-8];
System.arraycopy(source,start+8,_recdata,0,len-8);
}
/**
* Gets the record type.
* @return the record type.
*/
public long getRecordType() { return RecordTypes.ExMediaAtom.typeID; }
/**
* Write the contents of the record back, so it can be written
* to disk
*
* @param out the output stream to write to.
* @throws java.io.IOException if an error occurs.
*/
public void writeOut(OutputStream out) throws IOException {
out.write(_header);
out.write(_recdata);
}
/**
* A 4-byte unsigned integer that specifies an ID for an external object.
*
* @return A 4-byte unsigned integer that specifies an ID for an external object.
*/
public int getObjectId(){
return LittleEndian.getInt(_recdata, 0);
}
/**
* A 4-byte unsigned integer that specifies an ID for an external object.
*
* @param id A 4-byte unsigned integer that specifies an ID for an external object.
*/
public void setObjectId(int id){
LittleEndian.putInt(_recdata, 0, id);
}
/**
* A bit mask specifying options for displaying headers and footers
*
* @return A bit mask specifying options for displaying headers and footers
*/
public int getMask(){
return LittleEndian.getInt(_recdata, 4);
}
/**
* A bit mask specifying options for displaying video
*
* @param mask A bit mask specifying options for displaying video
*/
public void setMask(int mask){
LittleEndian.putInt(_recdata, 4, mask);
}
/**
* @param bit the bit to check
* @return whether the specified flag is set
*/
public boolean getFlag(int bit){
return (getMask() & bit) != 0;
}
/**
* @param bit the bit to set
* @param value whether the specified bit is set
*/
public void setFlag(int bit, boolean value){
int mask = getMask();
if(value) mask |= bit;
else mask &= ~bit;
setMask(mask);
}
public String toString(){
StringBuffer buf = new StringBuffer();
buf.append("ExMediaAtom\n");
buf.append("\tObjectId: " + getObjectId() + "\n");
buf.append("\tMask : " + getMask() + "\n");
buf.append("\t fLoop : " + getFlag(fLoop) + "\n");
buf.append("\t fRewind : " + getFlag(fRewind) + "\n");
buf.append("\t fNarration : " + getFlag(fNarration) + "\n");
return buf.toString();
}
}

View File

@ -65,11 +65,35 @@ import org.apache.poi.util.LittleEndian;
*/ */
public class ExOleObjAtom extends RecordAtom { 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; 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; 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; 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; 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_DEFAULT = 0;
public static final int SUBTYPE_CLIPART_GALLERY = 1; public static final int SUBTYPE_CLIPART_GALLERY = 1;
@ -101,14 +125,13 @@ public class ExOleObjAtom extends RecordAtom {
/** /**
* Constructs a brand new link related atom record. * Constructs a brand new link related atom record.
*/ */
protected ExOleObjAtom() { public ExOleObjAtom() {
_header = new byte[8]; _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.putShort(_header, 2, (short)getRecordType());
LittleEndian.putInt(_header, 4, _data.length); LittleEndian.putInt(_header, 4, _data.length);
// I hope it is fine for the other values to be zero.
} }
/** /**
@ -144,6 +167,16 @@ public class ExOleObjAtom extends RecordAtom {
return LittleEndian.getInt(_data, 0); 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. * Gets whether the object is embedded or linked.
* *
@ -153,6 +186,15 @@ public class ExOleObjAtom extends RecordAtom {
return LittleEndian.getInt(_data, 4); 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. * Gets the unique identifier for the OLE object.
* *
@ -162,6 +204,15 @@ public class ExOleObjAtom extends RecordAtom {
return LittleEndian.getInt(_data, 8); 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. * Gets the type of OLE object.
* *
@ -171,6 +222,15 @@ public class ExOleObjAtom extends RecordAtom {
return LittleEndian.getInt(_data, 12); 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 * Gets the reference to the persistent object
* *
@ -181,6 +241,16 @@ public class ExOleObjAtom extends RecordAtom {
return LittleEndian.getInt(_data, 16); 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. * Gets whether the object's image is blank.
* *
@ -191,6 +261,24 @@ public class ExOleObjAtom extends RecordAtom {
return LittleEndian.getInt(_data, 20) != 0; 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) * Returns the type (held as a little endian in bytes 3 and 4)
* that this class handles. * that this class handles.
@ -210,4 +298,16 @@ public class ExOleObjAtom extends RecordAtom {
out.write(_header); out.write(_header);
out.write(_data); 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();
}
} }

View File

@ -20,6 +20,7 @@ package org.apache.poi.hslf.record;
import java.io.*; import java.io.*;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
import java.util.zip.DeflaterOutputStream; import java.util.zip.DeflaterOutputStream;
import java.util.Hashtable;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
@ -28,7 +29,7 @@ import org.apache.poi.util.LittleEndian;
* *
* @author Daniel Noll * @author Daniel Noll
*/ */
public class ExOleObjStg extends RecordAtom implements PersistRecord { public class ExOleObjStg extends RecordAtom implements PositionDependentRecord, PersistRecord {
private int _persistId; // Found from PersistPtrHolder private int _persistId; // Found from PersistPtrHolder
@ -45,10 +46,11 @@ public class ExOleObjStg extends RecordAtom implements PersistRecord {
/** /**
* Constructs a new empty storage container. * Constructs a new empty storage container.
*/ */
protected ExOleObjStg() { public ExOleObjStg() {
_header = new byte[8]; _header = new byte[8];
_data = new byte[0]; _data = new byte[0];
LittleEndian.putShort(_header, 0, (short)0x10);
LittleEndian.putShort(_header, 2, (short)getRecordType()); LittleEndian.putShort(_header, 2, (short)getRecordType());
LittleEndian.putInt(_header, 4, _data.length); LittleEndian.putInt(_header, 4, _data.length);
} }
@ -90,6 +92,10 @@ public class ExOleObjStg extends RecordAtom implements PersistRecord {
return new InflaterInputStream(compressedStream); return new InflaterInputStream(compressedStream);
} }
public byte[] getRawData() {
return _data;
}
/** /**
* Sets the embedded data. * Sets the embedded data.
* *
@ -144,4 +150,23 @@ public class ExOleObjStg extends RecordAtom implements PersistRecord {
public void setPersistId(int id) { public void setPersistId(int id) {
_persistId = 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;
}
} }

View File

@ -0,0 +1,108 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
/**
* A container record that specifies information about external video data.
*
* @author Yegor Kozlov
*/
public class ExVideoContainer extends RecordContainer {
private byte[] _header;
// Links to our more interesting children
private ExMediaAtom mediaAtom;
//the UNC or local path to a video file.
private CString pathAtom;
/**
* Set things up, and find our more interesting children
*/
protected ExVideoContainer(byte[] source, int start, int len) {
// Grab the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
// Find our children
_children = Record.findChildRecords(source,start+8,len-8);
findInterestingChildren();
}
/**
* Go through our child records, picking out the ones that are
* interesting, and saving those for use by the easy helper
* methods.
*/
private void findInterestingChildren() {
// First child should be the ExMediaAtom
if(_children[0] instanceof ExMediaAtom) {
mediaAtom = (ExMediaAtom)_children[0];
} else {
logger.log(POILogger.ERROR, "First child record wasn't a ExMediaAtom, was of type " + _children[0].getRecordType());
}
if(_children[1] instanceof CString) {
pathAtom = (CString)_children[1];
} else {
logger.log(POILogger.ERROR, "Second child record wasn't a CString, was of type " + _children[1].getRecordType());
}
}
/**
* Create a new ExVideoContainer, with blank fields
*/
public ExVideoContainer() {
// Setup our header block
_header = new byte[8];
_header[0] = 0x0f; // We are a container record
LittleEndian.putShort(_header, 2, (short)getRecordType());
_children = new Record[2];
_children[0] = mediaAtom = new ExMediaAtom();
_children[1] = pathAtom = new CString();
}
/**
* We are of type 4103
*/
public long getRecordType() { return RecordTypes.ExVideoContainer.typeID; }
/**
* Write the contents of the record back, so it can be written
* to disk
*/
public void writeOut(OutputStream out) throws IOException {
writeOut(_header[0],_header[1],getRecordType(),_children,out);
}
/**
* Returns the ExMediaAtom of this link
*/
public ExMediaAtom getExMediaAtom() { return mediaAtom; }
/**
* Returns the Path Atom (CString) of this link
*/
public CString getPathAtom() { return pathAtom; }
}

View File

@ -39,27 +39,39 @@ public class InteractiveInfoAtom extends RecordAtom
/** /**
* Action Table * Action Table
*/ */
public static final int ACTION_NONE = 0; public static final byte ACTION_NONE = 0;
public static final int ACTION_MACRO = 1; public static final byte ACTION_MACRO = 1;
public static final int ACTION_RUNPROGRAM = 2; public static final byte ACTION_RUNPROGRAM = 2;
public static final int ACTION_JUMP = 3; public static final byte ACTION_JUMP = 3;
public static final int ACTION_HYPERLINK = 4; public static final byte ACTION_HYPERLINK = 4;
public static final int ACTION_OLE = 5; public static final byte ACTION_OLE = 5;
public static final int ACTION_MEDIA = 6; public static final byte ACTION_MEDIA = 6;
public static final int ACTION_CUSTOMSHOW = 7; public static final byte ACTION_CUSTOMSHOW = 7;
/** /**
* Jump Table * Jump Table
*/ */
public static final int JUMP_NONE = 0; public static final byte JUMP_NONE = 0;
public static final int JUMP_NEXTSLIDE = 1; public static final byte JUMP_NEXTSLIDE = 1;
public static final int JUMP_PREVIOUSSLIDE = 2; public static final byte JUMP_PREVIOUSSLIDE = 2;
public static final int JUMP_FIRSTSLIDE = 3; public static final byte JUMP_FIRSTSLIDE = 3;
public static final int JUMP_LASTSLIDE = 4; public static final byte JUMP_LASTSLIDE = 4;
public static final int JUMP_LASTSLIDEVIEWED = 5; public static final byte JUMP_LASTSLIDEVIEWED = 5;
public static final int JUMP_ENDSHOW = 6; 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. * Record header.

View File

@ -0,0 +1,110 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import org.apache.poi.hslf.util.SystemTimeUtils;
import org.apache.poi.util.LittleEndian;
/**
* Atom that contains information that describes shape client data.
*
* @author Yegor Kozlov
*/
public class OEShapeAtom extends RecordAtom
{
/**
* Record header.
*/
private byte[] _header;
/**
* record data
*/
private byte[] _recdata;
/**
* Constructs a brand new link related atom record.
*/
public OEShapeAtom() {
_recdata = new byte[4];
_header = new byte[8];
LittleEndian.putShort(_header, 2, (short)getRecordType());
LittleEndian.putInt(_header, 4, _recdata.length);
}
/**
* Constructs the link related atom record from its
* source data.
*
* @param source the source data as a byte array.
* @param start the start offset into the byte array.
* @param len the length of the slice in the byte array.
*/
protected OEShapeAtom(byte[] source, int start, int len) {
// Get the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
// Grab the record data
_recdata = new byte[len-8];
System.arraycopy(source,start+8,_recdata,0,len-8);
}
/**
* Gets the record type.
* @return the record type.
*/
public long getRecordType() { return RecordTypes.OEShapeAtom.typeID; }
/**
* Write the contents of the record back, so it can be written
* to disk
*
* @param out the output stream to write to.
* @throws java.io.IOException if an error occurs.
*/
public void writeOut(OutputStream out) throws IOException {
out.write(_header);
out.write(_recdata);
}
/**
* shape flags.
*
* @return shape flags.
*/
public int getOptions(){
return LittleEndian.getInt(_recdata, 0);
}
/**
* shape flags.
*
* @param id shape flags.
*/
public void setOptions(int id){
LittleEndian.putInt(_recdata, 0, id);
}
}

View File

@ -77,7 +77,7 @@ public class RecordTypes {
public static final Type BookmarkSeedAtom = new Type(2025,null); public static final Type BookmarkSeedAtom = new Type(2025,null);
public static final Type ColorSchemeAtom = new Type(2032,ColorSchemeAtom.class); public static final Type ColorSchemeAtom = new Type(2032,ColorSchemeAtom.class);
public static final Type ExObjRefAtom = new Type(3009,null); 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 OEPlaceholderAtom = new Type(3011,OEPlaceholderAtom.class);
public static final Type GPopublicintAtom = new Type(3024,null); public static final Type GPopublicintAtom = new Type(3024,null);
public static final Type GRatioAtom = new Type(3031,null); public static final Type GRatioAtom = new Type(3031,null);
@ -128,11 +128,11 @@ public class RecordTypes {
public static final Type DateTimeMCAtom = new Type(4087,null); public static final Type DateTimeMCAtom = new Type(4087,null);
public static final Type GenericDateMCAtom = new Type(4088,null); public static final Type GenericDateMCAtom = new Type(4088,null);
public static final Type FooterMCAtom = new Type(4090,null); public static final Type FooterMCAtom = new Type(4090,null);
public static final Type ExControlAtom = new Type(4091,null); public static final Type ExControlAtom = new Type(4091,ExControlAtom.class);
public static final Type ExMediaAtom = new Type(4100,null); public static final Type ExMediaAtom = new Type(4100,ExMediaAtom.class);
public static final Type ExVideo = new Type(4101,null); public static final Type ExVideoContainer = new Type(4101,ExVideoContainer.class);
public static final Type ExAviMovie = new Type(4102,null); public static final Type ExAviMovie = new Type(4102,ExAviMovie.class);
public static final Type ExMCIMovie = new Type(4103,null); public static final Type ExMCIMovie = new Type(4103,ExMCIMovie.class);
public static final Type ExMIDIAudio = new Type(4109,null); public static final Type ExMIDIAudio = new Type(4109,null);
public static final Type ExCDAudio = new Type(4110,null); public static final Type ExCDAudio = new Type(4110,null);
public static final Type ExWAVAudioEmbedded = new Type(4111,null); public static final Type ExWAVAudioEmbedded = new Type(4111,null);
@ -140,7 +140,8 @@ public class RecordTypes {
public static final Type ExOleObjStg = new Type(4113,ExOleObjStg.class); public static final Type ExOleObjStg = new Type(4113,ExOleObjStg.class);
public static final Type ExCDAudioAtom = new Type(4114,null); public static final Type ExCDAudioAtom = new Type(4114,null);
public static final Type ExWAVAudioEmbeddedAtom = new Type(4115,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 RTFDateTimeMCAtom = new Type(4117,null);
public static final Type ProgTags = new Type(5000,DummyPositionSensitiveRecordWithChildren.class); public static final Type ProgTags = new Type(5000,DummyPositionSensitiveRecordWithChildren.class);
public static final Type ProgStringTag = new Type(5001,null); public static final Type ProgStringTag = new Type(5001,null);

View File

@ -367,8 +367,14 @@ public class StyleTextPropAtom extends RecordAtom
rawContents = baos.toByteArray(); 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 * Create a new Paragraph TextPropCollection, and add it to the list
* @param charactersCovered The number of characters this TextPropCollection will cover * @param charactersCovered The number of characters this TextPropCollection will cover
* @return the new TextPropCollection, which will then be in the list * @return the new TextPropCollection, which will then be in the list

View File

@ -53,7 +53,7 @@ public class TextRulerAtom extends RecordAtom {
/** /**
* Constructs a new empty ruler atom. * Constructs a new empty ruler atom.
*/ */
protected TextRulerAtom() { public TextRulerAtom() {
_header = new byte[8]; _header = new byte[8];
_data = new byte[0]; _data = new byte[0];
@ -191,4 +191,19 @@ public class TextRulerAtom extends RecordAtom {
public int[] getBulletOffsets(){ public int[] getBulletOffsets(){
return bulletOffsets; return bulletOffsets;
} }
public static TextRulerAtom getParagraphInstance(){
byte[] data = new byte[] {
0x00, 0x00, (byte)0xA6, 0x0F, 0x0A, 0x00, 0x00, 0x00,
0x10, 0x03, 0x00, 0x00, (byte)0xF9, 0x00, 0x41, 0x01, 0x41, 0x01
};
TextRulerAtom ruler = new TextRulerAtom(data, 0, data.length);
return ruler;
}
public void setParagraphIndent(short tetxOffset, short bulletOffset){
LittleEndian.putShort(_data, 4, tetxOffset);
LittleEndian.putShort(_data, 6, bulletOffset);
LittleEndian.putShort(_data, 8, bulletOffset);
}
} }

View File

@ -687,6 +687,7 @@ public class RichTextRun {
*/ */
public void setBulletFont(int idx) { public void setBulletFont(int idx) {
setParaTextPropVal("bullet.font", idx); setParaTextPropVal("bullet.font", idx);
setFlag(false, ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true);
} }
/** /**

View File

@ -24,11 +24,7 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherContainerRecord;
@ -38,21 +34,9 @@ import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException; import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.model.*; import org.apache.poi.hslf.model.*;
import org.apache.poi.hslf.record.Document; import org.apache.poi.hslf.model.Notes;
import org.apache.poi.hslf.record.DocumentAtom; import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.record.FontCollection; import org.apache.poi.hslf.record.*;
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.record.SlideListWithText.SlideAtomsSet; import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
import org.apache.poi.util.ArrayUtil; import org.apache.poi.util.ArrayUtil;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
@ -590,9 +574,8 @@ public final class SlideShow {
* Create a blank <code>Slide</code>. * Create a blank <code>Slide</code>.
* *
* @return the created <code>Slide</code> * @return the created <code>Slide</code>
* @throws IOException
*/ */
public Slide createSlide() throws IOException { public Slide createSlide() {
SlideListWithText slist = null; SlideListWithText slist = null;
// We need to add the records to the SLWT that deals // We need to add the records to the SLWT that deals
@ -660,9 +643,13 @@ public final class SlideShow {
for (int i = 0; i < _records.length; i++) { for (int i = 0; i < _records.length; i++) {
Record record = _records[i]; Record record = _records[i];
ByteArrayOutputStream out = new ByteArrayOutputStream(); 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){ if(_records[i].getRecordType() == RecordTypes.PersistPtrIncrementalBlock.typeID){
ptr = (PersistPtrHolder)_records[i]; ptr = (PersistPtrHolder)_records[i];
} }
@ -888,4 +875,72 @@ public final class SlideShow {
} }
} }
/**
* 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;
}
} }

View File

@ -0,0 +1,66 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import junit.framework.TestCase;
import java.io.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.HSLFSlideShow;
/**
* Test <code>MovieShape</code> object.
*
* @author Yegor Kozlov
*/
public class TestMovieShape extends TestCase {
protected String cwd = System.getProperty("HSLF.testdata.path");
public void testCreate() throws Exception {
SlideShow ppt = new SlideShow();
Slide slide = ppt.createSlide();
String path = cwd + "/test-movie.mpg";
int movieIdx = ppt.addMovie(path, MovieShape.MOVIE_MPEG);
int thumbnailIdx = ppt.addPicture(new File(cwd, "tomcat.png"), Picture.PNG);
MovieShape shape = new MovieShape(movieIdx, thumbnailIdx);
shape.setAnchor(new Rectangle2D.Float(300,225,120,90));
slide.addShape(shape);
assertEquals(path, shape.getPath());
assertTrue(shape.isAutoPlay());
shape.setAutoPlay(false);
assertFalse(shape.isAutoPlay());
ByteArrayOutputStream out = new ByteArrayOutputStream();
ppt.write(out);
ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
slide = ppt.getSlides()[0];
shape = (MovieShape)slide.getShapes()[0];
assertEquals(path, shape.getPath());
assertFalse(shape.isAutoPlay());
}
}

View File

@ -0,0 +1,63 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import junit.framework.TestCase;
import java.io.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.HSLFSlideShow;
/**
* Test <code>Table</code> object.
*
* @author Yegor Kozlov
*/
public class TestTable extends TestCase {
/**
* Test that ShapeFactory works properly and returns <code>Table</code>
*/
public void testShapeFactory() throws Exception {
SlideShow ppt = new SlideShow();
Slide slide = ppt.createSlide();
Table tbl = new Table(2, 5);
slide.addShape(tbl);
assertTrue(slide.getShapes()[0] instanceof Table);
Table tbl2 = (Table)slide.getShapes()[0];
assertEquals(tbl.getNumberOfColumns(), tbl2.getNumberOfColumns());
assertEquals(tbl.getNumberOfRows(), tbl2.getNumberOfRows());
ByteArrayOutputStream out = new ByteArrayOutputStream();
ppt.write(out);
out.close();
ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
slide = ppt.getSlides()[0];
assertTrue(slide.getShapes()[0] instanceof Table);
Table tbl3 = (Table)slide.getShapes()[0];
assertEquals(tbl.getNumberOfColumns(), tbl3.getNumberOfColumns());
assertEquals(tbl.getNumberOfRows(), tbl3.getNumberOfRows());
}
}

View File

@ -0,0 +1,91 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import org.apache.poi.util.HexDump;
/**
* Tests that {@link HeadersFootersAtom} works properly
*
* @author Yegor Kozlov
*/
public class TestAnimationInfoAtom extends TestCase {
// From a real file
/*
<AnimationInfoAtom info="1" type="4081" size="28" offset="4015" header="01 00 F1 0F 1C 00 00 00 ">
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
00 00 00
</AnimationInfoAtom>
*/
private byte[] data = new byte[] {
0x01, 0x00, (byte)0xF1, 0x0F, 0x1C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
public void testRead() throws Exception {
AnimationInfoAtom record = new AnimationInfoAtom(data, 0, data.length);
assertEquals(RecordTypes.AnimationInfoAtom.typeID, record.getRecordType());
assertTrue(record.getFlag(AnimationInfoAtom.Automatic));
assertTrue(record.getFlag(AnimationInfoAtom.Play));
assertTrue(record.getFlag(AnimationInfoAtom.Synchronous));
assertFalse(record.getFlag(AnimationInfoAtom.Reverse));
assertFalse(record.getFlag(AnimationInfoAtom.Sound));
assertFalse(record.getFlag(AnimationInfoAtom.StopSound));
assertFalse(record.getFlag(AnimationInfoAtom.Hide));
assertFalse(record.getFlag(AnimationInfoAtom.AnimateBg));
assertEquals(0x07000000, record.getDimColor());
assertEquals(0, record.getSoundIdRef());
assertEquals(0, record.getDelayTime());
assertEquals(2, record.getOrderID());
assertEquals(0, record.getSlideCount());
}
public void testWrite() throws Exception {
AnimationInfoAtom record = new AnimationInfoAtom(data, 0, data.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
public void testNewRecord() throws Exception {
AnimationInfoAtom record = new AnimationInfoAtom();
record.setDimColor(0x07000000);
record.setOrderID(2);
record.setFlag(AnimationInfoAtom.Automatic, true);
record.setFlag(AnimationInfoAtom.Play, true);
record.setFlag(AnimationInfoAtom.Synchronous, true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
}

View File

@ -0,0 +1,127 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
/**
* Tests that {@link org.apache.poi.hslf.record.ExControl} works properly
*
* @author Yegor Kozlov
*/
public class TestExControl extends TestCase {
// From a real file (embedded SWF control)
/*
<ExControl info="15" type="4078" size="218" offset="76" header="0F 00 EE 0F DA 00 00 00 ">
<ExControlAtom info="0" type="4091" size="4" offset="84" header="00 00 FB 0F 04 00 00 00 ">
00 01 00 00
</ExControlAtom>
<ExOleObjAtom info="1" type="4035" size="24" offset="96" header="01 00 C3 0F 18 00 00 00 ">
01 00 00 00 02 00 00 00 01 00 00 00 00 00 00 00 02 00 00 00 00 96 13 00
</ExOleObjAtom>
<CString info="16" type="4026" size="44" offset="128" header="10 00 BA 0F 2C 00 00 00 ">
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
00 73 00 68 00 20 00 4F 00 62 00 6A 00 65 00 63 00 74 00
</CString>
<CString info="32" type="4026" size="62" offset="180" header="20 00 BA 0F 3E 00 00 00 ">
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
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
6C 00 61 00 73 00 68 00 2E 00 39 00
</CString>
<CString info="48" type="4026" size="44" offset="250" header="30 00 BA 0F 2C 00 00 00 ">
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
00 73 00 68 00 20 00 4F 00 62 00 6A 00 65 00 63 00 74 00
</CString>
</ExControl>
*/
private byte[] data = new byte[] {
0x0F, 0x00, (byte)0xEE, 0x0F, (byte)0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)0xFB, 0x0F, 0x04, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x01, 0x00, (byte)0xC3, 0x0F, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, (byte)0x96, 0x13, 0x00,
0x10, 0x00, (byte)0xBA, 0x0F, 0x2C, 0x00, 0x00, 0x00, 0x53, 0x00, 0x68, 0x00, 0x6F, 0x00, 0x63, 0x00, 0x6B, 0x00,
0x77, 0x00, 0x61, 0x00, 0x76, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68,
0x00, 0x20, 0x00, 0x4F, 0x00, 0x62, 0x00, 0x6A, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x20, 0x00, (byte)0xBA,
0x0F, 0x3E, 0x00, 0x00, 0x00, 0x53, 0x00, 0x68, 0x00, 0x6F, 0x00, 0x63, 0x00, 0x6B, 0x00, 0x77, 0x00, 0x61, 0x00,
0x76, 0x00, 0x65, 0x00, 0x46, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x2E, 0x00, 0x53, 0x00, 0x68,
0x00, 0x6F, 0x00, 0x63, 0x00, 0x6B, 0x00, 0x77, 0x00, 0x61, 0x00, 0x76, 0x00, 0x65, 0x00, 0x46, 0x00, 0x6C, 0x00,
0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x2E, 0x00, 0x39, 0x00, 0x30, 0x00, (byte)0xBA, 0x0F, 0x2C, 0x00, 0x00, 0x00,
0x53, 0x00, 0x68, 0x00, 0x6F, 0x00, 0x63, 0x00, 0x6B, 0x00, 0x77, 0x00, 0x61, 0x00, 0x76, 0x00, 0x65, 0x00, 0x20,
0x00, 0x46, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x73, 0x00, 0x68, 0x00, 0x20, 0x00, 0x4F, 0x00, 0x62, 0x00, 0x6A, 0x00,
0x65, 0x00, 0x63, 0x00, 0x74, 0x00
};
public void testRead() throws Exception {
ExControl record = new ExControl(data, 0, data.length);
assertEquals(RecordTypes.ExControl.typeID, record.getRecordType());
assertNotNull(record.getExControlAtom());
assertEquals(256, record.getExControlAtom().getSlideId());
ExOleObjAtom oleObj = record.getExOleObjAtom();
assertNotNull(oleObj);
assertEquals(oleObj.getDrawAspect(), ExOleObjAtom.DRAW_ASPECT_VISIBLE);
assertEquals(oleObj.getType(), ExOleObjAtom.TYPE_CONTROL);
assertEquals(oleObj.getSubType(), ExOleObjAtom.SUBTYPE_DEFAULT);
assertEquals("Shockwave Flash Object", record.getMenuName());
assertEquals("ShockwaveFlash.ShockwaveFlash.9", record.getProgId());
assertEquals("Shockwave Flash Object", record.getClipboardName());
}
public void testWrite() throws Exception {
ExControl record = new ExControl(data, 0, data.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
public void testNewRecord() throws Exception {
ExControl record = new ExControl();
ExControlAtom ctrl = record.getExControlAtom();
ctrl.setSlideId(256);
ExOleObjAtom oleObj = record.getExOleObjAtom();
oleObj.setDrawAspect(ExOleObjAtom.DRAW_ASPECT_VISIBLE);
oleObj.setType(ExOleObjAtom.TYPE_CONTROL);
oleObj.setObjID(1);
oleObj.setSubType(ExOleObjAtom.SUBTYPE_DEFAULT);
oleObj.setObjStgDataRef(2);
oleObj.setOptions(1283584);
record.setMenuName("Shockwave Flash Object");
record.setProgId("ShockwaveFlash.ShockwaveFlash.9");
record.setClipboardName("Shockwave Flash Object");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertEquals(data.length, b.length);
assertTrue(Arrays.equals(data, b));
}
}

View File

@ -0,0 +1,94 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
/**
* Tests that {@link org.apache.poi.hslf.record.HeadersFootersAtom} works properly
*
* @author Yegor Kozlov
*/
public class TestExMediaAtom extends TestCase {
// From a real file
private byte[] data = new byte[] {
0x00, 0x00, (byte)0x04, 0x10, 0x08, 0x00, 0x00, 00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
public void testRead() throws Exception {
ExMediaAtom record = new ExMediaAtom(data, 0, data.length);
assertEquals(RecordTypes.ExMediaAtom.typeID, record.getRecordType());
assertEquals(1, record.getObjectId());
assertFalse(record.getFlag(ExMediaAtom.fLoop));
assertFalse(record.getFlag(ExMediaAtom.fNarration));
assertFalse(record.getFlag(ExMediaAtom.fRewind));
}
public void testWrite() throws Exception {
ExMediaAtom record = new ExMediaAtom(data, 0, data.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
public void testNewRecord() throws Exception {
ExMediaAtom ref = new ExMediaAtom(data, 0, data.length);
System.out.println(ref.getMask());
ExMediaAtom record = new ExMediaAtom();
record.setObjectId(1);
record.setFlag(HeadersFootersAtom.fHasDate, false);
record.setFlag(HeadersFootersAtom.fHasTodayDate, false);
record.setFlag(HeadersFootersAtom.fHasFooter, false);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
public void testFlags() throws Exception {
ExMediaAtom record = new ExMediaAtom();
//in a new record all the bits are 0
for(int i = 0; i < 3; i++) assertFalse(record.getFlag(1 << i));
record.setFlag(ExMediaAtom.fLoop, true);
assertTrue(record.getFlag(ExMediaAtom.fLoop));
record.setFlag(ExMediaAtom.fNarration, true);
assertTrue(record.getFlag(ExMediaAtom.fNarration));
record.setFlag(ExMediaAtom.fNarration, false);
assertFalse(record.getFlag(ExMediaAtom.fNarration));
record.setFlag(ExMediaAtom.fNarration, false);
assertFalse(record.getFlag(ExMediaAtom.fNarration));
}
}

View File

@ -0,0 +1,78 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
/**
* Tests that {@link ExOleObjAtom} works properly
*
* @author Yegor Kozlov
*/
public class TestExOleObjAtom extends TestCase {
// From a real file (embedded SWF control)
private byte[] data = new byte[] {
0x01, 0x00, (byte)0xC3, 0x0F, 0x18, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, (byte)0x96, 0x13, 0x00 };
public void testRead() throws Exception {
ExOleObjAtom record = new ExOleObjAtom(data, 0, data.length);
assertEquals(RecordTypes.ExOleObjAtom.typeID, record.getRecordType());
System.out.println(record);
assertEquals(record.getDrawAspect(), ExOleObjAtom.DRAW_ASPECT_VISIBLE);
assertEquals(record.getType(), ExOleObjAtom.TYPE_CONTROL);
assertEquals(record.getObjID(), 1);
assertEquals(record.getSubType(), ExOleObjAtom.SUBTYPE_DEFAULT);
assertEquals(record.getObjStgDataRef(), 2);
assertEquals(record.getOptions(), 1283584); //ther meaning is unknown
}
public void testWrite() throws Exception {
ExOleObjAtom record = new ExOleObjAtom(data, 0, data.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
public void testNewRecord() throws Exception {
ExOleObjAtom record = new ExOleObjAtom();
record.setDrawAspect(ExOleObjAtom.DRAW_ASPECT_VISIBLE);
record.setType(ExOleObjAtom.TYPE_CONTROL);
record.setObjID(1);
record.setSubType(ExOleObjAtom.SUBTYPE_DEFAULT);
record.setObjStgDataRef(2);
record.setOptions(1283584);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
}

View File

@ -0,0 +1,144 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.Arrays;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentEntry;
/**
* Tests that {@link ExOleObjStg} works properly
*
* @author Yegor Kozlov
*/
public class TestExOleObjStg extends TestCase {
// From a real file (embedded SWF control)
/*
<ExOleObjStg info="16" type="4113" size="347" offset="4322" header="10 00 11 10 5B 01 00 00 ">
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
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
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
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
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
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
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
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
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
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
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
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
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
88 97 08 35 91 83 81 07 EC 27 10 BF 18 E8 9B E1 0F 00 BD 65 3D D4
</ExOleObjStg>
*/
private byte[] data = new byte[] {
0x10, 0x00, 0x11, 0x10, 0x5B, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x78, (byte)0x9C, (byte)0xBB, 0x70,
0x5E, (byte)0xF0, (byte)0xC1, (byte)0xC2, (byte)0x8D, 0x52, 0x0F, 0x19, (byte)0xD0, (byte)0x80, 0x1D, 0x03,
0x33, (byte)0xC3, (byte)0xBF, (byte)0xFF, (byte)0x9C, 0x0C, 0x6C, 0x48, 0x62, (byte)0x8C, 0x40, (byte)0xCC,
0x04, (byte)0xE3, 0x08, 0x30, 0x30, (byte)0xB0, 0x40, (byte)0xC5, (byte)0xFE, (byte)0xFD, (byte)0xFF, (byte)0xFF,
0x1F, 0x24, (byte)0xC4, (byte)0x0C, (byte)0xC4, (byte)0xFF, 0x47, (byte)0xC1, (byte)0x90, 0x02, 0x41, 0x0C,
(byte)0xF9, 0x40, 0x58, (byte)0xC2, (byte)0xA0, (byte)0xC0, (byte)0xE0, (byte)0xCA, (byte)0x90, 0x07, (byte)0xA4,
(byte)0x8B, 0x18, 0x2A, (byte)0xD1, (byte)0x93, 0x02, 0x5E, 0x20, (byte)0xC6, (byte)0xC0, 0x0A, (byte)0x8F,
0x73, 0x50, 0x5A, (byte)0xC8, (byte)0xBB, 0x5D, 0x73, 0x29, 0x77, (byte)0xDD, 0x79, (byte)0xC1, 0x69, 0x3B,
0x5C, 0x5C, (byte)0x83, 0x43, 0x50, (byte)0xD5, 0x06, (byte)0xBC, 0x48, 0x2F, 0x2B, 0x66, 0x38, (byte)0xC9,
(byte)0xC8, 0x0E, 0x64, 0x3B, 0x30, 0x42, (byte)0xC4, (byte)0x9C, (byte)0x81, (byte)0xB6, (byte)0x83, (byte)0xEC,
0x4D, 0x05, (byte)0x93, (byte)0xC5, 0x24, (byte)0xD9, 0x0D, 0x02, 0x42, 0x0C, 0x4C, (byte)0x8C, (byte)0xC8,
(byte)0xFE, 0x21, 0x56, (byte)0x9F, 0x02, 0x23, (byte)0xC9, 0x56, (byte)0xE1, 0x04, (byte)0xE4, (byte)0xD8,
0x4F, 0x4D, 0x40, (byte)0x89, (byte)0xFD, (byte)0xA0, (byte)0xBC, (byte)0xFB, 0x17, 0x4B, (byte)0xBA, (byte)0xF8,
0x07, (byte)0xC5, (byte)0xA3, 0x60, 0x78, 0x03, 0x7A, (byte)0xE6, (byte)0xFF, 0x09, 0x67, 0x59, 0x1B, 0x41,
(byte)0xF9, (byte)0x9F, (byte)0x95, 0x61, 0x34, (byte)0xFF, 0x53, 0x13, 0x50, 0x62, 0x3F, 0x4C, 0x1F, (byte)0xAC,
0x1C, 0x18, (byte)0xCD, (byte)0xF7, 0x23, 0x0B, (byte)0xC0, (byte)0xDA, 0x74, (byte)0xA0, (byte)0xB6, 0x1B,
(byte)0xA8, 0x3D, 0x37, 0x1A, (byte)0xF7, 0x23, 0x0B, (byte)0xA4, (byte)0x87, (byte)0xA6, (byte)0x85, 0x0A,
0x00, 0x1B, 0x64, 0x6F, 0x38, 0x21, (byte)0x98, 0x03, (byte)0xDA, (byte)0xC2, (byte)0xE7, 0x60, (byte)0x90,
0x01, (byte)0x92, 0x69, 0x0C, 0x39, 0x0C, 0x65, 0x0C, 0x05, 0x40, 0x32, 0x11, 0x58, 0x2F, (byte)0xA4, 0x02,
0x6B, 0x07, 0x3D, 0x60, 0x19, 0x5D, 0x0E, 0x14, 0x27, 0x4E, 0x05, 0x1F, (byte)0x90, 0x0C, 0x67, (byte)0xC8,
0x04, (byte)0x96, (byte)0xED, 0x29, (byte)0xC0, 0x72, (byte)0xBE, 0x1C, (byte)0xC8, (byte)0xE3, 0x06, (byte)0xE3,
(byte)0xFF, (byte)0xFF, 0x39, 0x18, (byte)0xB8, (byte)0x80, 0x2C, 0x0F, (byte)0xA0, 0x5C, 0x3A, 0x43, 0x06, 0x58,
0x2D, (byte)0xA8, (byte)0xA7, (byte)0xE1, (byte)0xC3, 0x10, 0x02, (byte)0x97, (byte)0x87, (byte)0xB8, 0x02,
(byte)0xE6, 0x1A, 0x60, 0x77, (byte)0x83, 0x21, 0x18, (byte)0xA8, 0x12, 0x64, (byte)0x8A, 0x23, (byte)0xD0,
(byte)0xB6, 0x1C, (byte)0xB8, 0x59, (byte)0xC8, (byte)0xAA, (byte)0x90, (byte)0xF5, (byte)0xF0, 0x62, (byte)0x94,
0x75, (byte)0xDC, (byte)0xC0, (byte)0xDE, 0x0A, 0x37, 0x5C, 0x1D, 0x33, 0x54, 0x35, (byte)0x88, (byte)0x97, 0x08,
0x35, (byte)0x91, (byte)0x83, (byte)0x81, 0x07, (byte)0xEC, 0x27, 0x10, (byte)0xBF, 0x18, (byte)0xE8, (byte)0x9B,
(byte)0xE1, 0x0F, 0x00, (byte)0xBD, 0x65, 0x3D, (byte)0xD4
};
public void testRead() throws Exception {
ExOleObjStg record = new ExOleObjStg(data, 0, data.length);
assertEquals(RecordTypes.ExOleObjStg.typeID, record.getRecordType());
int len = record.getDataLength();
byte[] oledata = readAll(record.getData());
assertEquals(len, oledata.length);
POIFSFileSystem fs = new POIFSFileSystem(record.getData());
assertTrue("Constructed POIFS from ExOleObjStg data", true);
DocumentEntry doc = (DocumentEntry)fs.getRoot().getEntry("Contents");
assertNotNull(doc);
assertTrue("Fetched the Contents stream containing OLE properties", true);
}
public void testWrite() throws Exception {
ExOleObjStg record = new ExOleObjStg(data, 0, data.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
public void testNewRecord() throws Exception {
ExOleObjStg src = new ExOleObjStg(data, 0, data.length);
byte[] oledata = readAll(src.getData());
ExOleObjStg tgt = new ExOleObjStg();
tgt.setData(oledata);
assertEquals(src.getDataLength(), tgt.getDataLength());
ByteArrayOutputStream out = new ByteArrayOutputStream();
tgt.writeOut(out);
byte[] b = out.toByteArray();
assertEquals(data.length, b.length);
assertTrue(Arrays.equals(data, b));
}
private byte[] readAll(InputStream is) throws IOException {
int pos;
byte[] chunk = new byte[1024];
ByteArrayOutputStream out = new ByteArrayOutputStream();
while((pos = is.read(chunk)) > 0){
out.write(chunk, 0, pos);
}
return out.toByteArray();
}
}

View File

@ -0,0 +1,90 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
/**
* Tests that {@link HeadersFootersAtom} works properly
*
* @author Yegor Kozlov
*/
public class TestExVideoContainer extends TestCase {
// From a real file
private byte[] data = new byte[]{
0x0F, 0x00, 0x05, 0x10, (byte) 0x9E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x10, 0x08, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, (byte)0xBA, 0x0F, (byte)0x86, 0x00, 0x00, 0x00,
0x44, 0x00, 0x3A, 0x00, 0x5C, 0x00, 0x70, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x6A, 0x00, 0x65, 0x00,
0x63, 0x00, 0x74, 0x00, 0x73, 0x00, 0x5C, 0x00, 0x53, 0x00, 0x63, 0x00, 0x68, 0x00, 0x75, 0x00,
0x6C, 0x00, 0x65, 0x00, 0x72, 0x00, 0x41, 0x00, 0x47, 0x00, 0x5C, 0x00, 0x6D, 0x00, 0x63, 0x00,
0x6F, 0x00, 0x6D, 0x00, 0x5F, 0x00, 0x76, 0x00, 0x5F, 0x00, 0x31, 0x00, 0x5F, 0x00, 0x30, 0x00,
0x5F, 0x00, 0x34, 0x00, 0x5C, 0x00, 0x76, 0x00, 0x69, 0x00, 0x65, 0x00, 0x77, 0x00, 0x5C, 0x00,
0x64, 0x00, 0x61, 0x00, 0x74, 0x00, 0x61, 0x00, 0x5C, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
0x74, 0x00, 0x73, 0x00, 0x5C, 0x00, 0x69, 0x00, 0x6D, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00,
0x73, 0x00, 0x5C, 0x00, 0x63, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x73, 0x00, 0x2E, 0x00,
0x6D, 0x00, 0x70, 0x00, 0x67, 0x00};
public void testRead() throws Exception {
ExVideoContainer record = new ExVideoContainer(data, 0, data.length);
assertEquals(RecordTypes.ExVideoContainer.typeID, record.getRecordType());
ExMediaAtom exMedia = record.getExMediaAtom();
assertEquals(1, exMedia.getObjectId());
assertNotNull(exMedia);
assertFalse(exMedia.getFlag(ExMediaAtom.fLoop));
assertFalse(exMedia.getFlag(ExMediaAtom.fNarration));
assertFalse(exMedia.getFlag(ExMediaAtom.fRewind));
CString path = record.getPathAtom();
assertNotNull(exMedia);
assertEquals("D:\\projects\\SchulerAG\\mcom_v_1_0_4\\view\\data\\tests\\images\\cards.mpg", path.getText());
}
public void testWrite() throws Exception {
ExVideoContainer record = new ExVideoContainer(data, 0, data.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
public void testNewRecord() throws Exception {
ExVideoContainer record = new ExVideoContainer();
record.getExMediaAtom().setObjectId(1);
record.getPathAtom().setText("D:\\projects\\SchulerAG\\mcom_v_1_0_4\\view\\data\\tests\\images\\cards.mpg");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
record.writeOut(baos);
byte[] b = baos.toByteArray();
assertTrue(Arrays.equals(data, b));
}
}

View File

@ -48,6 +48,10 @@ public class TestTextRulerAtom extends TestCase {
0x03, 0x69, 0x04, (byte)0xF6, 0x05, (byte)0xF6, 0x05 0x03, 0x69, 0x04, (byte)0xF6, 0x05, (byte)0xF6, 0x05
}; };
private byte[] data_2 = new byte[] {
0x00, 0x00, (byte)0xA6, 0x0F, 0x0A, 0x00, 0x00, 0x00,
0x10, 0x03, 0x00, 0x00, (byte)0xF9, 0x00, 0x41, 0x01, 0x41, 0x01
};
public void testReadRuler() throws Exception { public void testReadRuler() throws Exception {
TextRulerAtom ruler = new TextRulerAtom(data_1, 0, data_1.length); TextRulerAtom ruler = new TextRulerAtom(data_1, 0, data_1.length);
@ -73,4 +77,16 @@ public class TestTextRulerAtom extends TestCase {
byte[] result = out.toByteArray(); byte[] result = out.toByteArray();
assertTrue(Arrays.equals(result, data_1)); assertTrue(Arrays.equals(result, data_1));
} }
public void testRead2() throws Exception {
TextRulerAtom ruler = TextRulerAtom.getParagraphInstance();
ruler.setParagraphIndent((short)249, (short)321);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ruler.writeOut(out);
byte[] result = out.toByteArray();
assertTrue(Arrays.equals(result, data_2));
}
} }