improved handling of StyleTextPropAtom bit masks, added more read-write roundtrip tests
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@691180 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d3f7cc38ef
commit
7c1b5604d9
@ -35,19 +35,19 @@ public class CharFlagsTextProp extends BitMaskTextProp {
|
||||
public static String NAME = "char_flags";
|
||||
public CharFlagsTextProp() {
|
||||
super(2,0xffff, NAME, new String[] {
|
||||
"bold", // 0x0001
|
||||
"italic", // 0x0002
|
||||
"underline", // 0x0004
|
||||
"char_unknown_1",// 0x0008
|
||||
"shadow", // 0x0010
|
||||
"char_unknown_2",// 0x0020
|
||||
"char_unknown_3",// 0x0040
|
||||
"char_unknown_4",// 0x0080
|
||||
"strikethrough", // 0x0100
|
||||
"relief", // 0x0200
|
||||
"reset_numbering", // 0x0400
|
||||
"enable_numbering_1", // 0x0800
|
||||
"enable_numbering_2", // 0x1000
|
||||
"bold", // 0x0001 A bit that specifies whether the characters are bold.
|
||||
"italic", // 0x0002 A bit that specifies whether the characters are italicized.
|
||||
"underline", // 0x0004 A bit that specifies whether the characters are underlined.
|
||||
"char_unknown_1", // 0x0008 Undefined and MUST be ignored.
|
||||
"shadow", // 0x0010 A bit that specifies whether the characters have a shadow effect.
|
||||
"fehint", // 0x0020 A bit that specifies whether characters originated from double-byte input.
|
||||
"char_unknown_2", // 0x0040 Undefined and MUST be ignored.
|
||||
"kumi", // 0x0080 A bit that specifies whether Kumimoji are used for vertical text.
|
||||
"strikethrough", // 0x0100 Undefined and MUST be ignored.
|
||||
"emboss", // 0x0200 A bit that specifies whether the characters are embossed.
|
||||
"char_unknown_3", // 0x0400 Undefined and MUST be ignored.
|
||||
"char_unknown_4", // 0x0800 Undefined and MUST be ignored.
|
||||
"char_unknown_5", // 0x1000 Undefined and MUST be ignored.
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ public class TextPropCollection {
|
||||
private int charactersCovered;
|
||||
private short reservedField;
|
||||
private LinkedList textPropList;
|
||||
private int maskSpecial = 0;
|
||||
|
||||
/** Fetch the number of characters this styling applies to */
|
||||
public int getCharactersCovered() { return charactersCovered; }
|
||||
@ -94,20 +95,27 @@ public class TextPropCollection {
|
||||
// If we do, decode that, save it, and shuffle on
|
||||
for(int i=0; i<potentialProperties.length; i++) {
|
||||
// Check there's still data left to read
|
||||
if(dataOffset+bytesPassed >= data.length) {
|
||||
// Out of data, can't be any more properties to go
|
||||
return bytesPassed;
|
||||
}
|
||||
|
||||
// Check if this property is found in the mask
|
||||
if((containsField & potentialProperties[i].getMask()) != 0) {
|
||||
if(dataOffset+bytesPassed >= data.length) {
|
||||
// Out of data, can't be any more properties to go
|
||||
// remember the mask and return
|
||||
maskSpecial |= potentialProperties[i].getMask();
|
||||
return bytesPassed;
|
||||
}
|
||||
|
||||
// Bingo, data contains this property
|
||||
TextProp prop = (TextProp)potentialProperties[i].clone();
|
||||
int val = 0;
|
||||
if(prop.getSize() == 2) {
|
||||
val = LittleEndian.getShort(data,dataOffset+bytesPassed);
|
||||
} else {
|
||||
} else if(prop.getSize() == 4){
|
||||
val = LittleEndian.getInt(data,dataOffset+bytesPassed);
|
||||
} else if (prop.getSize() == 0){
|
||||
//remember "special" bits.
|
||||
maskSpecial |= potentialProperties[i].getMask();
|
||||
continue;
|
||||
}
|
||||
prop.setValue(val);
|
||||
bytesPassed += prop.getSize();
|
||||
@ -161,14 +169,17 @@ public class TextPropCollection {
|
||||
}
|
||||
|
||||
// Then the mask field
|
||||
int mask = 0;
|
||||
int mask = maskSpecial;
|
||||
for(int i=0; i<textPropList.size(); i++) {
|
||||
TextProp textProp = (TextProp)textPropList.get(i);
|
||||
//sometimes header indicates that the bitmask is present but its value is 0
|
||||
if (textProp instanceof BitMaskTextProp)
|
||||
mask |= (textProp.getWriteMask() == 0 ? 1 : textProp.getWriteMask());
|
||||
else
|
||||
|
||||
if (textProp instanceof BitMaskTextProp) {
|
||||
if(mask == 0) mask |= textProp.getWriteMask();
|
||||
}
|
||||
else {
|
||||
mask |= textProp.getWriteMask();
|
||||
}
|
||||
}
|
||||
StyleTextPropAtom.writeLittleEndian(mask,o);
|
||||
|
||||
@ -178,7 +189,7 @@ public class TextPropCollection {
|
||||
int val = textProp.getValue();
|
||||
if(textProp.getSize() == 2) {
|
||||
StyleTextPropAtom.writeLittleEndian((short)val,o);
|
||||
} else {
|
||||
} else if(textProp.getSize() == 4){
|
||||
StyleTextPropAtom.writeLittleEndian(val,o);
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +124,10 @@ public class StyleTextPropAtom extends RecordAtom
|
||||
|
||||
/** All the different kinds of paragraph properties we might handle */
|
||||
public static TextProp[] paragraphTextPropTypes = new TextProp[] {
|
||||
new TextProp(0, 0x1, "hasBullet"),
|
||||
new TextProp(0, 0x2, "hasBulletFont"),
|
||||
new TextProp(0, 0x4, "hasBulletColor"),
|
||||
new TextProp(0, 0x8, "hasBulletSize"),
|
||||
new ParagraphFlagsTextProp(),
|
||||
new TextProp(2, 0x80, "bullet.char"),
|
||||
new TextProp(2, 0x10, "bullet.font"),
|
||||
@ -131,35 +135,38 @@ public class StyleTextPropAtom extends RecordAtom
|
||||
new TextProp(4, 0x20, "bullet.color"),
|
||||
new AlignmentTextProp(),
|
||||
new TextProp(2, 0x100, "text.offset"),
|
||||
new TextProp(2, 0x200, "para_unknown_2"),
|
||||
new TextProp(2, 0x400, "bullet.offset"),
|
||||
new TextProp(2, 0x1000, "linespacing"),
|
||||
new TextProp(2, 0x2000, "spacebefore"),
|
||||
new TextProp(2, 0x4000, "spaceafter"),
|
||||
new TextProp(2, 0x8000, "para_unknown_4"),
|
||||
new TextProp(2, 0x10000, "para_unknown_5"),
|
||||
new TextProp(2, 0xA0000, "para_unknown_6"),
|
||||
new TextProp(2, 0x200000, "para_unknown_7")
|
||||
new TextProp(2, 0x8000, "defaultTabSize"),
|
||||
new TextProp(2, 0x100000, "tabStops"),
|
||||
new TextProp(2, 0x10000, "fontAlign"),
|
||||
new TextProp(2, 0xA0000, "wrapFlags"),
|
||||
new TextProp(2, 0x200000, "textDirection")
|
||||
};
|
||||
/** All the different kinds of character properties we might handle */
|
||||
public static TextProp[] characterTextPropTypes = new TextProp[] {
|
||||
new TextProp(0, 0x1, "bold"),
|
||||
new TextProp(0, 0x2, "italic"),
|
||||
new TextProp(0, 0x4, "underline"),
|
||||
new TextProp(0, 0x8, "unused1"),
|
||||
new TextProp(0, 0x10, "shadow"),
|
||||
new TextProp(0, 0x20, "fehint"),
|
||||
new TextProp(0, 0x40, "unused2"),
|
||||
new TextProp(0, 0x80, "kumi"),
|
||||
new TextProp(0, 0x100, "unused3"),
|
||||
new TextProp(0, 0x200, "emboss"),
|
||||
new CharFlagsTextProp(),
|
||||
new TextProp(2, 0x10000, "font.index"),
|
||||
new TextProp(2, 0x200000, "asian_or_complex"),
|
||||
new TextProp(2, 0x400000, "char_unknown_2"),
|
||||
new TextProp(2, 0x800000, "symbol"),
|
||||
new TextProp(0, 0x100000, "pp10ext"),
|
||||
new TextProp(2, 0x200000, "asian.font.index"),
|
||||
new TextProp(2, 0x400000, "ansi.font.index"),
|
||||
new TextProp(2, 0x800000, "symbol.font.index"),
|
||||
new TextProp(2, 0x20000, "font.size"),
|
||||
new TextProp(4, 0x40000, "font.color"),
|
||||
new TextProp(2, 0x80000, "superscript"),
|
||||
new TextProp(2, 0x100000, "char_unknown_1"),
|
||||
new TextProp(2, 0x1000000, "char_unknown_3"),
|
||||
new TextProp(2, 0x2000000, "char_unknown_4"),
|
||||
new TextProp(2, 0x4000000, "char_unknown_5"),
|
||||
new TextProp(2, 0x8000000, "char_unknown_6"),
|
||||
new TextProp(2, 0x10000000, "char_unknown_7"),
|
||||
new TextProp(2, 0x20000000, "char_unknown_8"),
|
||||
new TextProp(2, 0x40000000, "char_unknown_9"),
|
||||
new TextProp(2, 0x80000000, "char_unknown_10"),
|
||||
|
||||
};
|
||||
|
||||
/* *************** record code follows ********************** */
|
||||
@ -269,8 +276,7 @@ public class StyleTextPropAtom extends RecordAtom
|
||||
textHandled += textLen;
|
||||
pos += 4;
|
||||
|
||||
// Fetch the 2 byte value that is safe to ignore as 0
|
||||
short paraIgn = LittleEndian.getShort(rawContents,pos);
|
||||
short indent = LittleEndian.getShort(rawContents,pos);
|
||||
pos += 2;
|
||||
|
||||
// Grab the 4 byte value that tells us what properties follow
|
||||
@ -278,7 +284,7 @@ public class StyleTextPropAtom extends RecordAtom
|
||||
pos += 4;
|
||||
|
||||
// Now make sense of those properties
|
||||
TextPropCollection thisCollection = new TextPropCollection(textLen, paraIgn);
|
||||
TextPropCollection thisCollection = new TextPropCollection(textLen, indent);
|
||||
int plSize = thisCollection.buildTextPropList(
|
||||
paraFlags, paragraphTextPropTypes, rawContents, pos);
|
||||
pos += plSize;
|
||||
|
@ -31,6 +31,7 @@ import org.apache.poi.util.HexDump;
|
||||
import junit.framework.TestCase;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Tests that StyleTextPropAtom works properly
|
||||
@ -642,60 +643,6 @@ public class TestStyleTextPropAtom extends TestCase {
|
||||
stpa.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertEquals(data_b.length, b.length);
|
||||
for(int i=0; i<data_b.length; i++) {
|
||||
System.out.println(i + "\t" + b[i] + "\t" + data_b[i] + "\t" + Integer.toHexString(b[i]) );
|
||||
assertEquals(data_b[i],b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void testWriteA() throws Exception {
|
||||
StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
stpa.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertEquals(data_a.length, b.length);
|
||||
for(int i=0; i<data_a.length; i++) {
|
||||
assertEquals(data_a[i],b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void testLoadWriteA() throws Exception {
|
||||
StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
|
||||
stpa.setParentTextSize(data_a_text_len);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
stpa.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertEquals(data_a.length, b.length);
|
||||
for(int i=0; i<data_a.length; i++) {
|
||||
assertEquals(data_a[i],b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testWriteB() throws Exception {
|
||||
StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
stpb.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertEquals(data_b.length, b.length);
|
||||
for(int i=0; i<data_b.length; i++) {
|
||||
assertEquals(data_b[i],b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void testLoadWriteB() throws Exception {
|
||||
StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
|
||||
stpb.setParentTextSize(data_b_text_len);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
stpb.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertEquals(data_b.length, b.length);
|
||||
for(int i=0; i<data_b.length; i++) {
|
||||
//System.out.println(i + "\t" + b[i] + "\t" + data_b[i] + "\t" + Integer.toHexString(b[i]) );
|
||||
@ -703,6 +650,47 @@ public class TestStyleTextPropAtom extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testWriteA() throws Exception {
|
||||
doReadWrite(data_a, -1);
|
||||
}
|
||||
|
||||
public void testLoadWriteA() throws Exception {
|
||||
doReadWrite(data_b, data_b_text_len);
|
||||
}
|
||||
|
||||
|
||||
public void testWriteB() throws Exception {
|
||||
doReadWrite(data_b, -1);
|
||||
}
|
||||
|
||||
public void testLoadWriteB() throws Exception {
|
||||
doReadWrite(data_b, data_b_text_len);
|
||||
}
|
||||
|
||||
public void testLoadWriteC() throws Exception {
|
||||
doReadWrite(data_c, data_c_text_len);
|
||||
}
|
||||
|
||||
public void testLoadWriteD() throws Exception {
|
||||
doReadWrite(data_d, data_d_text_len);
|
||||
}
|
||||
|
||||
protected void doReadWrite(byte[] data, int textlen) throws Exception {
|
||||
StyleTextPropAtom stpb = new StyleTextPropAtom(data, 0,data.length);
|
||||
if(textlen != -1) stpb.setParentTextSize(textlen);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
stpb.writeOut(out);
|
||||
byte[] bytes = out.toByteArray();
|
||||
|
||||
assertEquals(data.length, bytes.length);
|
||||
try {
|
||||
assertTrue(Arrays.equals(data, bytes));
|
||||
} catch (Throwable e){
|
||||
//print hex dump if failed
|
||||
assertEquals(HexDump.toHex(data), HexDump.toHex(bytes));
|
||||
}
|
||||
}
|
||||
|
||||
public void testNotEnoughDataProp() throws Exception {
|
||||
// We don't have enough data in the record to cover
|
||||
@ -732,8 +720,8 @@ public class TestStyleTextPropAtom extends TestCase {
|
||||
assertEquals(1, chprops.findByName("char_flags").getValue());
|
||||
assertEquals(1, chprops.findByName("font.index").getValue());
|
||||
assertEquals(20, chprops.findByName("font.size").getValue());
|
||||
assertEquals(0, chprops.findByName("asian_or_complex").getValue());
|
||||
assertEquals(1, chprops.findByName("char_unknown_2").getValue());
|
||||
assertEquals(0, chprops.findByName("asian.font.index").getValue());
|
||||
assertEquals(1, chprops.findByName("ansi.font.index").getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -747,16 +735,7 @@ public class TestStyleTextPropAtom extends TestCase {
|
||||
0x00 , 0x00 , 0x13 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x63 , 0x00 ,
|
||||
0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x0F , 0x00
|
||||
};
|
||||
StyleTextPropAtom stpa = new StyleTextPropAtom(data,0,data.length);
|
||||
stpa.setParentTextSize(length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
stpa.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertEquals(data.length, b.length);
|
||||
for(int i=0; i<data.length; i++) {
|
||||
assertEquals(data[i],b[i]);
|
||||
}
|
||||
doReadWrite(data, length);
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user