#56570 - RecordType has repeat by code type 3009

#58159 - getHeaderText() and getFooterText() duplicate text in sheet.getTextRuns()

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1722476 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2015-12-31 22:10:17 +00:00
parent ee6966dae9
commit f317f5e288
53 changed files with 1269 additions and 859 deletions

View File

@ -16,13 +16,10 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.hslf.examples; package org.apache.poi.hslf.examples;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException;
import org.apache.poi.ddf.EscherClientDataRecord;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.hslf.record.InteractiveInfo;
import org.apache.poi.hslf.record.InteractiveInfoAtom; import org.apache.poi.hslf.record.InteractiveInfoAtom;
import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.usermodel.HSLFShape; import org.apache.poi.hslf.usermodel.HSLFShape;
import org.apache.poi.hslf.usermodel.HSLFSlide; import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.hslf.usermodel.HSLFSlideShow;
@ -30,12 +27,11 @@ import org.apache.poi.hslf.usermodel.HSLFSoundData;
/** /**
* For each slide iterate over shapes and found associated sound data. * For each slide iterate over shapes and found associated sound data.
*
* @author Yegor Kozlov
*/ */
public class SoundFinder { public class SoundFinder {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws IOException {
HSLFSlideShow ppt = new HSLFSlideShow(new FileInputStream(args[0])); FileInputStream fis = new FileInputStream(args[0]);
HSLFSlideShow ppt = new HSLFSlideShow(fis);
HSLFSoundData[] sounds = ppt.getSoundData(); HSLFSoundData[] sounds = ppt.getSoundData();
for (HSLFSlide slide : ppt.getSlides()) { for (HSLFSlide slide : ppt.getSlides()) {
@ -49,6 +45,8 @@ public class SoundFinder {
System.out.println(" " + sounds[soundRef].getSoundType()); System.out.println(" " + sounds[soundRef].getSoundType());
} }
} }
ppt.close();
fis.close();
} }
/** /**
@ -59,20 +57,10 @@ public class SoundFinder {
protected static int getSoundReference(HSLFShape shape){ protected static int getSoundReference(HSLFShape shape){
int soundRef = -1; int soundRef = -1;
//dive into the shape container and search for InteractiveInfoAtom //dive into the shape container and search for InteractiveInfoAtom
EscherContainerRecord spContainer = shape.getSpContainer(); InteractiveInfoAtom info = shape.getClientDataRecord(RecordTypes.InteractiveInfo.typeID);
for (EscherRecord obj : spContainer.getChildRecords()) { if (info != null && info.getAction() == InteractiveInfoAtom.ACTION_MEDIA) {
if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
byte[] data = obj.serialize();
for (Record record : Record.findChildRecords(data, 8, data.length - 8)) {
if (record instanceof InteractiveInfo) {
InteractiveInfoAtom info = ((InteractiveInfo)record).getInteractiveInfoAtom();
if (info.getAction() == InteractiveInfoAtom.ACTION_MEDIA) {
soundRef = info.getSoundRef(); soundRef = info.getSoundRef();
} }
}
}
}
}
return soundRef; return soundRef;
} }
} }

View File

@ -23,7 +23,7 @@ import java.awt.Rectangle;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
/** /**
* How to set slide title * How to set slide title

View File

@ -76,7 +76,7 @@ public class EscherClientDataRecord
public String toString() public String toString()
{ {
String nl = System.getProperty("line.separator"); String nl = System.getProperty("line.separator");
String extraData = HexDump.dump(this.remainingData, 0, 0); String extraData = HexDump.dump(getRemainingData(), 0, 0);
return getClass().getName() + ":" + nl + return getClass().getName() + ":" + nl +
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl + " RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
" Version: 0x" + HexDump.toHex(getVersion()) + nl + " Version: 0x" + HexDump.toHex(getVersion()) + nl +
@ -88,7 +88,7 @@ public class EscherClientDataRecord
@Override @Override
public String toXml(String tab) { public String toXml(String tab) {
String extraData = HexDump.dump(this.remainingData, 0, 0).trim(); String extraData = HexDump.dump(getRemainingData(), 0, 0).trim();
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()),
HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) HexDump.toHex(getVersion()), HexDump.toHex(getInstance())))

View File

@ -33,7 +33,12 @@ public class DrawMasterSheet extends DrawSheet {
* for instance, slide masters and layouts don't display placeholders * for instance, slide masters and layouts don't display placeholders
*/ */
@Override @Override
protected boolean canDraw(Shape<?,?> shape){ protected boolean canDraw(Shape<?,?> shape) {
return !(shape instanceof SimpleShape) || !((SimpleShape<?,?>)shape).isPlaceholder(); if (shape instanceof SimpleShape) {
Placeholder ph = ((SimpleShape<?,?>)shape).getPlaceholder();
return ph == null;
} else {
return true;
}
} }
} }

View File

@ -0,0 +1,138 @@
/* ====================================================================
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.sl.usermodel;
public enum Placeholder {
/**
* No placeholder shape.
*/
NONE(0,0,0,0,0),
/**
* Title text placeholder shape.
*/
TITLE(13,1,1,1,1),
/**
* Body text placeholder shape.
*/
BODY(14,2,12,6,2),
/**
* Center title text placeholder shape.
*/
CENTERED_TITLE(15,3,3,3,3),
/**
* Sub-title text placeholder shape.
*/
SUBTITLE(16,4,4,4,4),
/**
* Date placeholder shape.
*/
DATETIME(7,7,7,7,5),
/**
* Slide number placeholder shape.
*/
SLIDE_NUMBER(8,8,8,8,6),
/**
* Footer placeholder shape.
*/
FOOTER(9,9,9,9,7),
/**
* Header placeholder shape.
*/
HEADER(10,10,10,10,8),
/**
* Object placeholder shape.
*/
CONTENT(19,19,19,19,9),
/**
* Graph object placeholder shape.
*/
CHART(20,20,20,20,10),
/**
* Table object placeholder shape.
*/
TABLE(21,21,21,21,11),
/**
* Clipart object placeholder shape.
*/
CLIP_ART(22,22,22,22,12),
/**
* Organization chart object placeholder shape.
*/
DGM(23,23,23,23,13),
/**
* Media object placeholder shape.
*/
MEDIA(24,24,24,24,14),
/**
* Slide image placeholder shape.
*/
SLIDE_IMAGE(11,11,11,5,15),
/**
* Picture object placeholder shape.
*/
PICTURE(26,26,26,26,16),
/**
* Vertical object placeholder shape.
*/
VERTICAL_OBJECT(25,25,25,25,-2),
/**
* Vertical title text placeholder shape.
*/
VERTICAL_TEXT_TITLE(17,17,17,17,-2),
/**
* Vertical body text placeholder shape.
*/
VERTICAL_TEXT_BODY(18,18,18,18,-2)
;
public final int nativeSlideId;
public final int nativeSlideMasterId;
public final int nativeNotesId;
public final int nativeNotesMasterId;
public final int ooxmlId;
Placeholder(int nativeSlideId, int nativeSlideMasterId, int nativeNotesId, int nativeNotesMasterId, int ooxmlId) {
this.nativeSlideId = nativeSlideId;
this.nativeSlideMasterId = nativeSlideMasterId;
this.nativeNotesId = nativeNotesId;
this.nativeNotesMasterId = nativeNotesMasterId;
this.ooxmlId = ooxmlId;
}
public static Placeholder lookupNative(int nativeId) {
for (Placeholder ph : values()) {
if (ph.nativeSlideId == nativeId ||
ph.nativeSlideMasterId == nativeId ||
ph.nativeNotesId == nativeId ||
ph.nativeNotesMasterId == nativeId
) {
return ph;
}
}
return null;
}
public static Placeholder lookupOoxml(int ooxmlId) {
for (Placeholder ph : values()) {
if (ph.ooxmlId == ooxmlId) {
return ph;
}
}
return null;
}
}

View File

@ -28,25 +28,6 @@ public interface SimpleShape<
P extends TextParagraph<S,P,?> P extends TextParagraph<S,P,?>
> extends Shape<S,P>, IAdjustableShape, PlaceableShape<S,P> { > extends Shape<S,P>, IAdjustableShape, PlaceableShape<S,P> {
enum Placeholder {
TITLE,
BODY,
CENTERED_TITLE,
SUBTITLE,
DATETIME,
SLIDE_NUMBER,
FOOTER,
HEADER,
CONTENT,
CHART,
TABLE,
CLIP_ART,
DGM,
MEDIA,
SLIDE_IMAGE,
PICTURE
}
FillStyle getFillStyle(); FillStyle getFillStyle();
LineDecoration getLineDecoration(); LineDecoration getLineDecoration();
@ -69,7 +50,20 @@ public interface SimpleShape<
ShapeType getShapeType(); ShapeType getShapeType();
void setShapeType(ShapeType type); void setShapeType(ShapeType type);
boolean isPlaceholder(); /**
* @return the placeholder or null if none is assigned
* @see #setPlaceholder(Placeholder)
*/
Placeholder getPlaceholder();
/**
* Specifies that the corresponding shape should be represented by the generating application
* as a placeholder. When a shape is considered a placeholder by the generating application
* it can have special properties to alert the user that they may enter content into the shape.
*
* @param placeholder the placeholder or null to remove the reference to the placeholder
*/
void setPlaceholder(Placeholder placeholder);
Shadow<S,P> getShadow(); Shadow<S,P> getShadow();

View File

@ -21,11 +21,13 @@ import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import org.apache.poi.POIXMLException;
import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.Background; import org.apache.poi.sl.usermodel.Background;
import org.apache.poi.sl.usermodel.ColorStyle; import org.apache.poi.sl.usermodel.ColorStyle;
import org.apache.poi.sl.usermodel.FillStyle; import org.apache.poi.sl.usermodel.FillStyle;
import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D; import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground;
@ -70,4 +72,10 @@ public class XSLFBackground extends XSLFSimpleShape
protected CTTransform2D getXfrm() { protected CTTransform2D getXfrm() {
return CTTransform2D.Factory.newInstance(); return CTTransform2D.Factory.newInstance();
} }
@Override
public void setPlaceholder(Placeholder placeholder) {
// extending XSLFSimpleShape is a bit unlucky ...
throw new POIXMLException("Can't set a placeholder for a background");
}
} }

View File

@ -19,7 +19,9 @@
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import org.apache.poi.POIXMLException;
import org.apache.poi.sl.usermodel.ConnectorShape; import org.apache.poi.sl.usermodel.ConnectorShape;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D; import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
@ -69,4 +71,8 @@ public class XSLFConnectorShape extends XSLFSimpleShape
return null; return null;
} }
@Override
public void setPlaceholder(Placeholder placeholder) {
throw new POIXMLException("A connector shape can't be a placeholder.");
}
} }

View File

@ -28,6 +28,7 @@ import org.apache.poi.POIXMLException;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.sl.usermodel.PictureShape; import org.apache.poi.sl.usermodel.PictureShape;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
@ -119,6 +120,12 @@ public class XSLFPictureShape extends XSLFSimpleShape
return _data; return _data;
} }
@Override
public void setPlaceholder(Placeholder placeholder) {
super.setPlaceholder(placeholder);
}
/** /**
* For an external linked picture, return the last-seen * For an external linked picture, return the last-seen
* path to the picture. * path to the picture.
@ -168,7 +175,6 @@ public class XSLFPictureShape extends XSLFSimpleShape
return (r == null) ? null : new Insets(r.getT(), r.getL(), r.getB(), r.getR()); return (r == null) ? null : new Insets(r.getT(), r.getL(), r.getB(), r.getR());
} }
@SuppressWarnings("deprecation")
@Override @Override
void copy(XSLFShape sh){ void copy(XSLFShape sh){
super.copy(sh); super.copy(sh);

View File

@ -33,7 +33,7 @@ import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint; import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;
import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
import org.apache.poi.sl.usermodel.PlaceableShape; import org.apache.poi.sl.usermodel.PlaceableShape;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.Shape; import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
@ -255,6 +255,14 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
return _ph; return _ph;
} }
public Placeholder getPlaceholder() {
CTPlaceholder ph = getCTPlaceholder();
if (ph == null || !ph.isSetType()) {
return null;
}
return Placeholder.lookupOoxml(ph.getType().intValue());
}
/** /**
* Specifies that the corresponding shape should be represented by the generating application * Specifies that the corresponding shape should be represented by the generating application
* as a placeholder. When a shape is considered a placeholder by the generating application * as a placeholder. When a shape is considered a placeholder by the generating application
@ -272,7 +280,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
if (nv.isSetPh()) nv.unsetPh(); if (nv.isSetPh()) nv.unsetPh();
_ph = null; _ph = null;
} else { } else {
nv.addNewPh().setType(STPlaceholderType.Enum.forInt(placeholder.ordinal() + 1)); nv.addNewPh().setType(STPlaceholderType.Enum.forInt(placeholder.ooxmlId));
} }
} }
@ -442,7 +450,6 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
protected PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr) { protected PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr) {
@SuppressWarnings("deprecation")
final CTGradientStop[] gs = gradFill.getGsLst().getGsArray(); final CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
Arrays.sort(gs, new Comparator<CTGradientStop>() { Arrays.sort(gs, new Comparator<CTGradientStop>() {

View File

@ -42,8 +42,8 @@ import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.DrawPictureShape; import org.apache.poi.sl.draw.DrawPictureShape;
import org.apache.poi.sl.draw.Drawable; import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.PictureData; import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.Sheet; import org.apache.poi.sl.usermodel.Sheet;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;

View File

@ -34,6 +34,7 @@ import org.apache.poi.sl.usermodel.LineDecoration;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape; import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize; import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.SimpleShape; import org.apache.poi.sl.usermodel.SimpleShape;
@ -815,7 +816,6 @@ public abstract class XSLFSimpleShape extends XSLFShape
return ph != null; return ph != null;
} }
@SuppressWarnings("deprecation")
public Guide getAdjustValue(String name) { public Guide getAdjustValue(String name) {
CTPresetGeometry2D prst = getSpPr().getPrstGeom(); CTPresetGeometry2D prst = getSpPr().getPrstGeom();
if (prst.isSetAvLst()) { if (prst.isSetAvLst()) {
@ -918,4 +918,9 @@ public abstract class XSLFSimpleShape extends XSLFShape
} }
} }
} }
@Override
public void setPlaceholder(Placeholder placeholder) {
super.setPlaceholder(placeholder);
}
} }

View File

@ -27,7 +27,7 @@ import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.Drawable; import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.Notes; import org.apache.poi.sl.usermodel.Notes;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.Slide; import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;

View File

@ -24,7 +24,7 @@ import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.sl.usermodel.MasterSheet; import org.apache.poi.sl.usermodel.MasterSheet;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;

View File

@ -27,7 +27,7 @@ import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.sl.usermodel.MasterSheet; import org.apache.poi.sl.usermodel.MasterSheet;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping; import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping;

View File

@ -28,6 +28,7 @@ import org.apache.poi.POIXMLException;
import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.DrawTextShape; import org.apache.poi.sl.draw.DrawTextShape;
import org.apache.poi.sl.usermodel.Insets2D; import org.apache.poi.sl.usermodel.Insets2D;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.TextShape; import org.apache.poi.sl.usermodel.TextShape;
import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
@ -54,7 +55,6 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
implements TextShape<XSLFShape,XSLFTextParagraph> { implements TextShape<XSLFShape,XSLFTextParagraph> {
private final List<XSLFTextParagraph> _paragraphs; private final List<XSLFTextParagraph> _paragraphs;
@SuppressWarnings("deprecation")
/*package*/ XSLFTextShape(XmlObject shape, XSLFSheet sheet) { /*package*/ XSLFTextShape(XmlObject shape, XSLFSheet sheet) {
super(shape, sheet); super(shape, sheet);
@ -503,7 +503,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
if (ph == null) return null; if (ph == null) return null;
int val = ph.getType().intValue(); int val = ph.getType().intValue();
return Placeholder.values()[val - 1]; return Placeholder.lookupOoxml(val);
} }
@Override @Override

View File

@ -22,7 +22,7 @@ import static org.junit.Assert.assertNull;
import java.io.IOException; import java.io.IOException;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.xslf.XSLFTestDataSamples; import org.apache.poi.xslf.XSLFTestDataSamples;
import org.junit.Test; import org.junit.Test;

View File

@ -28,7 +28,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.poi.sl.draw.geom.TestPresetGeometries; import org.apache.poi.sl.draw.geom.TestPresetGeometries;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.StrokeStyle.LineCap; import org.apache.poi.sl.usermodel.StrokeStyle.LineCap;
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;

View File

