Yegor's TxMasterStyleAtom code from Bug #40057

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@423129 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2006-07-18 16:44:57 +00:00
parent bc74b9a09f
commit 9356b01d88
4 changed files with 454 additions and 8 deletions

View File

@ -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);

View File

@ -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

View File

@ -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).
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*
* @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 in <code>TextHeaderAtom</code>
*
* @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")
};
}
}

View File

@ -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 <code>TestTxMasterStyleAtom</code> record.
* Check master style for the empty ppt which is created
* by the default constructor of <code>SlideShow</code>
*
* @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()]);
}
}