diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java b/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java index 5117d5f1fd..ebb03446e9 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java @@ -84,7 +84,7 @@ public class RecordTypes { public static final Type TextCharsAtom = new Type(4000,TextCharsAtom.class); public static final Type StyleTextPropAtom = new Type(4001,StyleTextPropAtom.class); public static final Type BaseTextPropAtom = new Type(4002,null); - public static final Type TxMasterStyleAtom = new Type(4003,null); + public static final Type TxMasterStyleAtom = new Type(4003,TxMasterStyleAtom.class); public static final Type TxCFStyleAtom = new Type(4004,null); public static final Type TxPFStyleAtom = new Type(4005,null); public static final Type TextRulerAtom = new Type(4006,null); diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java index 4399cc3689..17d2101f04 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java @@ -93,9 +93,9 @@ public class StyleTextPropAtom extends RecordAtom new TextProp(4, 0x20, "bullet.color"), new TextProp(2, 0x40, "bullet.size"), new TextProp(2, 0x80, "bullet.char"), - new TextProp(2, 0x100, "para_unknown_1"), + new TextProp(2, 0x100, "text.offset"), new TextProp(2, 0x200, "para_unknown_2"), - new TextProp(2, 0x400, "para_unknown_3"), + new TextProp(2, 0x400, "bullet.offset"), new AlignmentTextProp(), // 0x800 new TextProp(2, 0x1000, "linespacing"), new TextProp(2, 0x2000, "spacebefore"), @@ -348,7 +348,7 @@ public class StyleTextPropAtom extends RecordAtom * Used to hold the number of characters affected, the list of active * properties, and the random reserved field if required. */ - public class TextPropCollection { + public static class TextPropCollection { private int charactersCovered; private short reservedField; private LinkedList textPropList; @@ -445,7 +445,7 @@ public class StyleTextPropAtom extends RecordAtom * Create a new collection of text properties (be they paragraph * or character) for a run of text without any */ - private TextPropCollection(int textSize) { + public TextPropCollection(int textSize) { charactersCovered = textSize; reservedField = -1; textPropList = new LinkedList(); @@ -511,7 +511,7 @@ public class StyleTextPropAtom extends RecordAtom /** * Generate the definition of a given type of text property. */ - private TextProp(int sizeOfDataBlock, int maskInHeader, String propName) { + public TextProp(int sizeOfDataBlock, int maskInHeader, String propName) { this.sizeOfDataBlock = sizeOfDataBlock; this.maskInHeader = maskInHeader; this.propName = propName; @@ -580,7 +580,7 @@ public class StyleTextPropAtom extends RecordAtom /** Fetch the list of if the sub properties match or not */ public boolean[] getSubPropMatches() { return subPropMatches; } - private BitMaskTextProp(int sizeOfDataBlock, int maskInHeader, String overallName, String[] subPropNames) { + public BitMaskTextProp(int sizeOfDataBlock, int maskInHeader, String overallName, String[] subPropNames) { super(sizeOfDataBlock,maskInHeader,"bitmask"); this.subPropNames = subPropNames; this.propName = overallName; @@ -679,7 +679,7 @@ public class StyleTextPropAtom extends RecordAtom public static final int ENABLE_NUMBERING_1_IDX = 11; public static final int ENABLE_NUMBERING_2_IDX = 12; - private CharFlagsTextProp() { + public CharFlagsTextProp() { super(2,0xffff, "char_flags", new String[] { "bold", // 0x0001 "italic", // 0x0002 diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java new file mode 100644 index 0000000000..062238a1b0 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java @@ -0,0 +1,213 @@ + +/* ==================================================================== + Copyright 2002-2004 Apache Software Foundation + + Licensed 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.OutputStream; +import java.io.IOException; +import org.apache.poi.hslf.record.StyleTextPropAtom.*; + +/** + * TxMasterStyleAtom atom (4003). + *
+ * Stores default character and paragraph styles. + * The atom instance value is the text type and is encoded like the txstyle field in + * TextHeaderAtom. The text styles are located in the MainMaster container, + * except for the "other" style, which is in the Document.Environment container. + *
+ *+ * This atom can store up to 5 pairs of paragraph+character styles, + * each pair describes an indent level. The first pair describes + * first-level paragraph with no indentation. + *
+ * + * @author Yegor Kozlov + */ +public class TxMasterStyleAtom extends RecordAtom { + + /** + * Maximum number of indentatio levels allowed in PowerPoint documents + */ + private static final int MAX_INDENT = 5; + + private byte[] _header; + private static long _type = 4003; + private byte[] _data; + + private TextPropCollection[] prstyles; + private TextPropCollection[] chstyles; + + protected TxMasterStyleAtom(byte[] source, int start, int len) { + _header = new byte[8]; + System.arraycopy(source,start,_header,0,8); + + _data = new byte[len-8]; + System.arraycopy(source,start+8,_data,0,_data.length); + + //read available styles + try { + init(); + } catch (Exception e){ + e.printStackTrace(); + } + } + + /** + * We are of type 4003 + * + * @return type of this record + * @see RecordTypes.TxMasterStyleAtom + */ + public long getRecordType() { + return _type; + } + + /** + * Write the contents of the record back, so it can be written + * to disk + */ + public void writeOut(OutputStream out) throws IOException { + // Write out the (new) header + out.write(_header); + + // Write out the record data + out.write(_data); + + } + + /** + * Returns array of character styles defined in this record. + * + * @return character styles defined in this record + */ + public TextPropCollection[] getCharacterStyles(){ + return chstyles; + } + + /** + * Returns array of paragraph styles defined in this record. + * + * @return paragraph styles defined in this record + */ + public TextPropCollection[] getParagraphStyles(){ + return prstyles; + } + + /** + * Return type of the text. + * Must be a constant defined inTextHeaderAtom
+ *
+ * @return type of the text
+ * @see TextHeaderAtom
+ */
+ public int getTextType(){
+ //The atom instance value is the text type
+ return LittleEndian.getShort(_header, 0) >> 4;
+ }
+
+ /**
+ * parse the record data and initialize styles
+ */
+ protected void init(){
+ //type of the text
+ int type = getTextType();
+
+ int head;
+ int pos = 0;
+
+ //number of indentation levels
+ short levels = LittleEndian.getShort(_data, 0);
+ pos += LittleEndian.SHORT_SIZE;
+
+ prstyles = new TextPropCollection[levels];
+ chstyles = new TextPropCollection[levels];
+
+ for(short j = 0; j < levels; j++) {
+
+ if (type >= TextHeaderAtom.CENTRE_BODY_TYPE) {
+ // Fetch the 2 byte value, that is safe to ignore for some types of text
+ short val = LittleEndian.getShort(_data, pos);
+ pos += LittleEndian.SHORT_SIZE;
+ }
+
+ head = LittleEndian.getInt(_data, pos);
+ pos += LittleEndian.INT_SIZE;
+ TextPropCollection prprops = new TextPropCollection(0);
+ pos += prprops.buildTextPropList( head, getParagraphProps(type, j), _data, pos);
+ prstyles[j] = prprops;
+
+ head = LittleEndian.getInt(_data, pos);
+ pos += LittleEndian.INT_SIZE;
+ TextPropCollection chprops = new TextPropCollection(0);
+ pos += chprops.buildTextPropList( head, getCharacterProps(type, j), _data, pos);
+ chstyles[j] = chprops;
+ }
+
+ }
+
+ /**
+ * Paragraph properties for the specified text type and indent level
+ */
+ protected TextProp[] getParagraphProps(int type, int level){
+ if (level != 0 || type >= MAX_INDENT){
+ return StyleTextPropAtom.paragraphTextPropTypes;
+ } else {
+ return new TextProp[] {
+ new BitMaskTextProp(2, 0xF, "paragraph_flags", new String[] {
+ "bullet", "bullet.hardfont",
+ "bullet.hardcolor", "bullet.hardsize"}
+ ),
+ new TextProp(2, 0x80, "bullet.char"),
+ new TextProp(2, 0x10, "bullet.font"),
+ new TextProp(2, 0x40, "bullet.size"),
+ new TextProp(4, 0x20, "bullet.color"),
+ new TextProp(2, 0xD00, "alignment"),
+ new TextProp(2, 0x1000, "linespacing"),
+ new TextProp(2, 0x2000, "spacebefore"),
+ new TextProp(2, 0x4000, "spaceafter"),
+ new TextProp(2, 0x8000, "text.offset"),
+ new TextProp(2, 0x10000, "bullet.offset"),
+ new TextProp(2, 0x20000, "defaulttab"),
+ new TextProp(2, 0x40000, "para_unknown_2"),
+ new TextProp(2, 0x80000, "para_unknown_3"),
+ new TextProp(2, 0x100000, "para_unknown_4"),
+ new TextProp(2, 0x200000, "para_unknown_5")
+ };
+ }
+ }
+
+ /**
+ * Character properties for the specified text type and indent level
+ */
+ protected TextProp[] getCharacterProps(int type, int level){
+ if (level != 0 || type >= MAX_INDENT){
+ return StyleTextPropAtom.characterTextPropTypes;
+ } else
+ return new TextProp[] {
+ new CharFlagsTextProp(),
+ new TextProp(2, 0x10000, "font.index"),
+ new TextProp(2, 0x20000, "char_unknown_1"),
+ new TextProp(4, 0x40000, "char_unknown_2"),
+ new TextProp(2, 0x80000, "font.size"),
+ new TextProp(2, 0x100000, "char_unknown_3"),
+ new TextProp(4, 0x200000, "font.color"),
+ new TextProp(2, 0x800000, "char_unknown_4")
+ };
+ }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTxMasterStyleAtom.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTxMasterStyleAtom.java
new file mode 100644
index 0000000000..92c95990e3
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTxMasterStyleAtom.java
@@ -0,0 +1,233 @@
+
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.hslf.record;
+
+import junit.framework.TestCase;
+import org.apache.poi.hslf.usermodel.SlideShow;
+import org.apache.poi.hslf.record.StyleTextPropAtom.*;
+
+import java.util.ArrayList;
+
+
+/**
+ * Test TestTxMasterStyleAtom
record.
+ * Check master style for the empty ppt which is created
+ * by the default constructor of SlideShow
+ *
+ * @author Yegor Kozlov
+ */
+public class TestTxMasterStyleAtom extends TestCase {
+ protected SlideShow _ppt;
+
+ public void setUp() throws Exception{
+ _ppt = new SlideShow();
+
+ }
+
+ public void testDefaultStyles() {
+ TxMasterStyleAtom[] txmaster = getMasterStyles();
+ for (int i = 0; i < txmaster.length; i++) {
+ int txtype = txmaster[i].getTextType();
+ switch (txtype){
+ case TextHeaderAtom.TITLE_TYPE:
+ checkTitleType(txmaster[i]);
+ break;
+ case TextHeaderAtom.BODY_TYPE:
+ checkBodyType(txmaster[i]);
+ break;
+ case TextHeaderAtom.NOTES_TYPE:
+ checkNotesType(txmaster[i]);
+ break;
+ case TextHeaderAtom.OTHER_TYPE:
+ checkOtherType(txmaster[i]);
+ break;
+ case TextHeaderAtom.CENTRE_BODY_TYPE:
+ break;
+ case TextHeaderAtom.CENTER_TITLE_TYPE:
+ break;
+ case TextHeaderAtom.HALF_BODY_TYPE:
+ break;
+ case TextHeaderAtom.QUARTER_BODY_TYPE:
+ break;
+ default:
+ fail("Unknown text type: " + txtype);
+ }
+
+ }
+ }
+
+
+
+ /**
+ * Test styles for type=TextHeaderAtom.TITLE_TYPE
+ */
+ private void checkTitleType(TxMasterStyleAtom txmaster){
+ TextPropCollection props;
+ TextProp prop;
+
+ //paragraph styles
+ props = txmaster.getParagraphStyles()[0];
+
+ prop = props.findByName("alignment");
+ assertEquals(1, prop.getValue()); //title has center alignment
+
+ //character styles
+ props = txmaster.getCharacterStyles()[0];
+
+ prop = props.findByName("font.color");
+ assertEquals(0x3000000, prop.getValue());
+
+ prop = props.findByName("font.index");
+ assertEquals(0, prop.getValue());
+
+ prop = props.findByName("font.size");
+ assertEquals(49, prop.getValue());
+
+ }
+
+ /**
+ * Test styles for type=TextHeaderAtom.BODY_TYPE
+ */
+ private void checkBodyType(TxMasterStyleAtom txmaster){
+ TextPropCollection props;
+ TextProp prop;
+
+ TextPropCollection[] prstyles = txmaster.getParagraphStyles();
+ TextPropCollection[] chstyles = txmaster.getCharacterStyles();
+ assertEquals("TxMasterStyleAtom for TextHeaderAtom.BODY_TYPE " +
+ "must contain styles for 5 indentation levels", 5, prstyles.length);
+ assertEquals("TxMasterStyleAtom for TextHeaderAtom.BODY_TYPE " +
+ "must contain styles for 5 indentation levels", 5, chstyles.length);
+
+ //paragraph styles
+ props = prstyles[0];
+
+ prop = props.findByName("alignment");
+ assertEquals(0, prop.getValue());
+
+
+ for (int i = 0; i < prstyles.length; i++) {
+ assertNotNull("text.offset is null for indentation level " + i, prstyles[i].findByName("text.offset"));
+ assertNotNull("bullet.offset is null for indentation level " + i, prstyles[i].findByName("bullet.offset"));
+ }
+
+ //character styles
+ props = chstyles[0];
+
+ prop = props.findByName("font.color");
+ assertEquals(0x1000000, prop.getValue());
+
+ prop = props.findByName("font.index");
+ assertEquals(0, prop.getValue());
+
+ prop = props.findByName("font.size");
+ assertEquals(36, prop.getValue());
+ }
+
+ /**
+ * Test styles for type=TextHeaderAtom.OTHER_TYPE
+ */
+ private void checkOtherType(TxMasterStyleAtom txmaster){
+ TextPropCollection props;
+ TextProp prop;
+
+ //paragraph styles
+ props = txmaster.getParagraphStyles()[0];
+
+ prop = props.findByName("alignment");
+ assertEquals(0, prop.getValue());
+
+ //character styles
+ props = txmaster.getCharacterStyles()[0];
+
+ prop = props.findByName("font.color");
+ assertEquals(0x1000000, prop.getValue());
+
+ prop = props.findByName("font.index");
+ assertEquals(0, prop.getValue());
+
+ prop = props.findByName("font.size");
+ assertEquals(24, prop.getValue());
+ }
+
+ /**
+ * Test styles for type=TextHeaderAtom.NOTES_TYPE
+ */
+ private void checkNotesType(TxMasterStyleAtom txmaster){
+ TextPropCollection props;
+ TextProp prop;
+
+ //paragraph styles
+ props = txmaster.getParagraphStyles()[0];
+
+ prop = props.findByName("alignment");
+ assertEquals(0, prop.getValue()); //title has center alignment
+
+ //character styles
+ props = txmaster.getCharacterStyles()[0];
+
+ prop = props.findByName("font.color");
+ assertEquals(0x1000000, prop.getValue());
+
+ prop = props.findByName("font.index");
+ assertEquals(0, prop.getValue());
+
+ prop = props.findByName("font.size");
+ assertEquals(12, prop.getValue());
+
+ }
+
+ /**
+ * Collect all TxMasterStyleAtom records contained in the supplied slide show.
+ * There must be a TxMasterStyleAtom per each type of text defined in TextHeaderAtom
+ */
+ protected TxMasterStyleAtom[] getMasterStyles(){
+ ArrayList lst = new ArrayList();
+
+ Record[] core = _ppt.getMostRecentCoreRecords();
+ for (int i = 0; i < core.length; i++) {
+ if(core[i].getRecordType() == RecordTypes.MainMaster.typeID){
+ Record[] rec = core[i].getChildRecords();
+ int cnt = 0;
+ for (int j = 0; j < rec.length; j++) {
+ if (rec[j] instanceof TxMasterStyleAtom) {
+ lst.add(rec[j]);
+ cnt++;
+ }
+ }
+ assertEquals("MainMaster must contain 7 TxMasterStyleAtoms ", 7, cnt);
+ } else if(core[i].getRecordType() == RecordTypes.Document.typeID){
+ TxMasterStyleAtom txstyle = null;
+ Document doc = (Document)core[i];
+ Record[] rec = doc.getEnvironment().getChildRecords();
+ for (int j = 0; j < rec.length; j++) {
+ if (rec[j] instanceof TxMasterStyleAtom) {
+ if (txstyle != null) fail("Document.Environment must contain 1 TxMasterStyleAtom");
+ txstyle = (TxMasterStyleAtom)rec[j];
+ }
+ }
+ assertNotNull("TxMasterStyleAtom not found in Document.Environment", txstyle);
+
+ assertEquals("Document.Environment must contain TxMasterStyleAtom with type=TextHeaderAtom.OTHER_TYPE",
+ TextHeaderAtom.OTHER_TYPE, txstyle.getTextType());
+ lst.add(txstyle);
+ }
+ }
+
+ return (TxMasterStyleAtom[])lst.toArray(new TxMasterStyleAtom[lst.size()]);
+ }
+}