@ -21,7 +21,7 @@ import static org.junit.Assert.assertNull;
import java.io.IOException; import java.io.IOException;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
import org.junit.Test; import org.junit.Test;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;

View File

@ -31,7 +31,7 @@ import java.util.List;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.usermodel.HSLFTextShape; import org.apache.poi.hslf.usermodel.HSLFTextShape;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.SlideShow; import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.SlideShowFactory; import org.apache.poi.sl.usermodel.SlideShowFactory;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;

View File

@ -122,7 +122,7 @@ public final class PPTXMLDump {
pos += LittleEndian.INT_SIZE; pos += LittleEndian.INT_SIZE;
//get name of the record by type //get name of the record by type
String recname = RecordTypes.recordName(type); String recname = RecordTypes.forTypeID(type).name();
write(out, "<"+recname + " info=\""+info+"\" type=\""+type+"\" size=\""+size+"\" offset=\""+(pos-8)+"\"", padding); write(out, "<"+recname + " info=\""+info+"\" type=\""+type+"\" size=\""+size+"\" offset=\""+(pos-8)+"\"", padding);
if (hexHeader){ if (hexHeader){
out.write(" header=\""); out.write(" header=\"");

View File

@ -79,7 +79,7 @@ public final class SLWTListing {
for(int k=0; k<upTo; k++) { for(int k=0; k<upTo; k++) {
Record r = children[k]; Record r = children[k];
int typeID = (int)r.getRecordType(); int typeID = (int)r.getRecordType();
String typeName = RecordTypes.recordName(typeID); String typeName = RecordTypes.forTypeID(typeID).name();
System.out.println(" - " + typeID + " (" + typeName + ")"); System.out.println(" - " + typeID + " (" + typeName + ")");
} }
} }

View File

@ -167,7 +167,7 @@ public void walkTree(int depth, int startPos, int maxLen) throws IOException {
out.println(String.format(Locale.ROOT, fmt, "", pos, type, len)); out.println(String.format(Locale.ROOT, fmt, "", pos, type, len));
// See if we know about the type of it // See if we know about the type of it
String recordName = RecordTypes.recordName((int)type); String recordName = RecordTypes.forTypeID((short)type).name();
// Jump over header, and think about going on more // Jump over header, and think about going on more
pos += 8; pos += 8;
@ -293,7 +293,7 @@ public void walkTree(int depth, int startPos, int maxLen) throws IOException {
String fmt = ind+"At position %2$d ($2$04x): type is %3$d (%3$04x), len is %4$d (%4$04x)"; String fmt = ind+"At position %2$d ($2$04x): type is %3$d (%3$04x), len is %4$d (%4$04x)";
out.println(String.format(Locale.ROOT, fmt, "", pos, type, atomlen)); out.println(String.format(Locale.ROOT, fmt, "", pos, type, atomlen));
String typeName = RecordTypes.recordName((int)type); String typeName = RecordTypes.forTypeID((short)type).name();
out.println(String.format(Locale.ROOT, ind+"%2$s", "That's an Escher Record: ", typeName)); out.println(String.format(Locale.ROOT, ind+"%2$s", "That's an Escher Record: ", typeName));
// Record specific dumps // Record specific dumps

View File

@ -17,21 +17,17 @@
package org.apache.poi.hslf.model; package org.apache.poi.hslf.model;
import java.io.ByteArrayOutputStream;
import java.util.Iterator;
import org.apache.poi.ddf.AbstractEscherOptRecord; import org.apache.poi.ddf.AbstractEscherOptRecord;
import org.apache.poi.ddf.EscherClientDataRecord;
import org.apache.poi.ddf.EscherComplexProperty; import org.apache.poi.ddf.EscherComplexProperty;
import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherProperties; import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherSpRecord; import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.Document; import org.apache.poi.hslf.record.Document;
import org.apache.poi.hslf.record.ExControl; import org.apache.poi.hslf.record.ExControl;
import org.apache.poi.hslf.record.ExObjList; import org.apache.poi.hslf.record.ExObjList;
import org.apache.poi.hslf.record.OEShapeAtom; import org.apache.poi.hslf.record.ExObjRefAtom;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordTypes; import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.usermodel.HSLFPictureData; import org.apache.poi.hslf.usermodel.HSLFPictureData;
@ -41,7 +37,6 @@ import org.apache.poi.hslf.usermodel.HSLFSheet;
import org.apache.poi.hslf.usermodel.HSLFTextParagraph; import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;
/** /**
@ -92,20 +87,8 @@ public final class ActiveXShape extends HSLFPictureShape {
setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002); setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, -1); setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, -1);
EscherClientDataRecord cldata = new EscherClientDataRecord(); HSLFEscherClientDataRecord cldata = getClientData(true);
cldata.setOptions((short)0xF); cldata.addChild(new ExObjRefAtom());
_escherContainer.addChildRecord(cldata); // TODO unit test to prove getChildRecords().add is wrong
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; return _escherContainer;
} }
@ -116,22 +99,18 @@ public final class ActiveXShape extends HSLFPictureShape {
* @see org.apache.poi.hslf.usermodel.HSLFSlideShow#addMovie(String, int) * @see org.apache.poi.hslf.usermodel.HSLFSlideShow#addMovie(String, int)
* @param idx the index of the movie * @param idx the index of the movie
*/ */
public void setActiveXIndex(int idx){ public void setActiveXIndex(int idx) {
EscherContainerRecord spContainer = getSpContainer(); ExObjRefAtom oe = getClientDataRecord(RecordTypes.ExObjRefAtom.typeID);
for (Iterator<EscherRecord> it = spContainer.getChildIterator(); it.hasNext();) { if (oe == null) {
EscherRecord obj = it.next(); throw new HSLFException("OEShapeAtom for ActiveX doesn't exist");
if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
EscherClientDataRecord clientRecord = (EscherClientDataRecord)obj;
byte[] recdata = clientRecord.getRemainingData();
LittleEndian.putInt(recdata, 8, idx);
}
} }
oe.setExObjIdRef(idx);
} }
public int getControlIndex(){ public int getControlIndex(){
int idx = -1; int idx = -1;
OEShapeAtom oe = getClientDataRecord(RecordTypes.OEShapeAtom.typeID); ExObjRefAtom oe = getClientDataRecord(RecordTypes.ExObjRefAtom.typeID);
if(oe != null) idx = oe.getOptions(); if(oe != null) idx = oe.getExObjIdRef();
return idx; return idx;
} }

View File

@ -17,14 +17,24 @@
package org.apache.poi.hslf.model; package org.apache.poi.hslf.model;
import java.io.ByteArrayOutputStream;
import org.apache.poi.ddf.EscherClientDataRecord;
import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherProperties; import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.record.AnimationInfo;
import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.record.AnimationInfoAtom;
import org.apache.poi.hslf.usermodel.*; import org.apache.poi.hslf.record.ExMCIMovie;
import org.apache.poi.hslf.record.ExObjList;
import org.apache.poi.hslf.record.ExObjRefAtom;
import org.apache.poi.hslf.record.ExVideoContainer;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.InteractiveInfo;
import org.apache.poi.hslf.record.InteractiveInfoAtom;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.usermodel.HSLFPictureData;
import org.apache.poi.hslf.usermodel.HSLFPictureShape;
import org.apache.poi.hslf.usermodel.HSLFShape;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeContainer;
/** /**
@ -82,11 +92,7 @@ public final class MovieShape extends HSLFPictureShape {
setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x1000100); setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x1000100);
setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x10001); setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x10001);
EscherClientDataRecord cldata = new EscherClientDataRecord(); ExObjRefAtom oe = new ExObjRefAtom();
cldata.setOptions((short)0xF);
_escherContainer.addChildRecord(cldata);
OEShapeAtom oe = new OEShapeAtom();
InteractiveInfo info = new InteractiveInfo(); InteractiveInfo info = new InteractiveInfo();
InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom(); InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom();
infoAtom.setAction(InteractiveInfoAtom.ACTION_MEDIA); infoAtom.setAction(InteractiveInfoAtom.ACTION_MEDIA);
@ -96,16 +102,10 @@ public final class MovieShape extends HSLFPictureShape {
AnimationInfoAtom anAtom = an.getAnimationInfoAtom(); AnimationInfoAtom anAtom = an.getAnimationInfoAtom();
anAtom.setFlag(AnimationInfoAtom.Automatic, true); anAtom.setFlag(AnimationInfoAtom.Automatic, true);
//convert hslf into ddf HSLFEscherClientDataRecord cldata = getClientData(true);
ByteArrayOutputStream out = new ByteArrayOutputStream(); cldata.addChild(oe);
try { cldata.addChild(an);
oe.writeOut(out); cldata.addChild(info);
an.writeOut(out);
info.writeOut(out);
} catch(Exception e){
throw new HSLFException(e);
}
cldata.setRemainingData(out.toByteArray());
return _escherContainer; return _escherContainer;
} }
@ -117,8 +117,8 @@ public final class MovieShape extends HSLFPictureShape {
* @param idx the index of the movie * @param idx the index of the movie
*/ */
public void setMovieIndex(int idx){ public void setMovieIndex(int idx){
OEShapeAtom oe = getClientDataRecord(RecordTypes.OEShapeAtom.typeID); ExObjRefAtom oe = getClientDataRecord(RecordTypes.ExObjRefAtom.typeID);
oe.setOptions(idx); oe.setExObjIdRef(idx);
AnimationInfo an = getClientDataRecord(RecordTypes.AnimationInfo.typeID); AnimationInfo an = getClientDataRecord(RecordTypes.AnimationInfo.typeID);
if(an != null) { if(an != null) {
@ -135,7 +135,6 @@ public final class MovieShape extends HSLFPictureShape {
AnimationInfo an = getClientDataRecord(RecordTypes.AnimationInfo.typeID); AnimationInfo an = getClientDataRecord(RecordTypes.AnimationInfo.typeID);
if(an != null){ if(an != null){
an.getAnimationInfoAtom().setFlag(AnimationInfoAtom.Automatic, flag); an.getAnimationInfoAtom().setFlag(AnimationInfoAtom.Automatic, flag);
updateClientData();
} }
} }
@ -150,13 +149,16 @@ public final class MovieShape extends HSLFPictureShape {
/** /**
* @return UNC or local path to a video file * @return UNC or local path to a video file
*/ */
@SuppressWarnings("resource")
public String getPath(){ public String getPath(){
OEShapeAtom oe = getClientDataRecord(RecordTypes.OEShapeAtom.typeID); ExObjRefAtom oe = getClientDataRecord(RecordTypes.ExObjRefAtom.typeID);
int idx = oe.getOptions(); int idx = oe.getExObjIdRef();
HSLFSlideShow ppt = getSheet().getSlideShow(); HSLFSlideShow ppt = getSheet().getSlideShow();
ExObjList lst = (ExObjList)ppt.getDocumentRecord().findFirstOfType(RecordTypes.ExObjList.typeID); ExObjList lst = (ExObjList)ppt.getDocumentRecord().findFirstOfType(RecordTypes.ExObjList.typeID);
if(lst == null) return null; if(lst == null) {
return null;
}
Record[] r = lst.getChildRecords(); Record[] r = lst.getChildRecords();
for (int i = 0; i < r.length; i++) { for (int i = 0; i < r.length; i++) {

View File

@ -17,14 +17,22 @@
package org.apache.poi.hslf.model; package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*; import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.hslf.usermodel.*; import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.hslf.record.ExObjList; import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.ExEmbed; import org.apache.poi.hslf.record.ExEmbed;
import org.apache.poi.hslf.record.ExObjList;
import org.apache.poi.hslf.record.ExObjRefAtom;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordTypes; import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.usermodel.HSLFObjectData;
import org.apache.poi.hslf.usermodel.HSLFPictureData;
import org.apache.poi.hslf.usermodel.HSLFPictureShape;
import org.apache.poi.hslf.usermodel.HSLFShape;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
@ -88,26 +96,19 @@ public final class OLEShape extends HSLFPictureShape {
EscherSpRecord spRecord = ecr.getChildById(EscherSpRecord.RECORD_ID); EscherSpRecord spRecord = ecr.getChildById(EscherSpRecord.RECORD_ID);
spRecord.setFlags(spRecord.getFlags()|EscherSpRecord.FLAG_OLESHAPE); spRecord.setFlags(spRecord.getFlags()|EscherSpRecord.FLAG_OLESHAPE);
EscherContainerRecord uerCont = ecr.getChildById((short)RecordTypes.EscherClientData); HSLFEscherClientDataRecord cldata = getClientData(true);
if (uerCont == null) { ExObjRefAtom uer = null;
uerCont = new EscherContainerRecord(); for (Record r : cldata.getHSLFChildRecords()) {
ecr.addChildRecord(uerCont); if (r.getRecordType() == RecordTypes.ExObjRefAtom.typeID) {
uer = (ExObjRefAtom)r;
break;
}
} }
uerCont.setRecordId((short)RecordTypes.EscherClientData);
uerCont.setVersion((short)0x000F); // yes, we are still a container ...
UnknownEscherRecord uer = uerCont.getChildById((short)RecordTypes.ExObjRefAtom.typeID);
if (uer == null) { if (uer == null) {
uer = new UnknownEscherRecord(); uer = new ExObjRefAtom();
uerCont.addChildRecord(uer); cldata.addChild(uer);
} }
uer.setExObjIdRef(objectId);
byte uerData[] = new byte[12];
LittleEndian.putShort( uerData, 0, (short)0 ); // options = 0
LittleEndian.putShort( uerData, 2, (short)RecordTypes.ExObjRefAtom.typeID); // recordId
LittleEndian.putInt( uerData, 4, 4 ); // remaining bytes
LittleEndian.putInt( uerData, 8, objectId ); // the data
uer.fillFields(uerData, 0, null);
} }
@ -116,6 +117,7 @@ public final class OLEShape extends HSLFPictureShape {
* *
* @return the unique identifier for the OLE object * @return the unique identifier for the OLE object
*/ */
@SuppressWarnings("resource")
public HSLFObjectData getObjectData(){ public HSLFObjectData getObjectData(){
HSLFSlideShow ppt = getSheet().getSlideShow(); HSLFSlideShow ppt = getSheet().getSlideShow();
HSLFObjectData[] ole = ppt.getEmbeddedObjects(); HSLFObjectData[] ole = ppt.getEmbeddedObjects();
@ -153,6 +155,7 @@ public final class OLEShape extends HSLFPictureShape {
* 6. MetaFile( 4033), optional * 6. MetaFile( 4033), optional
* </p> * </p>
*/ */
@SuppressWarnings("resource")
public ExEmbed getExEmbed(){ public ExEmbed getExEmbed(){
if(_exEmbed == null){ if(_exEmbed == null){
HSLFSlideShow ppt = getSheet().getSlideShow(); HSLFSlideShow ppt = getSheet().getSlideShow();

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 org.apache.poi.util.LittleEndian;
import java.io.IOException;
import java.io.OutputStream;
/**
* ExObjRefAtom (3009).
* <p>
* An atom record that specifies a reference to an external object.
* </p>
*/
public final class ExObjRefAtom extends RecordAtom {
private byte[] _header;
/**
* A 4-byte unsigned integer that specifies a reference to an external object.
* It MUST be equal to the value of the exObjId field of an ExMediaAtom record
* or the value of the exObjId field of an ExOleObjAtom record.
*/
private int exObjIdRef;
/**
* Create a new instance of <code>ExObjRefAtom</code>
*/
public ExObjRefAtom() {
_header = new byte[8];
LittleEndian.putUShort(_header, 0, 0);
LittleEndian.putUShort(_header, 2, (int)getRecordType());
LittleEndian.putInt(_header, 4, 4);
exObjIdRef = 0;
}
/**
* Build an instance of <code>ExObjRefAtom</code> from on-disk 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 ExObjRefAtom(byte[] source, int start, int len) {
_header = new byte[8];
int offset = start;
System.arraycopy(source,start,_header,0,8);
offset += _header.length;
exObjIdRef = (int)LittleEndian.getUInt(source, offset);
}
/**
* @return type of this record {@link RecordTypes#ExObjRefAtom}.
*/
public long getRecordType() {
return RecordTypes.ExObjRefAtom.typeID;
}
public int getExObjIdRef(){
return exObjIdRef;
}
public void setExObjIdRef(int id){
exObjIdRef = id;
}
/**
* Write the contents of the record back, so it can be written
* to disk
*/
public void writeOut(OutputStream out) throws IOException {
out.write(_header);
byte[] recdata = new byte[4];
LittleEndian.putUInt(recdata, 0, exObjIdRef);
out.write(recdata);
}
}

View File

@ -0,0 +1,120 @@
/* ====================================================================
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.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.ddf.EscherClientDataRecord;
import org.apache.poi.ddf.EscherRecordFactory;
import org.apache.poi.ddf.EscherSerializationListener;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.util.LittleEndian;
/**
* An atom record that specifies whether a shape is a placeholder shape.
* The number, position, and type of placeholder shapes are determined by
* the slide layout as specified in the SlideAtom record.
*
* @since POI 3.14-Beta2
*/
public class HSLFEscherClientDataRecord extends EscherClientDataRecord {
private final List<Record> _childRecords = new ArrayList<Record>();
public List<? extends Record> getHSLFChildRecords() {
return _childRecords;
}
public void removeChild(Class<? extends Record> childClass) {
Iterator<Record> iter = _childRecords.iterator();
while (iter.hasNext()) {
if (childClass.isInstance(iter.next())) {
iter.remove();
}
}
}
public void addChild(Record childRecord) {
_childRecords.add(childRecord);
}
@Override
public int fillFields(byte[] data, int offset, EscherRecordFactory recordFactory) {
int bytesRemaining = readHeader( data, offset );
byte remainingData[] = new byte[bytesRemaining];
System.arraycopy(data, offset+8, remainingData, 0, bytesRemaining);
setRemainingData(remainingData);
return bytesRemaining + 8;
}
@Override
public int serialize(int offset, byte[] data, EscherSerializationListener listener) {
listener.beforeRecordSerialize( offset, getRecordId(), this );
LittleEndian.putShort(data, offset, getOptions());
LittleEndian.putShort(data, offset+2, getRecordId());
byte childBytes[] = getRemainingData();
LittleEndian.putInt(data, offset+4, childBytes.length);
System.arraycopy(childBytes, 0, data, offset+8, childBytes.length);
int recordSize = 8+childBytes.length;
listener.afterRecordSerialize( offset+recordSize, getRecordId(), recordSize, this );
return recordSize;
}
@Override
public int getRecordSize() {
return 8 + getRemainingData().length;
}
@Override
public byte[] getRemainingData() {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
for (Record r : _childRecords) {
r.writeOut(bos);
}
} catch (IOException e) {
throw new HSLFException(e);
}
return bos.toByteArray();
}
@Override
public void setRemainingData( byte[] remainingData ) {
_childRecords.clear();
int offset = 0;
while (offset < remainingData.length) {
Record r = Record.buildRecordAtOffset(remainingData, offset);
_childRecords.add(r);
long rlen = LittleEndian.getUInt(remainingData,offset+4);
offset += 8 + rlen;
}
}
public String getRecordName() {
return "HSLFClientData";
}
}

View File

@ -29,7 +29,7 @@ import org.apache.poi.util.LittleEndian;
* @see EscherRecordFactory * @see EscherRecordFactory
*/ */
public class HSLFEscherRecordFactory extends DefaultEscherRecordFactory { public class HSLFEscherRecordFactory extends DefaultEscherRecordFactory {
private static Class<?>[] escherRecordClasses = { EscherPlaceholder.class }; private static Class<?>[] escherRecordClasses = { EscherPlaceholder.class, HSLFEscherClientDataRecord.class };
private static Map<Short, Constructor<? extends EscherRecord>> recordsMap = recordsToMap( escherRecordClasses ); private static Map<Short, Constructor<? extends EscherRecord>> recordsMap = recordsToMap( escherRecordClasses );
@ -65,6 +65,10 @@ public class HSLFEscherRecordFactory extends DefaultEscherRecordFactory {
} }
escherRecord.setRecordId(recordId); escherRecord.setRecordId(recordId);
escherRecord.setOptions(options); escherRecord.setOptions(options);
if (escherRecord instanceof EscherContainerRecord) {
((EscherContainerRecord)escherRecord).fillFields(data, offset, this);
}
return escherRecord; return escherRecord;
} }
} }

View File

@ -201,6 +201,7 @@ public final class OEPlaceholderAtom extends RecordAtom{
private int placementId; private int placementId;
private int placeholderId; private int placeholderId;
private int placeholderSize; private int placeholderSize;
private short unusedShort = 0;
/** /**
@ -227,8 +228,9 @@ public final class OEPlaceholderAtom extends RecordAtom{
offset += _header.length; offset += _header.length;
placementId = LittleEndian.getInt(source, offset); offset += 4; placementId = LittleEndian.getInt(source, offset); offset += 4;
placeholderId = LittleEndian.getUnsignedByte(source, offset); offset++; placeholderId = LittleEndian.getUByte(source, offset); offset++;
placeholderSize = LittleEndian.getUnsignedByte(source, offset); offset++; placeholderSize = LittleEndian.getUByte(source, offset); offset++;
unusedShort = LittleEndian.getShort(source, offset);
} }
/** /**
@ -322,6 +324,7 @@ public final class OEPlaceholderAtom extends RecordAtom{
LittleEndian.putInt(recdata, 0, placementId); LittleEndian.putInt(recdata, 0, placementId);
recdata[4] = (byte)placeholderId; recdata[4] = (byte)placeholderId;
recdata[5] = (byte)placeholderSize; recdata[5] = (byte)placeholderSize;
LittleEndian.putShort(recdata, 6, unusedShort);
out.write(recdata); out.write(recdata);
} }

View File

@ -1,107 +0,0 @@
/* ====================================================================
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;
/**
* Atom that contains information that describes shape client data.
*
* @author Yegor Kozlov
*/
public final 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

@ -20,7 +20,6 @@ package org.apache.poi.hslf.record;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -36,7 +35,6 @@ import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherSpRecord; import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.ddf.EscherSpgrRecord; import org.apache.poi.ddf.EscherSpgrRecord;
import org.apache.poi.ddf.EscherTextboxRecord; import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.ddf.UnknownEscherRecord;
import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
@ -57,7 +55,7 @@ public final class PPDrawing extends RecordAtom {
private byte[] _header; private byte[] _header;
private long _type; private long _type;
private EscherRecord[] childRecords; private final List<EscherRecord> childRecords = new ArrayList<EscherRecord>();
private EscherTextboxWrapper[] textboxWrappers; private EscherTextboxWrapper[] textboxWrappers;
//cached EscherDgRecord //cached EscherDgRecord
@ -66,7 +64,7 @@ public final class PPDrawing extends RecordAtom {
/** /**
* Get access to the underlying Escher Records * Get access to the underlying Escher Records
*/ */
public EscherRecord[] getEscherRecords() { return childRecords; } public List<EscherRecord> getEscherRecords() { return childRecords; }
/** /**
* Get access to the atoms inside Textboxes * Get access to the atoms inside Textboxes
@ -76,6 +74,20 @@ public final class PPDrawing extends RecordAtom {
/* ******************** record stuff follows ********************** */ /* ******************** record stuff follows ********************** */
/**
* Creates a new, empty, PPDrawing (typically for use with a new Slide
* or Notes)
*/
public PPDrawing() {
_header = new byte[8];
LittleEndian.putUShort(_header, 0, 15);
LittleEndian.putUShort(_header, 2, RecordTypes.PPDrawing.typeID);
LittleEndian.putInt(_header, 4, 0);
textboxWrappers = new EscherTextboxWrapper[]{};
create();
}
/** /**
* Sets everything up, groks the escher etc * Sets everything up, groks the escher etc
*/ */
@ -93,12 +105,11 @@ public final class PPDrawing extends RecordAtom {
// Build up a tree of Escher records contained within // Build up a tree of Escher records contained within
final DefaultEscherRecordFactory erf = new HSLFEscherRecordFactory(); final DefaultEscherRecordFactory erf = new HSLFEscherRecordFactory();
final List<EscherRecord> escherChildren = new ArrayList<EscherRecord>(); findEscherChildren(erf, contents, 8, len-8, childRecords);
findEscherChildren(erf, contents, 8, len-8, escherChildren); EscherContainerRecord dgContainer = getDgContainer();
this.childRecords = escherChildren.toArray(new EscherRecord[escherChildren.size()]);
if (1 == this.childRecords.length && (short)RecordTypes.EscherDgContainer == this.childRecords[0].getRecordId() && this.childRecords[0] instanceof EscherContainerRecord) { if (dgContainer != null) {
this.textboxWrappers = findInDgContainer((EscherContainerRecord) this.childRecords[0]); textboxWrappers = findInDgContainer(dgContainer);
} else { } else {
// Find and EscherTextboxRecord's, and wrap them up // Find and EscherTextboxRecord's, and wrap them up
final List<EscherTextboxWrapper> textboxes = new ArrayList<EscherTextboxWrapper>(); final List<EscherTextboxWrapper> textboxes = new ArrayList<EscherTextboxWrapper>();
@ -108,15 +119,15 @@ public final class PPDrawing extends RecordAtom {
} }
private EscherTextboxWrapper[] findInDgContainer(final EscherContainerRecord dgContainer) { private EscherTextboxWrapper[] findInDgContainer(final EscherContainerRecord dgContainer) {
final List<EscherTextboxWrapper> found = new LinkedList<EscherTextboxWrapper>(); final List<EscherTextboxWrapper> found = new LinkedList<EscherTextboxWrapper>();
final EscherContainerRecord spgrContainer = findFirstEscherContainerRecordOfType((short)RecordTypes.EscherSpgrContainer, dgContainer); final EscherContainerRecord spgrContainer = findFirstEscherContainerRecordOfType(RecordTypes.EscherSpgrContainer, dgContainer);
final EscherContainerRecord[] spContainers = findAllEscherContainerRecordOfType((short)RecordTypes.EscherSpContainer, spgrContainer); final EscherContainerRecord[] spContainers = findAllEscherContainerRecordOfType(RecordTypes.EscherSpContainer, spgrContainer);
for (EscherContainerRecord spContainer : spContainers) { for (EscherContainerRecord spContainer : spContainers) {
StyleTextProp9Atom nineAtom = findInSpContainer(spContainer); EscherSpRecord sp = (EscherSpRecord)findFirstEscherRecordOfType(RecordTypes.EscherSp, spContainer);
EscherSpRecord sp = (EscherSpRecord)findFirstEscherRecordOfType((short)RecordTypes.EscherSp, spContainer); EscherTextboxRecord clientTextbox = (EscherTextboxRecord)findFirstEscherRecordOfType(RecordTypes.EscherClientTextbox, spContainer);
EscherTextboxRecord clientTextbox = (EscherTextboxRecord)findFirstEscherRecordOfType((short)RecordTypes.EscherClientTextbox, spContainer);
if (null == clientTextbox) { continue; } if (null == clientTextbox) { continue; }
EscherTextboxWrapper w = new EscherTextboxWrapper(clientTextbox); EscherTextboxWrapper w = new EscherTextboxWrapper(clientTextbox);
StyleTextProp9Atom nineAtom = findInSpContainer(spContainer);
w.setStyleTextProp9Atom(nineAtom); w.setStyleTextProp9Atom(nineAtom);
if (null != sp) { if (null != sp) {
w.setShapeId(sp.getShapeId()); w.setShapeId(sp.getShapeId());
@ -127,16 +138,26 @@ public final class PPDrawing extends RecordAtom {
} }
private StyleTextProp9Atom findInSpContainer(final EscherContainerRecord spContainer) { private StyleTextProp9Atom findInSpContainer(final EscherContainerRecord spContainer) {
EscherContainerRecord clientData = findFirstEscherContainerRecordOfType((short)RecordTypes.EscherClientData, spContainer); HSLFEscherClientDataRecord cldata = spContainer.getChildById(RecordTypes.EscherClientData.typeID);
if (null == clientData) { return null; } if (cldata == null) {
final EscherContainerRecord progTagsContainer = findFirstEscherContainerRecordOfType((short)0x1388, clientData); return null;
if (null == progTagsContainer) { return null; } }
final EscherContainerRecord progBinaryTag = findFirstEscherContainerRecordOfType((short)0x138A, progTagsContainer); DummyPositionSensitiveRecordWithChildren progTags =
if (null == progBinaryTag) { return null; } getChildRecord(cldata.getHSLFChildRecords(), RecordTypes.ProgTags);
int size = progBinaryTag.getChildRecords().size(); if (progTags == null) {
return null;
}
DummyPositionSensitiveRecordWithChildren progBinaryTag =
(DummyPositionSensitiveRecordWithChildren)progTags.findFirstOfType(RecordTypes.ProgBinaryTag.typeID);
if (progBinaryTag == null) {
return null;
}
int size = progBinaryTag.getChildRecords().length;
if (2 != size) { return null; } if (2 != size) { return null; }
final Record r0 = buildFromUnknownEscherRecord((UnknownEscherRecord) progBinaryTag.getChild(0));
final Record r1 = buildFromUnknownEscherRecord((UnknownEscherRecord) progBinaryTag.getChild(1)); final Record r0 = progBinaryTag.getChildRecords()[0];
final Record r1 = progBinaryTag.getChildRecords()[1];
if (!(r0 instanceof CString)) { return null; } if (!(r0 instanceof CString)) { return null; }
if (!("___PPT9".equals(((CString) r0).getText()))) { return null; }; if (!("___PPT9".equals(((CString) r0).getText()))) { return null; };
if (!(r1 instanceof BinaryTagDataBlob )) { return null; } if (!(r1 instanceof BinaryTagDataBlob )) { return null; }
@ -144,19 +165,6 @@ public final class PPDrawing extends RecordAtom {
if (1 != blob.getChildRecords().length) { return null; } if (1 != blob.getChildRecords().length) { return null; }
return (StyleTextProp9Atom) blob.findFirstOfType(RecordTypes.StyleTextProp9Atom.typeID); return (StyleTextProp9Atom) blob.findFirstOfType(RecordTypes.StyleTextProp9Atom.typeID);
} }
/**
* Creates a new, empty, PPDrawing (typically for use with a new Slide
* or Notes)
*/
public PPDrawing(){
_header = new byte[8];
LittleEndian.putUShort(_header, 0, 15);
LittleEndian.putUShort(_header, 2, RecordTypes.PPDrawing.typeID);
LittleEndian.putInt(_header, 4, 0);
textboxWrappers = new EscherTextboxWrapper[]{};
create();
}
/** /**
* Tree walking way of finding Escher Child Records * Tree walking way of finding Escher Child Records
@ -198,30 +206,25 @@ public final class PPDrawing extends RecordAtom {
/** /**
* Look for EscherTextboxRecords * Look for EscherTextboxRecords
*/ */
private void findEscherTextboxRecord(EscherRecord[] toSearch, List<EscherTextboxWrapper> found) { private void findEscherTextboxRecord(List<EscherRecord> toSearch, List<EscherTextboxWrapper> found) {
for(int i=0; i<toSearch.length; i++) { EscherSpRecord sp = null;
if(toSearch[i] instanceof EscherTextboxRecord) { for (EscherRecord r : toSearch) {
EscherTextboxRecord tbr = (EscherTextboxRecord)toSearch[i]; if (r instanceof EscherSpRecord) {
sp = (EscherSpRecord)r;
} else if (r instanceof EscherTextboxRecord) {
EscherTextboxRecord tbr = (EscherTextboxRecord)r;
EscherTextboxWrapper w = new EscherTextboxWrapper(tbr); EscherTextboxWrapper w = new EscherTextboxWrapper(tbr);
found.add(w); if (sp != null) {
for (int j = i; j >= 0; j--) {
if(toSearch[j] instanceof EscherSpRecord){
EscherSpRecord sp = (EscherSpRecord)toSearch[j];
w.setShapeId(sp.getShapeId()); w.setShapeId(sp.getShapeId());
break;
} }
} found.add(w);
} else { } else if (r.isContainerRecord()) {
// If it has children, walk them // If it has children, walk them
if(toSearch[i].isContainerRecord()) { List<EscherRecord> children = r.getChildRecords();
List<EscherRecord> childrenL = toSearch[i].getChildRecords();
EscherRecord[] children = new EscherRecord[childrenL.size()];
childrenL.toArray(children);
findEscherTextboxRecord(children,found); findEscherTextboxRecord(children,found);
} }
} }
} }
}
/** /**
* We are type 1036 * We are type 1036
@ -259,9 +262,8 @@ public final class PPDrawing extends RecordAtom {
// Now grab the children's data // Now grab the children's data
byte[] b = new byte[newSize]; byte[] b = new byte[newSize];
int done = 0; int done = 0;
for(int i=0; i<childRecords.length; i++) { for(EscherRecord r : childRecords) {
int written = childRecords[i].serialize( done, b ); done += r.serialize( done, b );
done += written;
} }
// Finally, write out the children // Finally, write out the children
@ -276,7 +278,7 @@ public final class PPDrawing extends RecordAtom {
dgContainer.setRecordId( EscherContainerRecord.DG_CONTAINER ); dgContainer.setRecordId( EscherContainerRecord.DG_CONTAINER );
dgContainer.setOptions((short)15); dgContainer.setOptions((short)15);
EscherDgRecord dg = new EscherDgRecord(); dg = new EscherDgRecord();
dg.setOptions((short)16); dg.setOptions((short)16);
dg.setNumShapes(1); dg.setNumShapes(1);
dgContainer.addChildRecord(dg); dgContainer.addChildRecord(dg);
@ -322,9 +324,7 @@ public final class PPDrawing extends RecordAtom {
dgContainer.addChildRecord(spContainer); dgContainer.addChildRecord(spContainer);
childRecords = new EscherRecord[]{ childRecords.add(dgContainer);
dgContainer
};
} }
/** /**
@ -338,6 +338,22 @@ public final class PPDrawing extends RecordAtom {
textboxWrappers = tw; textboxWrappers = tw;
} }
/**
* @return the container record for drawings
* @since POI 3.14-Beta2
*/
public EscherContainerRecord getDgContainer() {
if (childRecords.isEmpty()) {
return null;
}
EscherRecord r = childRecords.get(0);
if (r instanceof EscherContainerRecord && r.getRecordId() == RecordTypes.EscherDgContainer.typeID) {
return (EscherContainerRecord)r;
} else {
return null;
}
}
/** /**
* Return EscherDgRecord which keeps track of the number of shapes and shapeId in this drawing group * Return EscherDgRecord which keeps track of the number of shapes and shapeId in this drawing group
* *
@ -345,9 +361,7 @@ public final class PPDrawing extends RecordAtom {
*/ */
public EscherDgRecord getEscherDgRecord(){ public EscherDgRecord getEscherDgRecord(){
if(dg == null){ if(dg == null){
EscherContainerRecord dgContainer = (EscherContainerRecord)childRecords[0]; for(EscherRecord r : getDgContainer().getChildRecords()){
for(Iterator<EscherRecord> it = dgContainer.getChildIterator(); it.hasNext();){
EscherRecord r = it.next();
if(r instanceof EscherDgRecord){ if(r instanceof EscherDgRecord){
dg = (EscherDgRecord)r; dg = (EscherDgRecord)r;
break; break;
@ -357,59 +371,59 @@ public final class PPDrawing extends RecordAtom {
return dg; return dg;
} }
protected EscherContainerRecord findFirstEscherContainerRecordOfType(short type, EscherContainerRecord parent) { protected EscherContainerRecord findFirstEscherContainerRecordOfType(RecordTypes type, EscherContainerRecord parent) {
if (null == parent) { return null; } if (null == parent) { return null; }
final List<EscherContainerRecord> children = parent.getChildContainers(); final List<EscherContainerRecord> children = parent.getChildContainers();
for (EscherContainerRecord child : children) { for (EscherContainerRecord child : children) {
if (type == child.getRecordId()) { if (type.typeID == child.getRecordId()) {
return child; return child;
} }
} }
return null; return null;
} }
protected EscherRecord findFirstEscherRecordOfType(short type, EscherContainerRecord parent) { protected EscherRecord findFirstEscherRecordOfType(RecordTypes type, EscherContainerRecord parent) {
if (null == parent) { return null; } if (null == parent) { return null; }
final List<EscherRecord> children = parent.getChildRecords(); final List<EscherRecord> children = parent.getChildRecords();
for (EscherRecord child : children) { for (EscherRecord child : children) {
if (type == child.getRecordId()) { if (type.typeID == child.getRecordId()) {
return child; return child;
} }
} }
return null; return null;
} }
protected EscherContainerRecord[] findAllEscherContainerRecordOfType(short type, EscherContainerRecord parent) { protected EscherContainerRecord[] findAllEscherContainerRecordOfType(RecordTypes type, EscherContainerRecord parent) {
if (null == parent) { return new EscherContainerRecord[0]; } if (null == parent) { return new EscherContainerRecord[0]; }
final List<EscherContainerRecord> children = parent.getChildContainers(); final List<EscherContainerRecord> children = parent.getChildContainers();
final List<EscherContainerRecord> result = new LinkedList<EscherContainerRecord>(); final List<EscherContainerRecord> result = new LinkedList<EscherContainerRecord>();
for (EscherContainerRecord child : children) { for (EscherContainerRecord child : children) {
if (type == child.getRecordId()) { if (type.typeID == child.getRecordId()) {
result.add(child); result.add(child);
} }
} }
return result.toArray(new EscherContainerRecord[result.size()]); return result.toArray(new EscherContainerRecord[result.size()]);
} }
protected Record buildFromUnknownEscherRecord(UnknownEscherRecord unknown) {
byte[] bingo = unknown.getData();
byte[] restoredRecord = new byte[8 + bingo.length];
System.arraycopy(bingo, 0, restoredRecord, 8, bingo.length);
short recordVersion = unknown.getVersion();
short recordId = unknown.getRecordId();
int recordLength = unknown.getRecordSize();
LittleEndian.putShort(restoredRecord, 0, recordVersion);
LittleEndian.putShort(restoredRecord, 2, recordId);
LittleEndian.putInt(restoredRecord, 4, recordLength);
return Record.createRecordForType(recordId, restoredRecord, 0, restoredRecord.length);
}
public StyleTextProp9Atom[] getNumberedListInfo() { public StyleTextProp9Atom[] getNumberedListInfo() {
final List<StyleTextProp9Atom> result = new LinkedList<StyleTextProp9Atom>(); final List<StyleTextProp9Atom> result = new LinkedList<StyleTextProp9Atom>();
EscherContainerRecord dgContainer = (EscherContainerRecord)childRecords[0]; EscherContainerRecord dgContainer = getDgContainer();
final EscherContainerRecord spgrContainer = findFirstEscherContainerRecordOfType((short)RecordTypes.EscherSpgrContainer, dgContainer); final EscherContainerRecord spgrContainer = findFirstEscherContainerRecordOfType(RecordTypes.EscherSpgrContainer, dgContainer);
final EscherContainerRecord[] spContainers = findAllEscherContainerRecordOfType((short)RecordTypes.EscherSpContainer, spgrContainer); final EscherContainerRecord[] spContainers = findAllEscherContainerRecordOfType(RecordTypes.EscherSpContainer, spgrContainer);
for (EscherContainerRecord spContainer : spContainers) { for (EscherContainerRecord spContainer : spContainers) {
StyleTextProp9Atom prop9 = findInSpContainer(spContainer); StyleTextProp9Atom prop9 = findInSpContainer(spContainer);
if (prop9 != null) result.add(prop9); if (prop9 != null) {
result.add(prop9);
}
} }
return result.toArray(new StyleTextProp9Atom[result.size()]); return result.toArray(new StyleTextProp9Atom[result.size()]);
} }
@SuppressWarnings("unchecked")
private static <T extends Record> T getChildRecord(List<? extends Record> children, RecordTypes type) {
for (Record r : children) {
if (r.getRecordType() == type.typeID) {
return (T)r;
}
}
return null;
}
} }

View File

@ -166,19 +166,19 @@ public abstract class Record
// Any special record handling occurs once we have the class // Any special record handling occurs once we have the class
Class<? extends Record> c = null; Class<? extends Record> c = null;
try { try {
c = RecordTypes.recordHandlingClass((int)type); c = RecordTypes.forTypeID((short)type).handlingClass;
if(c == null) { if(c == null) {
// How odd. RecordTypes normally subsitutes in // How odd. RecordTypes normally subsitutes in
// a default handler class if it has heard of the record // a default handler class if it has heard of the record
// type but there's no support for it. Explicitly request // type but there's no support for it. Explicitly request
// that now // that now
c = RecordTypes.recordHandlingClass( RecordTypes.Unknown.typeID ); c = RecordTypes.UnknownRecordPlaceholder.handlingClass;
} }
// Grab the right constructor // Grab the right constructor
java.lang.reflect.Constructor<? extends Record> con = c.getDeclaredConstructor(new Class[] { byte[].class, Integer.TYPE, Integer.TYPE }); java.lang.reflect.Constructor<? extends Record> con = c.getDeclaredConstructor(new Class[] { byte[].class, Integer.TYPE, Integer.TYPE });
// Instantiate // Instantiate
toReturn = con.newInstance(new Object[] { b, Integer.valueOf(start), Integer.valueOf(len) }); toReturn = con.newInstance(new Object[] { b, start, len });
} catch(InstantiationException ie) { } catch(InstantiationException ie) {
throw new RuntimeException("Couldn't instantiate the class for type with id " + type + " on class " + c + " : " + ie, ie); throw new RuntimeException("Couldn't instantiate the class for type with id " + type + " on class " + c + " : " + ie, ie);
} catch(java.lang.reflect.InvocationTargetException ite) { } catch(java.lang.reflect.InvocationTargetException ite) {

View File

@ -17,8 +17,8 @@
package org.apache.poi.hslf.record; package org.apache.poi.hslf.record;
import java.lang.reflect.Field;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
/** /**
* List of all known record types in a PowerPoint document, and the * List of all known record types in a PowerPoint document, and the
@ -26,191 +26,209 @@ import java.util.HashMap;
* There are two categories of records: * There are two categories of records:
* <li> PowerPoint records: 0 <= info <= 10002 (will carry class info) * <li> PowerPoint records: 0 <= info <= 10002 (will carry class info)
* <li> Escher records: info >= 0xF000 (handled by DDF, so no class info) * <li> Escher records: info >= 0xF000 (handled by DDF, so no class info)
*
* @author Yegor Kozlov
* @author Nick Burch
*/ */
public final class RecordTypes { public enum RecordTypes {
public static final HashMap<Integer,String> typeToName; Unknown(0,null),
public static final HashMap<Integer,Class<? extends Record>> typeToClass; UnknownRecordPlaceholder(-1, UnknownRecordPlaceholder.class),
Document(1000,Document.class),
public static final Type Unknown = new Type(0,null); DocumentAtom(1001,DocumentAtom.class),
public static final Type Document = new Type(1000,Document.class); EndDocument(1002,null),
public static final Type DocumentAtom = new Type(1001,DocumentAtom.class); Slide(1006,Slide.class),
public static final Type EndDocument = new Type(1002,null); SlideAtom(1007,SlideAtom.class),
public static final Type Slide = new Type(1006,Slide.class); Notes(1008,Notes.class),
public static final Type SlideAtom = new Type(1007,SlideAtom.class); NotesAtom(1009,NotesAtom.class),
public static final Type Notes = new Type(1008,Notes.class); Environment(1010,Environment.class),
public static final Type NotesAtom = new Type(1009,NotesAtom.class); SlidePersistAtom(1011,SlidePersistAtom.class),
public static final Type Environment = new Type(1010,Environment.class); SSlideLayoutAtom(1015,null),
public static final Type SlidePersistAtom = new Type(1011,SlidePersistAtom.class); MainMaster(1016,MainMaster.class),
public static final Type SSlideLayoutAtom = new Type(1015,null); SSSlideInfoAtom(1017,SSSlideInfoAtom.class),
public static final Type MainMaster = new Type(1016,MainMaster.class); SlideViewInfo(1018,null),
public static final Type SSSlideInfoAtom = new Type(1017,SSSlideInfoAtom.class); GuideAtom(1019,null),
public static final Type SlideViewInfo = new Type(1018,null); ViewInfo(1020,null),
public static final Type GuideAtom = new Type(1019,null); ViewInfoAtom(1021,null),
public static final Type ViewInfo = new Type(1020,null); SlideViewInfoAtom(1022,null),
public static final Type ViewInfoAtom = new Type(1021,null); VBAInfo(1023,null),
public static final Type SlideViewInfoAtom = new Type(1022,null); VBAInfoAtom(1024,null),
public static final Type VBAInfo = new Type(1023,null); SSDocInfoAtom(1025,null),
public static final Type VBAInfoAtom = new Type(1024,null); Summary(1026,null),
public static final Type SSDocInfoAtom = new Type(1025,null); DocRoutingSlip(1030,null),
public static final Type Summary = new Type(1026,null); OutlineViewInfo(1031,null),
public static final Type DocRoutingSlip = new Type(1030,null); SorterViewInfo(1032,null),
public static final Type OutlineViewInfo = new Type(1031,null); ExObjList(1033,ExObjList.class),
public static final Type SorterViewInfo = new Type(1032,null); ExObjListAtom(1034,ExObjListAtom.class),
public static final Type ExObjList = new Type(1033,ExObjList.class); PPDrawingGroup(1035,PPDrawingGroup.class),
public static final Type ExObjListAtom = new Type(1034,ExObjListAtom.class); PPDrawing(1036,PPDrawing.class),
public static final Type PPDrawingGroup = new Type(1035,PPDrawingGroup.class); NamedShows(1040,null),
public static final Type PPDrawing = new Type(1036,PPDrawing.class); NamedShow(1041,null),
public static final Type NamedShows = new Type(1040,null); NamedShowSlides(1042,null),
public static final Type NamedShow = new Type(1041,null); SheetProperties(1044,null),
public static final Type NamedShowSlides = new Type(1042,null); RoundTripCustomTableStyles12Atom(1064,null),
public static final Type SheetProperties = new Type(1044,null); List(2000,null),
public static final Type RoundTripCustomTableStyles12Atom = new Type(1064,null); FontCollection(2005,FontCollection.class),
public static final Type List = new Type(2000,null); BookmarkCollection(2019,null),
public static final Type FontCollection = new Type(2005,FontCollection.class); SoundCollection(2020,SoundCollection.class),
public static final Type BookmarkCollection = new Type(2019,null); SoundCollAtom(2021,null),
public static final Type SoundCollection = new Type(2020,SoundCollection.class); Sound(2022,Sound.class),
public static final Type SoundCollAtom = new Type(2021,null); SoundData(2023,SoundData.class),
public static final Type Sound = new Type(2022,Sound.class); BookmarkSeedAtom(2025,null),
public static final Type SoundData = new Type(2023,SoundData.class); ColorSchemeAtom(2032,ColorSchemeAtom.class),
public static final Type BookmarkSeedAtom = new Type(2025,null); ExObjRefAtom(3009,ExObjRefAtom.class),
public static final Type ColorSchemeAtom = new Type(2032,ColorSchemeAtom.class); OEPlaceholderAtom(3011,OEPlaceholderAtom.class),
public static final Type ExObjRefAtom = new Type(3009,null); GPopublicintAtom(3024,null),
public static final Type OEShapeAtom = new Type(3009,OEShapeAtom.class); GRatioAtom(3031,null),
public static final Type OEPlaceholderAtom = new Type(3011,OEPlaceholderAtom.class); OutlineTextRefAtom(3998,OutlineTextRefAtom.class),
public static final Type GPopublicintAtom = new Type(3024,null); TextHeaderAtom(3999,TextHeaderAtom.class),
public static final Type GRatioAtom = new Type(3031,null); TextCharsAtom(4000,TextCharsAtom.class),
public static final Type OutlineTextRefAtom = new Type(3998,OutlineTextRefAtom.class); StyleTextPropAtom(4001, StyleTextPropAtom.class),//0x0fa1 RT_StyleTextPropAtom
public static final Type TextHeaderAtom = new Type(3999,TextHeaderAtom.class); MasterTextPropAtom(4002, MasterTextPropAtom.class),
public static final Type TextCharsAtom = new Type(4000,TextCharsAtom.class); TxMasterStyleAtom(4003,TxMasterStyleAtom.class),
public static final Type StyleTextPropAtom = new Type(4001, StyleTextPropAtom.class);//0x0fa1 RT_StyleTextPropAtom TxCFStyleAtom(4004,null),
public static final Type MasterTextPropAtom = new Type(4002, MasterTextPropAtom.class); TxPFStyleAtom(4005,null),
public static final Type TxMasterStyleAtom = new Type(4003,TxMasterStyleAtom.class); TextRulerAtom(4006,TextRulerAtom.class),
public static final Type TxCFStyleAtom = new Type(4004,null); TextBookmarkAtom(4007,null),
public static final Type TxPFStyleAtom = new Type(4005,null); TextBytesAtom(4008,TextBytesAtom.class),
public static final Type TextRulerAtom = new Type(4006,TextRulerAtom.class); TxSIStyleAtom(4009,null),
public static final Type TextBookmarkAtom = new Type(4007,null); TextSpecInfoAtom(4010, TextSpecInfoAtom.class),
public static final Type TextBytesAtom = new Type(4008,TextBytesAtom.class); DefaultRulerAtom(4011,null),
public static final Type TxSIStyleAtom = new Type(4009,null); StyleTextProp9Atom(4012, StyleTextProp9Atom.class), //0x0FAC RT_StyleTextProp9Atom
public static final Type TextSpecInfoAtom = new Type(4010, TextSpecInfoAtom.class); FontEntityAtom(4023,FontEntityAtom.class),
public static final Type DefaultRulerAtom = new Type(4011,null); FontEmbeddedData(4024,null),
public static final Type StyleTextProp9Atom = new Type(4012, StyleTextProp9Atom.class); //0x0FAC RT_StyleTextProp9Atom CString(4026,CString.class),
public static final Type FontEntityAtom = new Type(4023,FontEntityAtom.class); MetaFile(4033,null),
public static final Type FontEmbeddedData = new Type(4024,null); ExOleObjAtom(4035,ExOleObjAtom.class),
public static final Type CString = new Type(4026,CString.class); SrKinsoku(4040,null),
public static final Type MetaFile = new Type(4033,null); HandOut(4041,DummyPositionSensitiveRecordWithChildren.class),
public static final Type ExOleObjAtom = new Type(4035,ExOleObjAtom.class); ExEmbed(4044,ExEmbed.class),
public static final Type SrKinsoku = new Type(4040,null); ExEmbedAtom(4045,ExEmbedAtom.class),
public static final Type HandOut = new Type(4041,DummyPositionSensitiveRecordWithChildren.class); ExLink(4046,null),
public static final Type ExEmbed = new Type(4044,ExEmbed.class); BookmarkEntityAtom(4048,null),
public static final Type ExEmbedAtom = new Type(4045,ExEmbedAtom.class); ExLinkAtom(4049,null),
public static final Type ExLink = new Type(4046,null); SrKinsokuAtom(4050,null),
public static final Type BookmarkEntityAtom = new Type(4048,null); ExHyperlinkAtom(4051,ExHyperlinkAtom.class),
public static final Type ExLinkAtom = new Type(4049,null); ExHyperlink(4055,ExHyperlink.class),
public static final Type SrKinsokuAtom = new Type(4050,null); SlideNumberMCAtom(4056,null),
public static final Type ExHyperlinkAtom = new Type(4051,ExHyperlinkAtom.class); HeadersFooters(4057,HeadersFootersContainer.class),
public static final Type ExHyperlink = new Type(4055,ExHyperlink.class); HeadersFootersAtom(4058,HeadersFootersAtom.class),
public static final Type SlideNumberMCAtom = new Type(4056,null); TxInteractiveInfoAtom(4063,TxInteractiveInfoAtom.class),
public static final Type HeadersFooters = new Type(4057,HeadersFootersContainer.class); CharFormatAtom(4066,null),
public static final Type HeadersFootersAtom = new Type(4058,HeadersFootersAtom.class); ParaFormatAtom(4067,null),
public static final Type TxInteractiveInfoAtom = new Type(4063,TxInteractiveInfoAtom.class); RecolorInfoAtom(4071,null),
public static final Type CharFormatAtom = new Type(4066,null); ExQuickTimeMovie(4074,null),
public static final Type ParaFormatAtom = new Type(4067,null); ExQuickTimeMovieData(4075,null),
public static final Type RecolorInfoAtom = new Type(4071,null); ExControl(4078,ExControl.class),
public static final Type ExQuickTimeMovie = new Type(4074,null); SlideListWithText(4080,SlideListWithText.class),
public static final Type ExQuickTimeMovieData = new Type(4075,null); InteractiveInfo(4082,InteractiveInfo.class),
public static final Type ExControl = new Type(4078,ExControl.class); InteractiveInfoAtom(4083,InteractiveInfoAtom.class),
public static final Type SlideListWithText = new Type(4080,SlideListWithText.class); UserEditAtom(4085,UserEditAtom.class),
public static final Type InteractiveInfo = new Type(4082,InteractiveInfo.class); CurrentUserAtom(4086,null),
public static final Type InteractiveInfoAtom = new Type(4083,InteractiveInfoAtom.class); DateTimeMCAtom(4087,null),
public static final Type UserEditAtom = new Type(4085,UserEditAtom.class); GenericDateMCAtom(4088,null),
public static final Type CurrentUserAtom = new Type(4086,null); FooterMCAtom(4090,null),
public static final Type DateTimeMCAtom = new Type(4087,null); ExControlAtom(4091,ExControlAtom.class),
public static final Type GenericDateMCAtom = new Type(4088,null); ExMediaAtom(4100,ExMediaAtom.class),
public static final Type FooterMCAtom = new Type(4090,null); ExVideoContainer(4101,ExVideoContainer.class),
public static final Type ExControlAtom = new Type(4091,ExControlAtom.class); ExAviMovie(4102,ExAviMovie.class),
public static final Type ExMediaAtom = new Type(4100,ExMediaAtom.class); ExMCIMovie(4103,ExMCIMovie.class),
public static final Type ExVideoContainer = new Type(4101,ExVideoContainer.class); ExMIDIAudio(4109,null),
public static final Type ExAviMovie = new Type(4102,ExAviMovie.class); ExCDAudio(4110,null),
public static final Type ExMCIMovie = new Type(4103,ExMCIMovie.class); ExWAVAudioEmbedded(4111,null),
public static final Type ExMIDIAudio = new Type(4109,null); ExWAVAudioLink(4112,null),
public static final Type ExCDAudio = new Type(4110,null); ExOleObjStg(4113,ExOleObjStg.class),
public static final Type ExWAVAudioEmbedded = new Type(4111,null); ExCDAudioAtom(4114,null),
public static final Type ExWAVAudioLink = new Type(4112,null); ExWAVAudioEmbeddedAtom(4115,null),
public static final Type ExOleObjStg = new Type(4113,ExOleObjStg.class); AnimationInfo(4116,AnimationInfo.class),
public static final Type ExCDAudioAtom = new Type(4114,null); AnimationInfoAtom(4081,AnimationInfoAtom.class),
public static final Type ExWAVAudioEmbeddedAtom = new Type(4115,null); RTFDateTimeMCAtom(4117,null),
public static final Type AnimationInfo = new Type(4116,AnimationInfo.class); ProgTags(5000,DummyPositionSensitiveRecordWithChildren.class),
public static final Type AnimationInfoAtom = new Type(4081,AnimationInfoAtom.class); ProgStringTag(5001,null),
public static final Type RTFDateTimeMCAtom = new Type(4117,null); ProgBinaryTag(5002,DummyPositionSensitiveRecordWithChildren.class),
public static final Type ProgTags = new Type(5000,DummyPositionSensitiveRecordWithChildren.class); BinaryTagData(5003, BinaryTagDataBlob.class),//0x138b RT_BinaryTagDataBlob
public static final Type ProgStringTag = new Type(5001,null); PrpublicintOptions(6000,null),
public static final Type ProgBinaryTag = new Type(5002,DummyPositionSensitiveRecordWithChildren.class); PersistPtrFullBlock(6001,PersistPtrHolder.class),
public static final Type BinaryTagData = new Type(5003, BinaryTagDataBlob.class);//0x138b RT_BinaryTagDataBlob PersistPtrIncrementalBlock(6002,PersistPtrHolder.class),
public static final Type PrpublicintOptions = new Type(6000,null); GScalingAtom(10001,null),
public static final Type PersistPtrFullBlock = new Type(6001,PersistPtrHolder.class); GRColorAtom(10002,null),
public static final Type PersistPtrIncrementalBlock = new Type(6002,PersistPtrHolder.class);
public static final Type GScalingAtom = new Type(10001,null);
public static final Type GRColorAtom = new Type(10002,null);
// Records ~12000 seem to be related to the Comments used in PPT 2000/XP // Records ~12000 seem to be related to the Comments used in PPT 2000/XP
// (Comments in PPT97 are normal Escher text boxes) // (Comments in PPT97 are normal Escher text boxes)
public static final Type Comment2000 = new Type(12000,Comment2000.class); Comment2000(12000,Comment2000.class),
public static final Type Comment2000Atom = new Type(12001,Comment2000Atom.class); Comment2000Atom(12001,Comment2000Atom.class),
public static final Type Comment2000Summary = new Type(12004,null); Comment2000Summary(12004,null),
public static final Type Comment2000SummaryAtom = new Type(12005,null); Comment2000SummaryAtom(12005,null),
// Records ~12050 seem to be related to Document Encryption // Records ~12050 seem to be related to Document Encryption
public static final Type DocumentEncryptionAtom = new Type(12052,DocumentEncryptionAtom.class); DocumentEncryptionAtom(12052,DocumentEncryptionAtom.class),
OriginalMainMasterId(1052,null),
CompositeMasterId(1052,null),
RoundTripContentMasterInfo12(1054,null),
RoundTripShapeId12(1055,null),
RoundTripHFPlaceholder12(1056,RoundTripHFPlaceholder12.class),
RoundTripContentMasterId(1058,null),
RoundTripOArtTextStyles12(1059,null),
RoundTripShapeCheckSumForCustomLayouts12(1062,null),
RoundTripNotesMasterTextStyles12(1063,null),
RoundTripCustomTableStyles12(1064,null),
// records greater then 0xF000 belong to with Microsoft Office Drawing format also known as Escher
EscherDggContainer(0xF000,null),
EscherDgg(0xf006,null),
EscherCLSID(0xf016,null),
EscherOPT(0xf00b,null),
EscherBStoreContainer(0xf001,null),
EscherBSE(0xf007,null),
EscherBlip_START(0xf018,null),
EscherBlip_END(0xf117,null),
EscherDgContainer(0xf002,null),
EscherDg(0xf008,null),
EscherRegroupItems(0xf118,null),
EscherColorScheme(0xf120,null),
EscherSpgrContainer(0xf003,null),
EscherSpContainer(0xf004,null),
EscherSpgr(0xf009,null),
EscherSp(0xf00a,null),
EscherTextbox(0xf00c,null),
EscherClientTextbox(0xf00d,null),
EscherAnchor(0xf00e,null),
EscherChildAnchor(0xf00f,null),
EscherClientAnchor(0xf010,null),
EscherClientData(0xf011,null),
EscherSolverContainer(0xf005,null),
EscherConnectorRule(0xf012,null),
EscherAlignRule(0xf013,null),
EscherArcRule(0xf014,null),
EscherClientRule(0xf015,null),
EscherCalloutRule(0xf017,null),
EscherSelection(0xf119,null),
EscherColorMRU(0xf11a,null),
EscherDeletedPspl(0xf11d,null),
EscherSplitMenuColors(0xf11e,null),
EscherOleObject(0xf11f,null),
EscherUserDefined(0xf122,null);
private static final Map<Short,RecordTypes> LOOKUP;
static {
LOOKUP = new HashMap<Short,RecordTypes>();
for(RecordTypes s : values()) {
LOOKUP.put(s.typeID, s);
}
}
public final short typeID;
public final Class<? extends Record> handlingClass;
private RecordTypes(int typeID, Class<? extends Record> handlingClass) {
this.typeID = (short)typeID;
this.handlingClass = handlingClass;
}
public static RecordTypes forTypeID(int typeID) {
RecordTypes rt = LOOKUP.get((short)typeID);
return (rt != null) ? rt : UnknownRecordPlaceholder;
}
public static final Type OriginalMainMasterId = new Type(1052,null);
public static final Type CompositeMasterId = new Type(1052,null);
public static final Type RoundTripContentMasterInfo12 = new Type(1054,null);
public static final Type RoundTripShapeId12 = new Type(1055,null);
public static final Type RoundTripHFPlaceholder12 = new Type(1056,RoundTripHFPlaceholder12.class);
public static final Type RoundTripContentMasterId = new Type(1058,null);
public static final Type RoundTripOArtTextStyles12 = new Type(1059,null);
public static final Type RoundTripShapeCheckSumForCustomLayouts12 = new Type(1062,null);
public static final Type RoundTripNotesMasterTextStyles12 = new Type(1063,null);
public static final Type RoundTripCustomTableStyles12 = new Type(1064,null);
//records greater then 0xF000 belong to with Microsoft Office Drawing format also known as Escher
public static final int EscherDggContainer = 0xf000;
public static final int EscherDgg = 0xf006;
public static final int EscherCLSID = 0xf016;
public static final int EscherOPT = 0xf00b;
public static final int EscherBStoreContainer = 0xf001;
public static final int EscherBSE = 0xf007;
public static final int EscherBlip_START = 0xf018;
public static final int EscherBlip_END = 0xf117;
public static final int EscherDgContainer = 0xf002;
public static final int EscherDg = 0xf008;
public static final int EscherRegroupItems = 0xf118;
public static final int EscherColorScheme = 0xf120;
public static final int EscherSpgrContainer = 0xf003;
public static final int EscherSpContainer = 0xf004;
public static final int EscherSpgr = 0xf009;
public static final int EscherSp = 0xf00a;
public static final int EscherTextbox = 0xf00c;
public static final int EscherClientTextbox = 0xf00d;
public static final int EscherAnchor = 0xf00e;
public static final int EscherChildAnchor = 0xf00f;
public static final int EscherClientAnchor = 0xf010;
public static final int EscherClientData = 0xf011;
public static final int EscherSolverContainer = 0xf005;
public static final int EscherConnectorRule = 0xf012;
public static final int EscherAlignRule = 0xf013;
public static final int EscherArcRule = 0xf014;
public static final int EscherClientRule = 0xf015;
public static final int EscherCalloutRule = 0xf017;
public static final int EscherSelection = 0xf119;
public static final int EscherColorMRU = 0xf11a;
public static final int EscherDeletedPspl = 0xf11d;
public static final int EscherSplitMenuColors = 0xf11e;
public static final int EscherOleObject = 0xf11f;
public static final int EscherUserDefined = 0xf122;
/** /**
* Returns name of the record by its type * Returns name of the record by its type
@ -218,10 +236,10 @@ public final class RecordTypes {
* @param type section of the record header * @param type section of the record header
* @return name of the record * @return name of the record
*/ */
public static String recordName(int type) { // public static String recordName(int type) {
String name = typeToName.get(Integer.valueOf(type)); // String name = typeToName.get(Integer.valueOf(type));
return (name == null) ? ("Unknown" + type) : name; // return (name == null) ? ("Unknown" + type) : name;
} // }
/** /**
* Returns the class handling a record by its type. * Returns the class handling a record by its type.
@ -232,38 +250,38 @@ public final class RecordTypes {
* @param type section of the record header * @param type section of the record header
* @return class to handle the record, or null if an unknown (eg Escher) record * @return class to handle the record, or null if an unknown (eg Escher) record
*/ */
public static Class<? extends Record> recordHandlingClass(int type) { // public static Class<? extends Record> recordHandlingClass(int type) {
Class<? extends Record> c = typeToClass.get(Integer.valueOf(type)); // Class<? extends Record> c = typeToClass.get(Integer.valueOf(type));
return c; // return c;
} // }
//
static { // static {
typeToName = new HashMap<Integer,String>(); // typeToName = new HashMap<Integer,String>();
typeToClass = new HashMap<Integer,Class<? extends Record>>(); // typeToClass = new HashMap<Integer,Class<? extends Record>>();
try { // try {
Field[] f = RecordTypes.class.getFields(); // Field[] f = RecordTypes.class.getFields();
for (int i = 0; i < f.length; i++){ // for (int i = 0; i < f.length; i++){
Object val = f[i].get(null); // Object val = f[i].get(null);
//
// Escher record, only store ID -> Name // // Escher record, only store ID -> Name
if (val instanceof Integer) { // if (val instanceof Integer) {
typeToName.put((Integer)val, f[i].getName()); // typeToName.put((Integer)val, f[i].getName());
} // }
// PowerPoint record, store ID -> Name and ID -> Class // // PowerPoint record, store ID -> Name and ID -> Class
if (val instanceof Type) { // if (val instanceof Type) {
Type t = (Type)val; // Type t = (Type)val;
Class<? extends Record> c = t.handlingClass; // Class<? extends Record> c = t.handlingClass;
Integer id = Integer.valueOf(t.typeID); // Integer id = Integer.valueOf(t.typeID);
if(c == null) { c = UnknownRecordPlaceholder.class; } // if(c == null) { c = UnknownRecordPlaceholder.class; }
//
typeToName.put(id, f[i].getName()); // typeToName.put(id, f[i].getName());
typeToClass.put(id, c); // typeToClass.put(id, c);
} // }
} // }
} catch (IllegalAccessException e){ // } catch (IllegalAccessException e){
throw new RuntimeException("Failed to initialize records types"); // throw new RuntimeException("Failed to initialize records types");
} // }
} // }
/** /**
@ -271,12 +289,12 @@ public final class RecordTypes {
* Contains both the type, and the handling class (if any), and * Contains both the type, and the handling class (if any), and
* offers methods to get either back out. * offers methods to get either back out.
*/ */
public static class Type { // public static class Type {
public final int typeID; // public final int typeID;
public final Class<? extends Record> handlingClass; // public final Class<? extends Record> handlingClass;
public Type(int typeID, Class<? extends Record> handlingClass) { // public Type(int typeID, Class<? extends Record> handlingClass) {
this.typeID = typeID; // this.typeID = typeID;
this.handlingClass = handlingClass; // this.handlingClass = handlingClass;
} // }
} // }
} }

View File

@ -20,6 +20,8 @@ package org.apache.poi.hslf.record;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import org.apache.poi.util.LittleEndian;
/** /**
* An atom record that specifies that a shape is a header or footer placeholder shape * An atom record that specifies that a shape is a header or footer placeholder shape
* *
@ -40,6 +42,17 @@ public final class RoundTripHFPlaceholder12 extends RecordAtom {
*/ */
private byte _placeholderId; private byte _placeholderId;
/**
* Create a new instance of <code>RoundTripHFPlaceholder12</code>
*/
public RoundTripHFPlaceholder12(){
_header = new byte[8];
LittleEndian.putUShort(_header, 0, 0);
LittleEndian.putUShort(_header, 2, (int)getRecordType());
LittleEndian.putInt(_header, 4, 8);
_placeholderId = 0;
}
/** /**
* Constructs the comment atom record from its source data. * Constructs the comment atom record from its source data.
* *

View File

@ -171,7 +171,7 @@ public final class TxMasterStyleAtom extends RecordAtom {
/** /**
* Updates the rawdata from the modified paragraph/character styles * Updates the rawdata from the modified paragraph/character styles
* *
* @since 3.14-beta1 * @since POI 3.14-beta1
*/ */
public void updateStyles() { public void updateStyles() {
int type = getTextType(); int type = getTextType();

View File

@ -17,10 +17,18 @@
package org.apache.poi.hslf.usermodel; package org.apache.poi.hslf.usermodel;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import org.apache.poi.ddf.*; import org.apache.poi.hslf.record.ExHyperlink;
import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.record.ExObjList;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.InteractiveInfo;
import org.apache.poi.hslf.record.InteractiveInfoAtom;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.TxInteractiveInfoAtom;
/** /**
* Represents a hyperlink in a PowerPoint document * Represents a hyperlink in a PowerPoint document
@ -156,6 +164,7 @@ public final class HSLFHyperlink {
* @param paragraphs List of <code>TextParagraph</code> to lookup hyperlinks * @param paragraphs List of <code>TextParagraph</code> to lookup hyperlinks
* @return found hyperlinks * @return found hyperlinks
*/ */
@SuppressWarnings("resource")
public static List<HSLFHyperlink> find(List<HSLFTextParagraph> paragraphs){ public static List<HSLFHyperlink> find(List<HSLFTextParagraph> paragraphs){
List<HSLFHyperlink> lst = new ArrayList<HSLFHyperlink>(); List<HSLFHyperlink> lst = new ArrayList<HSLFHyperlink>();
if (paragraphs == null || paragraphs.isEmpty()) return lst; if (paragraphs == null || paragraphs.isEmpty()) return lst;
@ -165,10 +174,10 @@ public final class HSLFHyperlink {
HSLFSlideShow ppt = firstPara.getSheet().getSlideShow(); HSLFSlideShow ppt = firstPara.getSheet().getSlideShow();
//document-level container which stores info about all links in a presentation //document-level container which stores info about all links in a presentation
ExObjList exobj = ppt.getDocumentRecord().getExObjList(); ExObjList exobj = ppt.getDocumentRecord().getExObjList();
if (exobj == null) return lst; if (exobj != null) {
Record[] records = firstPara.getRecords(); Record[] records = firstPara.getRecords();
find(records, exobj, lst); find(Arrays.asList(records), exobj, lst);
}
return lst; return lst;
} }
@ -179,39 +188,38 @@ public final class HSLFHyperlink {
* @param shape <code>Shape</code> to lookup hyperlink in * @param shape <code>Shape</code> to lookup hyperlink in
* @return found hyperlink or <code>null</code> * @return found hyperlink or <code>null</code>
*/ */
@SuppressWarnings("resource")
public static HSLFHyperlink find(HSLFShape shape){ public static HSLFHyperlink find(HSLFShape shape){
List<HSLFHyperlink> lst = new ArrayList<HSLFHyperlink>();
HSLFSlideShow ppt = shape.getSheet().getSlideShow(); HSLFSlideShow ppt = shape.getSheet().getSlideShow();
//document-level container which stores info about all links in a presentation //document-level container which stores info about all links in a presentation
ExObjList exobj = ppt.getDocumentRecord().getExObjList(); ExObjList exobj = ppt.getDocumentRecord().getExObjList();
if (exobj == null) { HSLFEscherClientDataRecord cldata = shape.getClientData(false);
if (exobj != null && cldata != null) {
List<HSLFHyperlink> lst = new ArrayList<HSLFHyperlink>();
find(cldata.getHSLFChildRecords(), exobj, lst);
return lst.isEmpty() ? null : (HSLFHyperlink)lst.get(0);
}
return null; return null;
} }
EscherContainerRecord spContainer = shape.getSpContainer(); private static void find(List<? extends Record> records, ExObjList exobj, List<HSLFHyperlink> out){
for (Iterator<EscherRecord> it = spContainer.getChildIterator(); it.hasNext(); ) { ListIterator<? extends Record> iter = records.listIterator();
EscherRecord obj = it.next(); while (iter.hasNext()) {
if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID){ Record r = iter.next();
byte[] data = obj.serialize(); // see if we have InteractiveInfo in the textrun's records
Record[] records = Record.findChildRecords(data, 8, data.length-8); if (!(r instanceof InteractiveInfo)) {
find(records, exobj, lst); continue;
}
} }
return lst.size() == 1 ? (HSLFHyperlink)lst.get(0) : null; InteractiveInfo hldr = (InteractiveInfo)r;
}
private static void find(Record[] records, ExObjList exobj, List<HSLFHyperlink> out){
if (records == null) return;
for (int i = 0; i < records.length; i++) {
//see if we have InteractiveInfo in the textrun's records
if(!(records[i] instanceof InteractiveInfo)) continue;
InteractiveInfo hldr = (InteractiveInfo)records[i];
InteractiveInfoAtom info = hldr.getInteractiveInfoAtom(); InteractiveInfoAtom info = hldr.getInteractiveInfoAtom();
int id = info.getHyperlinkID(); int id = info.getHyperlinkID();
ExHyperlink linkRecord = exobj.get(id); ExHyperlink linkRecord = exobj.get(id);
if (linkRecord == null) continue; if (linkRecord == null) {
continue;
}
HSLFHyperlink link = new HSLFHyperlink(); HSLFHyperlink link = new HSLFHyperlink();
link.title = linkRecord.getLinkTitle(); link.title = linkRecord.getLinkTitle();
@ -219,8 +227,13 @@ public final class HSLFHyperlink {
link.type = info.getAction(); link.type = info.getAction();
out.add(link); out.add(link);
if (i+1 < records.length && records[i+1] instanceof TxInteractiveInfoAtom){ if (iter.hasNext()) {
TxInteractiveInfoAtom txinfo = (TxInteractiveInfoAtom)records[++i]; r = iter.next();
if (!(r instanceof TxInteractiveInfoAtom)) {
iter.previous();
continue;
}
TxInteractiveInfoAtom txinfo = (TxInteractiveInfoAtom)r;
link.startIndex = txinfo.getStartIndex(); link.startIndex = txinfo.getStartIndex();
link.endIndex = txinfo.getEndIndex(); link.endIndex = txinfo.getEndIndex();
} }

View File

@ -18,7 +18,7 @@
package org.apache.poi.hslf.usermodel; package org.apache.poi.hslf.usermodel;
import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeContainer;
/** /**

View File

@ -21,6 +21,7 @@ import java.awt.Color;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import org.apache.poi.ddf.AbstractEscherOptRecord; import org.apache.poi.ddf.AbstractEscherOptRecord;
import org.apache.poi.ddf.EscherChildAnchorRecord; import org.apache.poi.ddf.EscherChildAnchorRecord;
@ -33,7 +34,10 @@ import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherRecord; import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherSimpleProperty; import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherSpRecord; import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.hslf.record.ColorSchemeAtom; import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordTypes; import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.sl.usermodel.FillStyle; import org.apache.poi.sl.usermodel.FillStyle;
import org.apache.poi.sl.usermodel.Shape; import org.apache.poi.sl.usermodel.Shape;
@ -218,18 +222,31 @@ public abstract class HSLFShape implements Shape<HSLFShape,HSLFTextParagraph> {
return owner.getChildById((short)recordId); return owner.getChildById((short)recordId);
} }
/**
* @since POI 3.14-Beta2
*/
public static <T extends EscherRecord> T getEscherChild(EscherContainerRecord owner, RecordTypes recordId){
return getEscherChild(owner, recordId.typeID);
}
public <T extends EscherRecord> T getEscherChild(int recordId){ public <T extends EscherRecord> T getEscherChild(int recordId){
return _escherContainer.getChildById((short)recordId); return _escherContainer.getChildById((short)recordId);
} }
/**
* @since POI 3.14-Beta2
*/
public <T extends EscherRecord> T getEscherChild(RecordTypes recordId){
return getEscherChild(recordId.typeID);
}
/** /**
* Returns escher property by id. * Returns escher property by id.
* *
* @return escher property or <code>null</code> if not found. * @return escher property or <code>null</code> if not found.
*/ */
public static <T extends EscherProperty> T getEscherProperty(AbstractEscherOptRecord opt, int propId){ public static <T extends EscherProperty> T getEscherProperty(AbstractEscherOptRecord opt, int propId){
if (opt == null) return null; return (opt == null) ? null : opt.<T>lookup(propId);
return opt.lookup(propId);
} }
/** /**
@ -443,7 +460,7 @@ public abstract class HSLFShape implements Shape<HSLFShape,HSLFTextParagraph> {
} }
public AbstractEscherOptRecord getEscherOptRecord() { public AbstractEscherOptRecord getEscherOptRecord() {
AbstractEscherOptRecord opt = getEscherChild(EscherOptRecord.RECORD_ID); AbstractEscherOptRecord opt = getEscherChild(RecordTypes.EscherOPT);
if (opt == null) { if (opt == null) {
opt = getEscherChild(RecordTypes.EscherUserDefined); opt = getEscherChild(RecordTypes.EscherUserDefined);
} }
@ -485,4 +502,48 @@ public abstract class HSLFShape implements Shape<HSLFShape,HSLFTextParagraph> {
public boolean isPlaceholder() { public boolean isPlaceholder() {
return false; return false;
} }
/**
* Find a record in the underlying EscherClientDataRecord
*
* @param recordType type of the record to search
*/
@SuppressWarnings("unchecked")
public <T extends Record> T getClientDataRecord(int recordType) {
List<? extends Record> records = getClientRecords();
if (records != null) for (Record r : records) {
if (r.getRecordType() == recordType){
return (T)r;
}
}
return null;
}
/**
* Search for EscherClientDataRecord, if found, convert its contents into an array of HSLF records
*
* @return an array of HSLF records contained in the shape's EscherClientDataRecord or <code>null</code>
*/
protected List<? extends Record> getClientRecords() {
HSLFEscherClientDataRecord clientData = getClientData(false);
return (clientData == null) ? null : clientData.getHSLFChildRecords();
}
/**
* Create a new HSLF-specific EscherClientDataRecord
*
* @param create if true, create the missing record
* @return the client record or null if it was missing and create wasn't activated
*/
protected HSLFEscherClientDataRecord getClientData(boolean create) {
HSLFEscherClientDataRecord clientData = getEscherChild(HSLFEscherClientDataRecord.RECORD_ID);
if (clientData == null && create) {
clientData = new HSLFEscherClientDataRecord();
clientData.setOptions((short)15);
clientData.setRecordId(HSLFEscherClientDataRecord.RECORD_ID);
getSpContainer().addChildBefore(clientData, EscherTextboxRecord.RECORD_ID);
}
return clientData;
}
} }

View File

@ -17,12 +17,27 @@
package org.apache.poi.hslf.usermodel; package org.apache.poi.hslf.usermodel;
import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.poi.ddf.*; import org.apache.poi.ddf.AbstractEscherOptRecord;
import org.apache.poi.hslf.model.*; import org.apache.poi.ddf.EscherClientDataRecord;
import org.apache.poi.hslf.record.*; import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherPropertyFactory;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.hslf.model.MovieShape;
import org.apache.poi.hslf.model.OLEShape;
import org.apache.poi.hslf.record.ExObjRefAtom;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.InteractiveInfo;
import org.apache.poi.hslf.record.InteractiveInfoAtom;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
@ -50,7 +65,7 @@ public final class HSLFShapeFactory {
public static HSLFGroupShape createShapeGroup(EscherContainerRecord spContainer, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){ public static HSLFGroupShape createShapeGroup(EscherContainerRecord spContainer, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
boolean isTable = false; boolean isTable = false;
EscherContainerRecord ecr = (EscherContainerRecord)spContainer.getChild(0); EscherContainerRecord ecr = (EscherContainerRecord)spContainer.getChild(0);
EscherRecord opt = HSLFShape.getEscherChild(ecr, (short)RecordTypes.EscherUserDefined); EscherRecord opt = HSLFShape.getEscherChild(ecr, RecordTypes.EscherUserDefined);
if (opt != null) { if (opt != null) {
EscherPropertyFactory f = new EscherPropertyFactory(); EscherPropertyFactory f = new EscherPropertyFactory();
@ -120,12 +135,10 @@ public final class HSLFShapeFactory {
} }
} }
OEShapeAtom oes = getClientDataRecord(spContainer, RecordTypes.OEShapeAtom.typeID); ExObjRefAtom oes = getClientDataRecord(spContainer, RecordTypes.ExObjRefAtom.typeID);
if (oes != null){ return (oes != null)
return new OLEShape(spContainer, parent); ? new OLEShape(spContainer, parent)
} : new HSLFPictureShape(spContainer, parent);
return new HSLFPictureShape(spContainer, parent);
} }
private static HSLFShape createNonPrimitive(EscherContainerRecord spContainer, ShapeContainer<HSLFShape,HSLFTextParagraph> parent) { private static HSLFShape createNonPrimitive(EscherContainerRecord spContainer, ShapeContainer<HSLFShape,HSLFTextParagraph> parent) {
@ -141,17 +154,12 @@ public final class HSLFShapeFactory {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected static <T extends Record> T getClientDataRecord(EscherContainerRecord spContainer, int recordType) { protected static <T extends Record> T getClientDataRecord(EscherContainerRecord spContainer, int recordType) {
for (Iterator<EscherRecord> it = spContainer.getChildIterator(); it.hasNext();) { HSLFEscherClientDataRecord cldata = spContainer.getChildById(EscherClientDataRecord.RECORD_ID);
EscherRecord obj = it.next(); if (cldata != null) for (Record r : cldata.getHSLFChildRecords()) {
if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
byte[] data = obj.serialize();
for (Record r : Record.findChildRecords(data, 8, data.length - 8)) {
if (r.getRecordType() == recordType) { if (r.getRecordType() == recordType) {
return (T)r; return (T)r;
} }
} }
}
}
return null; return null;
} }

View File

@ -149,7 +149,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
public List<HSLFShape> getShapes() { public List<HSLFShape> getShapes() {
PPDrawing ppdrawing = getPPDrawing(); PPDrawing ppdrawing = getPPDrawing();
EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; EscherContainerRecord dg = ppdrawing.getDgContainer();
EscherContainerRecord spgr = null; EscherContainerRecord spgr = null;
for (Iterator<EscherRecord> it = dg.getChildIterator(); it.hasNext();) { for (Iterator<EscherRecord> it = dg.getChildIterator(); it.hasNext();) {
@ -187,7 +187,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
public void addShape(HSLFShape shape) { public void addShape(HSLFShape shape) {
PPDrawing ppdrawing = getPPDrawing(); PPDrawing ppdrawing = getPPDrawing();
EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; EscherContainerRecord dgContainer = ppdrawing.getDgContainer();
EscherContainerRecord spgr = (EscherContainerRecord) HSLFShape.getEscherChild(dgContainer, EscherContainerRecord.SPGR_CONTAINER); EscherContainerRecord spgr = (EscherContainerRecord) HSLFShape.getEscherChild(dgContainer, EscherContainerRecord.SPGR_CONTAINER);
spgr.addChildRecord(shape.getSpContainer()); spgr.addChildRecord(shape.getSpContainer());
@ -244,16 +244,8 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
public boolean removeShape(HSLFShape shape) { public boolean removeShape(HSLFShape shape) {
PPDrawing ppdrawing = getPPDrawing(); PPDrawing ppdrawing = getPPDrawing();
EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; EscherContainerRecord dg = ppdrawing.getDgContainer();
EscherContainerRecord spgr = null; EscherContainerRecord spgr = dg.getChildById(EscherContainerRecord.SPGR_CONTAINER);
for (Iterator<EscherRecord> it = dg.getChildIterator(); it.hasNext();) {
EscherRecord rec = it.next();
if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
spgr = (EscherContainerRecord) rec;
break;
}
}
if(spgr == null) { if(spgr == null) {
return false; return false;
} }
@ -292,7 +284,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
if (_background == null) { if (_background == null) {
PPDrawing ppdrawing = getPPDrawing(); PPDrawing ppdrawing = getPPDrawing();
EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; EscherContainerRecord dg = ppdrawing.getDgContainer();
EscherContainerRecord spContainer = dg.getChildById(EscherContainerRecord.SP_CONTAINER); EscherContainerRecord spContainer = dg.getChildById(EscherContainerRecord.SP_CONTAINER);
_background = new HSLFBackground(spContainer, null); _background = new HSLFBackground(spContainer, null);
_background.setSheet(this); _background.setSheet(this);

View File

@ -18,16 +18,40 @@
package org.apache.poi.hslf.usermodel; package org.apache.poi.hslf.usermodel;
import java.awt.Color; import java.awt.Color;
import java.io.ByteArrayOutputStream; import java.util.List;
import org.apache.poi.ddf.*; import org.apache.poi.ddf.AbstractEscherOptRecord;
import org.apache.poi.ddf.EscherChildAnchorRecord;
import org.apache.poi.ddf.EscherClientAnchorRecord;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.InteractiveInfo;
import org.apache.poi.hslf.record.InteractiveInfoAtom;
import org.apache.poi.hslf.record.OEPlaceholderAtom;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.draw.geom.*; import org.apache.poi.sl.draw.geom.CustomGeometry;
import org.apache.poi.sl.usermodel.*; import org.apache.poi.sl.draw.geom.Guide;
import org.apache.poi.sl.usermodel.LineDecoration.*; import org.apache.poi.sl.draw.geom.PresetGeometries;
import org.apache.poi.sl.usermodel.LineDecoration;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.Shadow;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.SimpleShape;
import org.apache.poi.sl.usermodel.StrokeStyle;
import org.apache.poi.sl.usermodel.StrokeStyle.LineCap; import org.apache.poi.sl.usermodel.StrokeStyle.LineCap;
import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound; import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
@ -45,12 +69,6 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
public final static double DEFAULT_LINE_WIDTH = 0.75; public final static double DEFAULT_LINE_WIDTH = 0.75;
/**
* 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.
* *
@ -83,8 +101,9 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
_escherContainer.addChildRecord(opt); _escherContainer.addChildRecord(opt);
EscherRecord anchor; EscherRecord anchor;
if(isChild) anchor = new EscherChildAnchorRecord(); if(isChild) {
else { anchor = new EscherChildAnchorRecord();
} else {
anchor = new EscherClientAnchorRecord(); anchor = new EscherClientAnchorRecord();
//hack. internal variable EscherClientAnchorRecord.shortRecord can be //hack. internal variable EscherClientAnchorRecord.shortRecord can be
@ -251,70 +270,11 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
getFill().setForegroundColor(color); getFill().setForegroundColor(color);
} }
/**
* Find a record in the underlying EscherClientDataRecord
*
* @param recordType type of the record to search
*/
@SuppressWarnings("unchecked")
protected <T extends Record> T getClientDataRecord(int recordType) {
Record[] records = getClientRecords();
if(records != null) for (int i = 0; i < records.length; i++) {
if(records[i].getRecordType() == recordType){
return (T)records[i];
}
}
return null;
}
/**
* Search for EscherClientDataRecord, if found, convert its contents into an array of HSLF records
*
* @return an array of HSLF records contained in the shape's EscherClientDataRecord or <code>null</code>
*/
protected Record[] getClientRecords() {
if(_clientData == null){
EscherRecord r = getEscherChild(EscherClientDataRecord.RECORD_ID);
//ddf can return EscherContainerRecord with recordId=EscherClientDataRecord.RECORD_ID
//convert in to EscherClientDataRecord on the fly
if(r != null && !(r instanceof EscherClientDataRecord)){
byte[] data = r.serialize();
r = new EscherClientDataRecord();
r.fillFields(data, 0, new HSLFEscherRecordFactory());
}
_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());
}
}
public void setHyperlink(HSLFHyperlink link){ public void setHyperlink(HSLFHyperlink link){
if(link.getId() == -1){ if(link.getId() == -1){
throw new HSLFException("You must call SlideShow.addHyperlink(Hyperlink link) first"); throw new HSLFException("You must call SlideShow.addHyperlink(Hyperlink link) first");
} }
EscherClientDataRecord cldata = new EscherClientDataRecord();
cldata.setOptions((short)0xF);
getSpContainer().addChildRecord(cldata); // TODO - junit to prove getChildRecords().add is wrong
InteractiveInfo info = new InteractiveInfo(); InteractiveInfo info = new InteractiveInfo();
InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom(); InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom();
@ -356,14 +316,8 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
infoAtom.setHyperlinkID(link.getId()); infoAtom.setHyperlinkID(link.getId());
ByteArrayOutputStream out = new ByteArrayOutputStream(); HSLFEscherClientDataRecord cldata = getClientData(true);
try { cldata.addChild(infoAtom);
info.writeOut(out);
} catch(Exception e){
throw new HSLFException(e);
}
cldata.setRemainingData(out.toByteArray());
} }
public Guide getAdjustValue(String name) { public Guide getAdjustValue(String name) {
@ -561,98 +515,118 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
}; };
} }
protected void setPlaceholder(Placeholder placeholder) { @Override
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID); public Placeholder getPlaceholder() {
List<? extends Record> clRecords = getClientRecords();
if (clRecords == null) {
return null;
}
for (Record r : clRecords) {
if (r instanceof OEPlaceholderAtom) {
OEPlaceholderAtom oep = (OEPlaceholderAtom)r;
return Placeholder.lookupNative(oep.getPlaceholderId());
} else if (r instanceof RoundTripHFPlaceholder12) {
RoundTripHFPlaceholder12 rtp = (RoundTripHFPlaceholder12)r;
return Placeholder.lookupNative(rtp.getPlaceholderId());
}
}
return null;
}
@Override
public void setPlaceholder(Placeholder placeholder) {
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
int flags = spRecord.getFlags(); int flags = spRecord.getFlags();
if (placeholder == null) {
flags ^= EscherSpRecord.FLAG_HAVEMASTER;
} else {
flags |= EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER; flags |= EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER;
}
spRecord.setFlags(flags); spRecord.setFlags(flags);
EscherClientDataRecord cldata = _escherContainer.getChildById(EscherClientDataRecord.RECORD_ID);
if (cldata == null) {
cldata = new EscherClientDataRecord();
// append placeholder container before EscherTextboxRecord
_escherContainer.addChildBefore(cldata, EscherTextboxRecord.RECORD_ID);
}
cldata.setOptions((short)15);
AbstractEscherOptRecord opt = getEscherOptRecord();
// Placeholders can't be grouped // Placeholders can't be grouped
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144); setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, (placeholder == null ? -1 : 262144));
HSLFEscherClientDataRecord clientData = getClientData(false);
if (placeholder == null) {
if (clientData != null) {
clientData.removeChild(OEPlaceholderAtom.class);
clientData.removeChild(RoundTripHFPlaceholder12.class);
// remove client data if the placeholder was the only child to be carried
if (clientData.getChildRecords().isEmpty()) {
getSpContainer().removeChildRecord(clientData);
}
}
return;
}
if (clientData == null) {
clientData = getClientData(true);
}
// OEPlaceholderAtom tells powerpoint that this shape is a placeholder // OEPlaceholderAtom tells powerpoint that this shape is a placeholder
OEPlaceholderAtom oep = new OEPlaceholderAtom(); OEPlaceholderAtom oep = null;
RoundTripHFPlaceholder12 rtp = null;
for (Record r : clientData.getHSLFChildRecords()) {
if (r instanceof OEPlaceholderAtom) {
oep = (OEPlaceholderAtom)r;
break;
}
if (r instanceof RoundTripHFPlaceholder12) {
rtp = (RoundTripHFPlaceholder12)r;
break;
}
}
/** /**
* Extarct from MSDN: * Extract from MSDN:
* *
* There is a special case when the placeholder does not have a position in the layout. * There is a special case when the placeholder does not have a position in the layout.
* This occurs when the user has moved the placeholder from its original position. * This occurs when the user has moved the placeholder from its original position.
* In this case the placeholder ID is -1. * In this case the placeholder ID is -1.
*/ */
oep.setPlacementId(-1);
boolean isMaster = (getSheet() instanceof HSLFSlideMaster);
boolean isNotes = (getSheet() instanceof HSLFNotes);
byte phId; byte phId;
HSLFSheet sheet = getSheet();
// TODO: implement/switch NotesMaster
if (sheet instanceof HSLFSlideMaster) {
phId = (byte)placeholder.nativeSlideMasterId;
} else if (sheet instanceof HSLFNotes) {
phId = (byte)placeholder.nativeNotesId;
} else {
phId = (byte)placeholder.nativeSlideId;
}
if (phId == -2) {
throw new HSLFException("Placeholder "+placeholder.name()+" not supported for this sheet type ("+sheet.getClass()+")");
}
switch (placeholder) { switch (placeholder) {
case TITLE:
phId = (isMaster) ? OEPlaceholderAtom.MasterTitle : OEPlaceholderAtom.Title;
break;
case BODY:
phId = (isMaster) ? OEPlaceholderAtom.MasterBody :
((isNotes) ? OEPlaceholderAtom.NotesBody : OEPlaceholderAtom.Body);
break;
case CENTERED_TITLE:
phId = (isMaster) ? OEPlaceholderAtom.MasterCenteredTitle : OEPlaceholderAtom.CenteredTitle;
break;
case SUBTITLE:
phId = (isMaster) ? OEPlaceholderAtom.MasterSubTitle : OEPlaceholderAtom.Subtitle;
break;
case DATETIME:
phId = OEPlaceholderAtom.MasterDate;
break;
case SLIDE_NUMBER:
phId = OEPlaceholderAtom.MasterSlideNumber;
break;
case FOOTER:
phId = OEPlaceholderAtom.MasterFooter;
break;
case HEADER: case HEADER:
phId = OEPlaceholderAtom.MasterHeader; case FOOTER:
break; if (rtp == null) {
case DGM: rtp = new RoundTripHFPlaceholder12();
case CHART: rtp.setPlaceholderId(phId);
phId = OEPlaceholderAtom.Graph; clientData.addChild(rtp);
break; }
case TABLE: if (oep != null) {
phId = OEPlaceholderAtom.Table; clientData.removeChild(OEPlaceholderAtom.class);
break; }
case PICTURE:
case CLIP_ART:
phId = OEPlaceholderAtom.ClipArt;
break;
case MEDIA:
phId = OEPlaceholderAtom.MediaClip;
break;
case SLIDE_IMAGE:
phId = (isMaster) ? OEPlaceholderAtom.MasterNotesSlideImage : OEPlaceholderAtom.NotesSlideImage;
break; break;
default: default:
case CONTENT: if (rtp != null) {
phId = OEPlaceholderAtom.Object; clientData.removeChild(RoundTripHFPlaceholder12.class);
}
if (oep == null) {
oep = new OEPlaceholderAtom();
oep.setPlaceholderSize((byte)OEPlaceholderAtom.PLACEHOLDER_FULLSIZE);
// TODO: placement id only "SHOULD" be unique ... check other placeholders on sheet for unique id
oep.setPlacementId(-1);
oep.setPlaceholderId(phId);
clientData.addChild(oep);
}
break; break;
} }
oep.setPlaceholderId(phId);
//convert hslf into ddf record
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
oep.writeOut(out);
} catch(Exception e){
throw new HSLFException(e);
}
cldata.setRemainingData(out.toByteArray());
} }

View File

@ -42,8 +42,8 @@ import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.Drawable; import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.Notes; import org.apache.poi.sl.usermodel.Notes;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;
import org.apache.poi.sl.usermodel.Slide; import org.apache.poi.sl.usermodel.Slide;
/** /**
@ -163,7 +163,7 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe
public void onCreate(){ public void onCreate(){
//initialize drawing group id //initialize drawing group id
EscherDggRecord dgg = getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord(); EscherDggRecord dgg = getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
EscherContainerRecord dgContainer = (EscherContainerRecord)getSheetContainer().getPPDrawing().getEscherRecords()[0]; EscherContainerRecord dgContainer = getSheetContainer().getPPDrawing().getDgContainer();
EscherDgRecord dg = (EscherDgRecord) HSLFShape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID); EscherDgRecord dg = (EscherDgRecord) HSLFShape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
int dgId = dgg.getMaxDrawingGroupId() + 1; int dgId = dgg.getMaxDrawingGroupId() + 1;
dg.setOptions((short)(dgId << 4)); dg.setOptions((short)(dgId << 4));

View File

@ -1162,8 +1162,8 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
// For position dependent records, hold where they were and now are // For position dependent records, hold where they were and now are
// As we go along, update, and hand over, to any Position Dependent // As we go along, update, and hand over, to any Position Dependent
// records we happen across // records we happen across
Map<RecordTypes.Type,PositionDependentRecord> interestingRecords = Map<RecordTypes,PositionDependentRecord> interestingRecords =
new HashMap<RecordTypes.Type,PositionDependentRecord>(); new HashMap<RecordTypes,PositionDependentRecord>();
try { try {
_hslfSlideShow.updateAndWriteDependantRecords(null,interestingRecords); _hslfSlideShow.updateAndWriteDependantRecords(null,interestingRecords);

View File

@ -474,7 +474,7 @@ public final class HSLFSlideShowImpl extends POIDocument implements Closeable {
* May be null, if not needed. * May be null, if not needed.
* @throws IOException * @throws IOException
*/ */
public void updateAndWriteDependantRecords(OutputStream os, Map<RecordTypes.Type,PositionDependentRecord> interestingRecords) public void updateAndWriteDependantRecords(OutputStream os, Map<RecordTypes,PositionDependentRecord> interestingRecords)
throws IOException { throws IOException {
// For position dependent records, hold where they were and now are // For position dependent records, hold where they were and now are
// As we go along, update, and hand over, to any Position Dependent // As we go along, update, and hand over, to any Position Dependent
@ -502,7 +502,7 @@ public final class HSLFSlideShowImpl extends POIDocument implements Closeable {
// Grab interesting records as they come past // Grab interesting records as they come past
// this will only save the very last record of each type // this will only save the very last record of each type
RecordTypes.Type saveme = null; RecordTypes saveme = null;
int recordType = (int)record.getRecordType(); int recordType = (int)record.getRecordType();
if (recordType == RecordTypes.PersistPtrIncrementalBlock.typeID) { if (recordType == RecordTypes.PersistPtrIncrementalBlock.typeID) {
saveme = RecordTypes.PersistPtrIncrementalBlock; saveme = RecordTypes.PersistPtrIncrementalBlock;

View File

@ -95,14 +95,14 @@ implements HSLFShapeContainer, TableShape<HSLFShape,HSLFTextParagraph> {
EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0); EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0);
AbstractEscherOptRecord opt = new EscherOptRecord(); AbstractEscherOptRecord opt = new EscherOptRecord();
opt.setRecordId((short)RecordTypes.EscherUserDefined); opt.setRecordId(RecordTypes.EscherUserDefined.typeID);
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GROUPSHAPE__TABLEPROPERTIES, 1)); opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GROUPSHAPE__TABLEPROPERTIES, 1));
EscherArrayProperty p = new EscherArrayProperty((short)(0x4000 | EscherProperties.GROUPSHAPE__TABLEROWPROPERTIES), false, null); EscherArrayProperty p = new EscherArrayProperty((short)(0x4000 | EscherProperties.GROUPSHAPE__TABLEROWPROPERTIES), false, null);
p.setSizeOfElements(0x0004); p.setSizeOfElements(0x0004);
p.setNumberOfElementsInArray(numRows); p.setNumberOfElementsInArray(numRows);
p.setNumberOfElementsInMemory(numRows); p.setNumberOfElementsInMemory(numRows);
opt.addEscherProperty(p); opt.addEscherProperty(p);
spCont.addChildBefore(opt, RecordTypes.EscherClientAnchor); spCont.addChildBefore(opt, RecordTypes.EscherClientAnchor.typeID);
} }
/** /**

View File

@ -157,7 +157,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
* *
* @param paragraphStyle the master style reference * @param paragraphStyle the master style reference
* *
* @since 3.14-Beta1 * @since POI 3.14-Beta1
*/ */
@Internal @Internal
/* package */ void setMasterStyleReference(TextPropCollection paragraphStyle) { /* package */ void setMasterStyleReference(TextPropCollection paragraphStyle) {

View File

@ -76,7 +76,7 @@ public final class HSLFTextRun implements TextRun {
* *
* @param characterStyle the master style reference * @param characterStyle the master style reference
* *
* @since 3.14-Beta1 * @since POI 3.14-Beta1
*/ */
@Internal @Internal
/* package */ void setMasterStyleReference(TextPropCollection characterStyle) { /* package */ void setMasterStyleReference(TextPropCollection characterStyle) {

View File

@ -45,6 +45,7 @@ import org.apache.poi.hslf.record.TxInteractiveInfoAtom;
import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.DrawTextShape; import org.apache.poi.sl.draw.DrawTextShape;
import org.apache.poi.sl.usermodel.Insets2D; import org.apache.poi.sl.usermodel.Insets2D;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.TextShape; import org.apache.poi.sl.usermodel.TextShape;
import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.sl.usermodel.VerticalAlignment;
@ -603,14 +604,29 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
} }
/** /**
* Return <code>OEPlaceholderAtom</code>, the atom that describes a placeholder. * Return {@link OEPlaceholderAtom}, the atom that describes a placeholder.
* *
* @return <code>OEPlaceholderAtom</code> or <code>null</code> if not found * @return {@link OEPlaceholderAtom} or {@code null} if not found
*/ */
public OEPlaceholderAtom getPlaceholderAtom(){ public OEPlaceholderAtom getPlaceholderAtom(){
return getClientDataRecord(OEPlaceholderAtom.typeID); return getClientDataRecord(OEPlaceholderAtom.typeID);
} }
/**
* Return {@link RoundTripHFPlaceholder12}, the atom that describes a header/footer placeholder.
* Compare the {@link RoundTripHFPlaceholder12#getPlaceholderId()} with
* {@link OEPlaceholderAtom#MasterHeader} or {@link OEPlaceholderAtom#MasterFooter}, to find out
* what kind of placeholder this is.
*
* @return {@link RoundTripHFPlaceholder12} or {@code null} if not found
*
* @since POI 3.14-Beta2
*/
public RoundTripHFPlaceholder12 getHFPlaceholderAtom() {
// special case for files saved in Office 2007
return getClientDataRecord(RoundTripHFPlaceholder12.typeID);
}
/** /**
* *
* Assigns a hyperlink to this text shape * Assigns a hyperlink to this text shape
@ -644,7 +660,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
if (oep != null) return true; if (oep != null) return true;
//special case for files saved in Office 2007 //special case for files saved in Office 2007
RoundTripHFPlaceholder12 hldr = getClientDataRecord(RoundTripHFPlaceholder12.typeID); RoundTripHFPlaceholder12 hldr = getHFPlaceholderAtom();
if (hldr != null) return true; if (hldr != null) return true;
return false; return false;

View File

@ -17,18 +17,22 @@
package org.apache.poi.hslf; package org.apache.poi.hslf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException; import java.io.IOException;
import junit.framework.TestCase;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl;
import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.junit.Before;
import org.junit.Test;
/** /**
* Tests that HSLFSlideShow writes the powerpoint bit of data back out * Tests that HSLFSlideShow writes the powerpoint bit of data back out
@ -36,7 +40,7 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
* *
* @author Nick Burch (nick at torchbox dot com) * @author Nick Burch (nick at torchbox dot com)
*/ */
public final class TestReWrite extends TestCase { public final class TestReWrite {
// HSLFSlideShow primed on the test data // HSLFSlideShow primed on the test data
private HSLFSlideShowImpl hssA; private HSLFSlideShowImpl hssA;
private HSLFSlideShowImpl hssB; private HSLFSlideShowImpl hssB;
@ -46,6 +50,7 @@ public final class TestReWrite extends TestCase {
private POIFSFileSystem pfsB; private POIFSFileSystem pfsB;
private POIFSFileSystem pfsC; private POIFSFileSystem pfsC;
@Before
public void setUp() throws Exception { public void setUp() throws Exception {
POIDataSamples slTests = POIDataSamples.getSlideShowInstance(); POIDataSamples slTests = POIDataSamples.getSlideShowInstance();
@ -60,10 +65,12 @@ public final class TestReWrite extends TestCase {
hssC = new HSLFSlideShowImpl(pfsC); hssC = new HSLFSlideShowImpl(pfsC);
} }
@Test
public void testWritesOutTheSame() throws Exception { public void testWritesOutTheSame() throws Exception {
assertWritesOutTheSame(hssA, pfsA); assertWritesOutTheSame(hssA, pfsA);
assertWritesOutTheSame(hssB, pfsB); assertWritesOutTheSame(hssB, pfsB);
} }
public void assertWritesOutTheSame(HSLFSlideShowImpl hss, POIFSFileSystem pfs) throws Exception { public void assertWritesOutTheSame(HSLFSlideShowImpl hss, POIFSFileSystem pfs) throws Exception {
// Write out to a byte array // Write out to a byte array
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
@ -89,9 +96,11 @@ public final class TestReWrite extends TestCase {
//System.out.println(i + "\t" + Integer.toHexString(i)); //System.out.println(i + "\t" + Integer.toHexString(i));
assertEquals(_oData[i], _nData[i]); assertEquals(_oData[i], _nData[i]);
} }
npfs.close();
} }
public void testWithMacroStreams() throws Exception { @Test
public void testWithMacroStreams() throws IOException {
// Check that they're apparently the same // Check that they're apparently the same
assertSlideShowWritesOutTheSame(hssC, pfsC); assertSlideShowWritesOutTheSame(hssC, pfsC);
@ -101,28 +110,25 @@ public final class TestReWrite extends TestCase {
// Write out normally, will loose the macro stream // Write out normally, will loose the macro stream
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
hssC.write(baos); hssC.write(baos);
POIFSFileSystem pfsNew = new POIFSFileSystem( ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
new ByteArrayInputStream(baos.toByteArray()) ); POIFSFileSystem pfsNew = new POIFSFileSystem(bais);
assertFalse(pfsNew.getRoot().hasEntry("Macros"));
try { pfsNew.close();
pfsNew.getRoot().getEntry("Macros");
fail();
} catch(FileNotFoundException e) {
// Good, as expected
}
// But if we write out with nodes preserved, will be there // But if we write out with nodes preserved, will be there
baos = new ByteArrayOutputStream(); baos.reset();
hssC.write(baos, true); hssC.write(baos, true);
pfsNew = new POIFSFileSystem( bais = new ByteArrayInputStream(baos.toByteArray());
new ByteArrayInputStream(baos.toByteArray()) ); pfsNew = new POIFSFileSystem(bais);
assertNotNull( pfsNew.getRoot().getEntry("Macros") ); assertTrue( pfsNew.getRoot().hasEntry("Macros") );
pfsNew.close();
} }
/** /**
* Ensure that simply opening a slideshow (usermodel) view of it * Ensure that simply opening a slideshow (usermodel) view of it
* doesn't change things * doesn't change things
*/ */
@Test
public void testSlideShowWritesOutTheSame() throws Exception { public void testSlideShowWritesOutTheSame() throws Exception {
assertSlideShowWritesOutTheSame(hssA, pfsA); assertSlideShowWritesOutTheSame(hssA, pfsA);
@ -130,8 +136,10 @@ public final class TestReWrite extends TestCase {
// We need to identify and fix that first // We need to identify and fix that first
//assertSlideShowWritesOutTheSame(hssB, pfsB); //assertSlideShowWritesOutTheSame(hssB, pfsB);
} }
public void assertSlideShowWritesOutTheSame(HSLFSlideShowImpl hss, POIFSFileSystem pfs) throws Exception {
public void assertSlideShowWritesOutTheSame(HSLFSlideShowImpl hss, POIFSFileSystem pfs) throws IOException {
// Create a slideshow covering it // Create a slideshow covering it
@SuppressWarnings("resource")
HSLFSlideShow ss = new HSLFSlideShow(hss); HSLFSlideShow ss = new HSLFSlideShow(hss);
ss.getSlides(); ss.getSlides();
ss.getNotes(); ss.getNotes();
@ -161,17 +169,23 @@ public final class TestReWrite extends TestCase {
System.out.println(i + "\t" + Integer.toHexString(i)); System.out.println(i + "\t" + Integer.toHexString(i));
assertEquals(_oData[i], _nData[i]); assertEquals(_oData[i], _nData[i]);
} }
npfs.close();
} }
public void test48593() throws Exception { @Test
HSLFSlideShow slideShow = new HSLFSlideShow(); public void test48593() throws IOException {
slideShow.createSlide(); HSLFSlideShow ppt1 = new HSLFSlideShow();
slideShow = HSLFTestDataSamples.writeOutAndReadBack(slideShow); ppt1.createSlide();
slideShow.createSlide(); HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
slideShow = HSLFTestDataSamples.writeOutAndReadBack(slideShow); ppt2.createSlide();
slideShow.createSlide(); HSLFSlideShow ppt3 = HSLFTestDataSamples.writeOutAndReadBack(ppt2);
slideShow = HSLFTestDataSamples.writeOutAndReadBack(slideShow); ppt3.createSlide();
slideShow.createSlide(); HSLFSlideShow ppt4 = HSLFTestDataSamples.writeOutAndReadBack(ppt3);
slideShow = HSLFTestDataSamples.writeOutAndReadBack(slideShow); ppt4.createSlide();
HSLFTestDataSamples.writeOutAndReadBack(ppt4).close();
ppt4.close();
ppt3.close();
ppt2.close();
ppt1.close();
} }
} }

View File

@ -18,40 +18,44 @@
package org.apache.poi.hslf.record; package org.apache.poi.hslf.record;
import junit.framework.TestCase; import static org.junit.Assert.assertEquals;
import org.junit.Test;
/** /**
* Tests that RecordTypes returns the right records and classes when asked * Tests that RecordTypes returns the right records and classes when asked
*
* @author Nick Burch (nick at torchbox dot com)
*/ */
public final class TestRecordTypes extends TestCase { public final class TestRecordTypes {
@Test
public void testPPTNameLookups() { public void testPPTNameLookups() {
assertEquals("MainMaster", RecordTypes.recordName(1016)); assertEquals("MainMaster", RecordTypes.MainMaster.name());
assertEquals("TextBytesAtom", RecordTypes.recordName(4008)); assertEquals("TextBytesAtom", RecordTypes.TextBytesAtom.name());
assertEquals("VBAInfo", RecordTypes.recordName(1023)); assertEquals("VBAInfo", RecordTypes.VBAInfo.name());
} }
@Test
public void testEscherNameLookups() { public void testEscherNameLookups() {
assertEquals("EscherDggContainer", RecordTypes.recordName(0xf000)); assertEquals("EscherDggContainer", RecordTypes.EscherDggContainer.name());
assertEquals("EscherClientTextbox", RecordTypes.recordName(0xf00d)); assertEquals("EscherClientTextbox", RecordTypes.EscherClientTextbox.name());
assertEquals("EscherSelection", RecordTypes.recordName(0xf119)); assertEquals("EscherSelection", RecordTypes.EscherSelection.name());
} }
@Test
public void testPPTClassLookups() { public void testPPTClassLookups() {
assertEquals(Slide.class, RecordTypes.recordHandlingClass(1006)); assertEquals(Slide.class, RecordTypes.Slide.handlingClass);
assertEquals(TextCharsAtom.class, RecordTypes.recordHandlingClass(4000)); assertEquals(TextCharsAtom.class, RecordTypes.TextCharsAtom.handlingClass);
assertEquals(TextBytesAtom.class, RecordTypes.recordHandlingClass(4008)); assertEquals(TextBytesAtom.class, RecordTypes.TextBytesAtom.handlingClass);
assertEquals(SlideListWithText.class, RecordTypes.recordHandlingClass(4080)); assertEquals(SlideListWithText.class, RecordTypes.SlideListWithText.handlingClass);
// If this record is ever implemented, change to one that isn't! // If this record is ever implemented, change to one that isn't!
// This is checking the "unhandled default" stuff works // This is checking the "unhandled default" stuff works
assertEquals(UnknownRecordPlaceholder.class, RecordTypes.recordHandlingClass(2019)); assertEquals(UnknownRecordPlaceholder.class, RecordTypes.forTypeID(-10).handlingClass);
} }
@Test
public void testEscherClassLookups() { public void testEscherClassLookups() {
// Should all come back with null, as DDF handles them // Should all come back with null, as DDF handles them
assertEquals(null, RecordTypes.recordHandlingClass(0xf000)); assertEquals(null, RecordTypes.EscherDggContainer.handlingClass);
assertEquals(null, RecordTypes.recordHandlingClass(0xf001)); assertEquals(null, RecordTypes.EscherBStoreContainer.handlingClass);
} }
} }

View File

@ -20,6 +20,7 @@ package org.apache.poi.hslf.usermodel;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.awt.Color; import java.awt.Color;
@ -42,7 +43,9 @@ import org.apache.poi.hslf.exceptions.OldPowerPointFormatException;
import org.apache.poi.hslf.extractor.PowerPointExtractor; import org.apache.poi.hslf.extractor.PowerPointExtractor;
import org.apache.poi.hslf.model.HeadersFooters; import org.apache.poi.hslf.model.HeadersFooters;
import org.apache.poi.hslf.record.Document; import org.apache.poi.hslf.record.Document;
import org.apache.poi.hslf.record.OEPlaceholderAtom;
import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
import org.apache.poi.hslf.record.SlideListWithText; import org.apache.poi.hslf.record.SlideListWithText;
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet; import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
import org.apache.poi.hslf.record.TextHeaderAtom; import org.apache.poi.hslf.record.TextHeaderAtom;
@ -50,6 +53,7 @@ import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.PictureData.PictureType; import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.Slide; import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.sl.usermodel.SlideShow; import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.SlideShowFactory; import org.apache.poi.sl.usermodel.SlideShowFactory;
@ -777,6 +781,31 @@ public final class TestBugs {
ex.close(); ex.close();
} }
@Test
public void bug58159() throws IOException {
File sample = HSLFTestDataSamples.getSampleFile("bug58159_headers-and-footers.ppt");
HSLFSlideShow ppt = (HSLFSlideShow)SlideShowFactory.create(sample);
HeadersFooters hf = ppt.getSlideHeadersFooters();
assertNull(hf.getHeaderText());
assertEquals("Slide footer", hf.getFooterText());
hf = ppt.getNotesHeadersFooters();
assertEquals("Notes header", hf.getHeaderText());
assertEquals("Notes footer", hf.getFooterText());
HSLFSlide sl = ppt.getSlides().get(0);
hf = sl.getHeadersFooters();
assertNull(hf.getHeaderText());
assertEquals("Slide footer", hf.getFooterText());
for (HSLFShape shape : sl.getShapes()) {
if (shape instanceof HSLFTextShape) {
HSLFTextShape ts = (HSLFTextShape)shape;
Placeholder ph = ts.getPlaceholder();
if (Placeholder.FOOTER == ph) {
assertEquals("Slide footer", ts.getText());
}
}
}
ppt.close();
}
private static HSLFSlideShow open(String fileName) throws IOException { private static HSLFSlideShow open(String fileName) throws IOException {
File sample = HSLFTestDataSamples.getSampleFile(fileName); File sample = HSLFTestDataSamples.getSampleFile(fileName);

View File

@ -42,12 +42,11 @@ public final class TestNumberedList {
@Test @Test
public void testNumberedList() throws Exception { public void testNumberedList() throws Exception {
HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("numbers.ppt")); HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("numbers.ppt"));
assertTrue("No Exceptions while reading file", true);
final List<HSLFSlide> slides = ppt.getSlides(); final List<HSLFSlide> slides = ppt.getSlides();
assertEquals(2, slides.size()); assertEquals(2, slides.size());
checkSlide0(slides.get(0)); checkSlide0(slides.get(0));
checkSlide1(slides.get(1)); checkSlide1(slides.get(1));
ppt.close();
} }
private void checkSlide0(final HSLFSlide s) { private void checkSlide0(final HSLFSlide s) {