|
|
@@ -20,6 +20,7 @@ package org.apache.poi.hslf.model.textproperties; |
|
|
|
import java.io.*; |
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
import org.apache.poi.hslf.exceptions.HSLFException; |
|
|
|
import org.apache.poi.hslf.record.StyleTextPropAtom; |
|
|
|
import org.apache.poi.util.HexDump; |
|
|
|
import org.apache.poi.util.LittleEndian; |
|
|
@@ -32,7 +33,7 @@ import org.apache.poi.util.LittleEndian; |
|
|
|
*/ |
|
|
|
public class TextPropCollection { |
|
|
|
/** All the different kinds of paragraph properties we might handle */ |
|
|
|
public static final TextProp[] paragraphTextPropTypes = { |
|
|
|
private static final TextProp[] paragraphTextPropTypes = { |
|
|
|
// TextProp order is according to 2.9.20 TextPFException, |
|
|
|
// bitmask order can be different |
|
|
|
new ParagraphFlagsTextProp(), |
|
|
@@ -60,7 +61,7 @@ public class TextPropCollection { |
|
|
|
}; |
|
|
|
|
|
|
|
/** All the different kinds of character properties we might handle */ |
|
|
|
public static final TextProp[] characterTextPropTypes = new TextProp[] { |
|
|
|
private static final TextProp[] characterTextPropTypes = new TextProp[] { |
|
|
|
new TextProp(0, 0x100000, "pp10ext"), |
|
|
|
new TextProp(0, 0x1000000, "newAsian.font.index"), // A bit that specifies whether the newEAFontRef field of the TextCFException10 structure that contains this CFMasks exists. |
|
|
|
new TextProp(0, 0x2000000, "cs.font.index"), // A bit that specifies whether the csFontRef field of the TextCFException10 structure that contains this CFMasks exists. |
|
|
@@ -84,7 +85,7 @@ public class TextPropCollection { |
|
|
|
// indentLevel is only valid for paragraph collection |
|
|
|
// if it's set to -1, it must be omitted - see 2.9.36 TextMasterStyleLevel |
|
|
|
private short indentLevel = 0; |
|
|
|
private final List<TextProp> textPropList = new ArrayList<TextProp>(); |
|
|
|
private final Map<String,TextProp> textProps = new HashMap<String,TextProp>(); |
|
|
|
private int maskSpecial = 0; |
|
|
|
private final TextPropType textPropType; |
|
|
|
|
|
|
@@ -98,101 +99,89 @@ public class TextPropCollection { |
|
|
|
this.textPropType = textPropType; |
|
|
|
} |
|
|
|
|
|
|
|
public int getSpecialMask() { return maskSpecial; } |
|
|
|
public int getSpecialMask() { |
|
|
|
return maskSpecial; |
|
|
|
} |
|
|
|
|
|
|
|
/** Fetch the number of characters this styling applies to */ |
|
|
|
public int getCharactersCovered() { return charactersCovered; } |
|
|
|
/** Fetch the TextProps that define this styling */ |
|
|
|
public List<TextProp> getTextPropList() { return textPropList; } |
|
|
|
public int getCharactersCovered() { |
|
|
|
return charactersCovered; |
|
|
|
} |
|
|
|
|
|
|
|
/** Fetch the TextProps that define this styling in the record order */ |
|
|
|
public List<TextProp> getTextPropList() { |
|
|
|
List<TextProp> orderedList = new ArrayList<TextProp>(); |
|
|
|
for (TextProp potProp : getPotentialProperties()) { |
|
|
|
TextProp textProp = textProps.get(potProp.getName()); |
|
|
|
if (textProp != null) { |
|
|
|
orderedList.add(textProp); |
|
|
|
} |
|
|
|
} |
|
|
|
return orderedList; |
|
|
|
} |
|
|
|
|
|
|
|
/** Fetch the TextProp with this name, or null if it isn't present */ |
|
|
|
public TextProp findByName(String textPropName) { |
|
|
|
for(TextProp prop : textPropList) { |
|
|
|
if(prop.getName().equals(textPropName)) { |
|
|
|
return prop; |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
public final TextProp findByName(String textPropName) { |
|
|
|
return textProps.get(textPropName); |
|
|
|
} |
|
|
|
|
|
|
|
public TextProp removeByName(String name) { |
|
|
|
Iterator<TextProp> iter = textPropList.iterator(); |
|
|
|
TextProp tp = null; |
|
|
|
while (iter.hasNext()) { |
|
|
|
tp = iter.next(); |
|
|
|
if (tp.getName().equals(name)){ |
|
|
|
iter.remove(); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
return tp; |
|
|
|
public final TextProp removeByName(String name) { |
|
|
|
return textProps.remove(name); |
|
|
|
} |
|
|
|
|
|
|
|
/** Add the TextProp with this name to the list */ |
|
|
|
public TextProp addWithName(String name) { |
|
|
|
// Find the base TextProp to base on |
|
|
|
TextProp existing = findByName(name); |
|
|
|
if (existing != null) return existing; |
|
|
|
|
|
|
|
TextProp base = null; |
|
|
|
for (TextProp tp : getPotentialProperties()) { |
|
|
|
if (tp.getName().equals(name)) { |
|
|
|
base = tp; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if(base == null) { |
|
|
|
throw new IllegalArgumentException("No TextProp with name " + name + " is defined to add from. " |
|
|
|
+ "Character and paragraphs have their own properties/names."); |
|
|
|
} |
|
|
|
|
|
|
|
// Add a copy of this property, in the right place to the list |
|
|
|
TextProp textProp = base.clone(); |
|
|
|
addProp(textProp); |
|
|
|
return textProp; |
|
|
|
} |
|
|
|
|
|
|
|
public TextPropType getTextPropType() { |
|
|
|
public final TextPropType getTextPropType() { |
|
|
|
return textPropType; |
|
|
|
} |
|
|
|
|
|
|
|
private TextProp[] getPotentialProperties() { |
|
|
|
return (textPropType == TextPropType.paragraph) ? paragraphTextPropTypes : characterTextPropTypes; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Checks the paragraph or character properties for the given property name. |
|
|
|
* Throws a HSLFException, if the name doesn't belong into this set of properties |
|
|
|
* |
|
|
|
* @param name the property name |
|
|
|
* @return if found, the property template to copy from |
|
|
|
*/ |
|
|
|
private TextProp validatePropName(String name) { |
|
|
|
for (TextProp tp : getPotentialProperties()) { |
|
|
|
if (tp.getName().equals(name)) { |
|
|
|
return tp; |
|
|
|
} |
|
|
|
} |
|
|
|
String errStr = |
|
|
|
"No TextProp with name " + name + " is defined to add from. " + |
|
|
|
"Character and paragraphs have their own properties/names."; |
|
|
|
throw new HSLFException(errStr); |
|
|
|
} |
|
|
|
|
|
|
|
/** Add the TextProp with this name to the list */ |
|
|
|
public final TextProp addWithName(String name) { |
|
|
|
// Find the base TextProp to base on |
|
|
|
TextProp existing = findByName(name); |
|
|
|
if (existing != null) return existing; |
|
|
|
|
|
|
|
// Add a copy of this property |
|
|
|
TextProp textProp = validatePropName(name).clone(); |
|
|
|
textProps.put(name,textProp); |
|
|
|
return textProp; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Add the property at the correct position. Replaces an existing property with the same name. |
|
|
|
* |
|
|
|
* @param textProp the property to be added |
|
|
|
*/ |
|
|
|
public void addProp(TextProp textProp) { |
|
|
|
assert(textProp != null); |
|
|
|
|
|
|
|
int pos = 0; |
|
|
|
boolean found = false; |
|
|
|
for (TextProp curProp : getPotentialProperties()) { |
|
|
|
String potName = curProp.getName(); |
|
|
|
if (pos == textPropList.size() || potName.equals(textProp.getName())) { |
|
|
|
if (textPropList.size() > pos && potName.equals(textPropList.get(pos).getName())) { |
|
|
|
// replace existing prop (with same name) |
|
|
|
textPropList.set(pos, textProp); |
|
|
|
} else { |
|
|
|
textPropList.add(pos, textProp); |
|
|
|
} |
|
|
|
found = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (potName.equals(textPropList.get(pos).getName())) { |
|
|
|
pos++; |
|
|
|
} |
|
|
|
} |
|
|
|
public final void addProp(TextProp textProp) { |
|
|
|
if (textProp == null) { |
|
|
|
throw new HSLFException("TextProp must not be null"); |
|
|
|
} |
|
|
|
|
|
|
|
if(!found) { |
|
|
|
String err = "TextProp with name " + textProp.getName() + " doesn't belong to this collection."; |
|
|
|
throw new IllegalArgumentException(err); |
|
|
|
} |
|
|
|
String propName = textProp.getName(); |
|
|
|
validatePropName(propName); |
|
|
|
|
|
|
|
textProps.put(propName, textProp); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@@ -254,8 +243,8 @@ public class TextPropCollection { |
|
|
|
this.charactersCovered = other.charactersCovered; |
|
|
|
this.indentLevel = other.indentLevel; |
|
|
|
this.maskSpecial = other.maskSpecial; |
|
|
|
this.textPropList.clear(); |
|
|
|
for (TextProp tp : other.textPropList) { |
|
|
|
this.textProps.clear(); |
|
|
|
for (TextProp tp : other.textProps.values()) { |
|
|
|
TextProp tpCopy = (tp instanceof BitMaskTextProp) |
|
|
|
? ((BitMaskTextProp)tp).cloneAll() |
|
|
|
: tp.clone(); |
|
|
@@ -285,25 +274,22 @@ public class TextPropCollection { |
|
|
|
|
|
|
|
// Then the mask field |
|
|
|
int mask = maskSpecial; |
|
|
|
for (TextProp textProp : textPropList) { |
|
|
|
for (TextProp textProp : textProps.values()) { |
|
|
|
mask |= textProp.getWriteMask(); |
|
|
|
} |
|
|
|
StyleTextPropAtom.writeLittleEndian(mask,o); |
|
|
|
|
|
|
|
// Then the contents of all the properties |
|
|
|
for (TextProp potProp : getPotentialProperties()) { |
|
|
|
for(TextProp textProp : textPropList) { |
|
|
|
if (!textProp.getName().equals(potProp.getName())) continue; |
|
|
|
int val = textProp.getValue(); |
|
|
|
if (textProp instanceof BitMaskTextProp && textProp.getWriteMask() == 0) { |
|
|
|
// don't add empty properties, as they can't be recognized while reading |
|
|
|
continue; |
|
|
|
} else if (textProp.getSize() == 2) { |
|
|
|
StyleTextPropAtom.writeLittleEndian((short)val,o); |
|
|
|
} else if (textProp.getSize() == 4) { |
|
|
|
StyleTextPropAtom.writeLittleEndian(val,o); |
|
|
|
} |
|
|
|
} |
|
|
|
for (TextProp textProp : getTextPropList()) { |
|
|
|
int val = textProp.getValue(); |
|
|
|
if (textProp instanceof BitMaskTextProp && textProp.getWriteMask() == 0) { |
|
|
|
// don't add empty properties, as they can't be recognized while reading |
|
|
|
continue; |
|
|
|
} else if (textProp.getSize() == 2) { |
|
|
|
StyleTextPropAtom.writeLittleEndian((short)val,o); |
|
|
|
} else if (textProp.getSize() == 4) { |
|
|
|
StyleTextPropAtom.writeLittleEndian(val,o); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -324,7 +310,7 @@ public class TextPropCollection { |
|
|
|
result = prime * result + charactersCovered; |
|
|
|
result = prime * result + maskSpecial; |
|
|
|
result = prime * result + indentLevel; |
|
|
|
result = prime * result + ((textPropList == null) ? 0 : textPropList.hashCode()); |
|
|
|
result = prime * result + ((textProps == null) ? 0 : textProps.hashCode()); |
|
|
|
return result; |
|
|
|
} |
|
|
|
/** |
|
|
@@ -340,21 +326,7 @@ public class TextPropCollection { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
if (textPropList == null) { |
|
|
|
return (o.textPropList == null); |
|
|
|
} |
|
|
|
|
|
|
|
Map<String,TextProp> m = new HashMap<String,TextProp>(); |
|
|
|
for (TextProp tp : o.textPropList) { |
|
|
|
m.put(tp.getName(), tp); |
|
|
|
} |
|
|
|
|
|
|
|
for (TextProp tp : this.textPropList) { |
|
|
|
TextProp otp = m.get(tp.getName()); |
|
|
|
if (!tp.equals(otp)) return false; |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
return textProps.equals(o.textProps); |
|
|
|
} |
|
|
|
|
|
|
|
public String toString() { |