From 695b85049da6695f2d6dc8a811aa6d21e91b2aaa Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Sun, 6 Jul 2008 12:11:37 +0000 Subject: [PATCH] Merged revisions 668156-671000 via svnmerge from https://svn.apache.org/repos/asf/poi/trunk ........ r668257 | yegor | 2008-06-16 19:38:59 +0100 (Mon, 16 Jun 2008) | 1 line TextShape.getMarginLeft() returned incorrect value. Added a unit test for text margins. ........ r668259 | yegor | 2008-06-16 19:40:51 +0100 (Mon, 16 Jun 2008) | 1 line patch from bug #45177: Remove GPL reference in NOTICE ........ r669140 | nick | 2008-06-18 12:35:04 +0100 (Wed, 18 Jun 2008) | 1 line A partial fix for bug #30978, but something still remains, which seems to be related to changing the ptg ........ r669456 | nick | 2008-06-19 12:47:48 +0100 (Thu, 19 Jun 2008) | 1 line Improved HWPF Range.replaceText, from N. Hira in bug #45001 ........ r669658 | josh | 2008-06-19 20:07:20 +0100 (Thu, 19 Jun 2008) | 1 line Fix for bug 45234 - Removed incorrect shared formula conversion in CFRuleRecord ........ r669809 | josh | 2008-06-20 08:10:03 +0100 (Fri, 20 Jun 2008) | 1 line Fix for bug 30978 - small re-arrangement of class Ptg hierarchy for DeletedRef3DPtg and DeletedArea3DPtg. Similar to c664220 ........ r670190 | yegor | 2008-06-21 13:41:34 +0100 (Sat, 21 Jun 2008) | 1 line started a new section for poi-3.2 family, updated release date of 3.2-FINAL ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@674287 13f79535-47bb-0310-9956-ffa450edef68 --- legal/NOTICE | 8 - src/documentation/content/xdocs/changes.xml | 8 +- src/documentation/content/xdocs/status.xml | 8 +- .../org/apache/poi/hssf/model/Workbook.java | 24 ++- .../apache/poi/hssf/record/CFRuleRecord.java | 191 +++++------------- .../apache/poi/hssf/record/NameRecord.java | 54 +---- .../poi/hssf/record/formula/Area3DPtg.java | 2 +- .../hssf/record/formula/DeletedArea3DPtg.java | 40 ++-- .../hssf/record/formula/DeletedRef3DPtg.java | 37 +++- .../poi/hssf/record/formula/Ref3DPtg.java | 2 +- .../hssf/usermodel/HSSFErrorConstants.java | 59 +----- .../HSSFSheetConditionalFormatting.java | 7 +- .../poi/ss/usermodel/ErrorConstants.java | 82 ++++++++ .../org/apache/poi/hslf/model/TextShape.java | 2 +- .../org/apache/poi/hwpf/usermodel/Range.java | 32 +-- .../org/apache/poi/hslf/data/text-margins.ppt | Bin 0 -> 44032 bytes .../apache/poi/hslf/model/TestTextShape.java | 43 ++++ .../poi/hwpf/data/testRangeReplacement.doc | Bin 0 -> 104448 bytes .../hwpf/usermodel/TestRangeReplacement.java | 119 +++++++++++ .../org/apache/poi/hssf/data/30978-alt.xls | Bin 0 -> 14848 bytes .../poi/hssf/record/TestCFRuleRecord.java | 54 +++++ .../apache/poi/hssf/usermodel/TestBugs.java | 62 ++++++ 22 files changed, 535 insertions(+), 299 deletions(-) create mode 100644 src/java/org/apache/poi/ss/usermodel/ErrorConstants.java create mode 100755 src/scratchpad/testcases/org/apache/poi/hslf/data/text-margins.ppt create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/data/testRangeReplacement.doc create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java create mode 100644 src/testcases/org/apache/poi/hssf/data/30978-alt.xls diff --git a/legal/NOTICE b/legal/NOTICE index d5d7883b3..848c767bc 100644 --- a/legal/NOTICE +++ b/legal/NOTICE @@ -10,14 +10,6 @@ Common Public License Version 1.0: http://www.opensource.org/licenses/cpl.php See http://www.junit.org/ -A single data file of the POI component HDGF is based on VSDump, - and is under the GNU General Public Licence version 3 (GPL v3): - http://gplv3.fsf.org/ -Since this is a data file, and has no compiled version (the original - file is distributed in both source and binary versions), there should - be little difference in licencing requirements compared to the ASL. -See http://www.gnome.ru/projects/vsdump_en.html - The Office Open XML experimental support had additional dependencies, with their own licensing: diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 43b373d04..561ab0d4d 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -45,7 +45,13 @@ Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx - + + + + + 30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d + 45234 - Removed incorrect shared formula conversion in CFRuleRecord + 45001 - Improved HWPF Range.replaceText() 44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size Support custom image renderers in HSLF Correctly increment the reference count of a blip when a picture is inserted diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 3ad07a216..ca47e0f20 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -42,7 +42,13 @@ Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx - + + + + + 30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d + 45234 - Removed incorrect shared formula conversion in CFRuleRecord + 45001 - Improved HWPF Range.replaceText() 44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size Support custom image renderers in HSLF Correctly increment the reference count of a blip when a picture is inserted diff --git a/src/java/org/apache/poi/hssf/model/Workbook.java b/src/java/org/apache/poi/hssf/model/Workbook.java index 5b38935f4..fa22cfb68 100644 --- a/src/java/org/apache/poi/hssf/model/Workbook.java +++ b/src/java/org/apache/poi/hssf/model/Workbook.java @@ -604,8 +604,28 @@ public class Workbook implements Model fixTabIdRecord(); } - // If we decide that we need to fix up - // NameRecords, do it here + // Within NameRecords, it's ok to have the formula + // part point at deleted sheets. It's also ok to + // have the ExternSheetNumber point at deleted + // sheets. + // However, the sheet index must be adjusted, or + // excel will break. (Sheet index is either 0 for + // global, or 1 based index to sheet) + int sheetNum1Based = sheetnum + 1; + for(int i=0; i sheetNum1Based) { + // Bump down by one, so still points + // at the same sheet + nr.setEqualsToIndexToSheet((short)( + nr.getEqualsToIndexToSheet()-1 + )); + } + } } /** diff --git a/src/java/org/apache/poi/hssf/record/CFRuleRecord.java b/src/java/org/apache/poi/hssf/record/CFRuleRecord.java index 2b1705abe..d000b5311 100644 --- a/src/java/org/apache/poi/hssf/record/CFRuleRecord.java +++ b/src/java/org/apache/poi/hssf/record/CFRuleRecord.java @@ -14,14 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; -import java.util.Stack; - import org.apache.poi.hssf.model.FormulaParser; -import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.record.cf.BorderFormatting; import org.apache.poi.hssf.record.cf.FontFormatting; import org.apache.poi.hssf.record.cf.PatternFormatting; @@ -30,7 +26,6 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.StringUtil; /** * Conditional Formatting Rule Record. @@ -59,9 +54,6 @@ public final class CFRuleRecord extends Record private byte field_2_comparison_operator; - private short field_3_formula1_len; - private short field_4_formula2_len; - private int field_5_options; private static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot @@ -121,8 +113,6 @@ public final class CFRuleRecord extends Record { field_1_condition_type=conditionType; field_2_comparison_operator=comparisonOperation; - field_3_formula1_len = (short)0; - field_4_formula2_len = (short)0; // Set modification flags to 1: by default options are not modified field_5_options = modificationBits.setValue(field_5_options, -1); @@ -147,8 +137,8 @@ public final class CFRuleRecord extends Record this(conditionType, comparisonOperation); field_1_condition_type = CONDITION_TYPE_CELL_VALUE_IS; field_2_comparison_operator = comparisonOperation; - setParsedExpression1(formula1); - setParsedExpression2(formula2); + field_17_formula1 = formula1; + field_18_formula2 = formula2; } /** @@ -167,63 +157,38 @@ public final class CFRuleRecord extends Record Ptg[] formula1 = parseFormula(formulaText1, workbook); Ptg[] formula2 = parseFormula(formulaText2, workbook); return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2); - } - /** - * Constructs a Formula record and sets its fields appropriately. - * Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an - * "explanation of this bug in the documentation) or an exception - * will be throw upon validation - * - * @param in the RecordInputstream to read the record from - */ - - public CFRuleRecord(RecordInputStream in) - { + public CFRuleRecord(RecordInputStream in) { super(in); } - - protected void fillFields(RecordInputStream in) { - try { - field_1_condition_type = in.readByte(); - field_2_comparison_operator = in.readByte(); - field_3_formula1_len = in.readShort(); - field_4_formula2_len = in.readShort(); - field_5_options = in.readInt(); - field_6_not_used = in.readShort(); + field_1_condition_type = in.readByte(); + field_2_comparison_operator = in.readByte(); + int field_3_formula1_len = in.readUShort(); + int field_4_formula2_len = in.readUShort(); + field_5_options = in.readInt(); + field_6_not_used = in.readShort(); - if (containsFontFormattingBlock()) { - fontFormatting = new FontFormatting(in); - } - - if (containsBorderFormattingBlock()) { - borderFormatting = new BorderFormatting(in); - } - - if (containsPatternFormattingBlock()) { - patternFormatting = new PatternFormatting(in); - } - - if (field_3_formula1_len > 0) { - Stack ptgs = Ptg.createParsedExpressionTokens(field_3_formula1_len, in); - // Now convert any fields as required - ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0); - field_17_formula1 = toArray(ptgs); - } - if (field_4_formula2_len > 0) { - Stack ptgs = Ptg.createParsedExpressionTokens(field_4_formula2_len, in); - - // Now convert any fields as required - ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0); - field_18_formula2 = toArray(ptgs); - } - } catch (java.lang.UnsupportedOperationException uoe) { - throw new RecordFormatException(uoe); + if (containsFontFormattingBlock()) { + fontFormatting = new FontFormatting(in); } + if (containsBorderFormattingBlock()) { + borderFormatting = new BorderFormatting(in); + } + + if (containsPatternFormattingBlock()) { + patternFormatting = new PatternFormatting(in); + } + + if (field_3_formula1_len > 0) { + field_17_formula1 = Ptg.readTokens(field_3_formula1_len, in); + } + if (field_4_formula2_len > 0) { + field_18_formula2 = Ptg.readTokens(field_4_formula2_len, in); + } } public byte getConditionType() @@ -323,24 +288,6 @@ public final class CFRuleRecord extends Record } - /** - * get the length (in number of tokens) of the expression 1 - * @return expression length - */ - private short getExpression1Length() - { - return field_3_formula1_len; - } - - - /** - * get the length (in number of tokens) of the expression 2 - * @return expression length - */ - private short getExpression2Length() - { - return field_4_formula2_len; - } /** * get the option flags * @@ -489,16 +436,6 @@ public final class CFRuleRecord extends Record return field_18_formula2; } - private void setParsedExpression1(Ptg[] ptgs) { - short len = getTotalPtgSize(field_17_formula1 = ptgs); - field_3_formula1_len = len; - } - - private void setParsedExpression2(Ptg[] ptgs) { - short len = getTotalPtgSize(field_18_formula2 = ptgs); - field_4_formula2_len = len; - } - /** * called by constructor, should throw runtime exception in the event of a * record passed with a differing ID. @@ -519,6 +456,17 @@ public final class CFRuleRecord extends Record return sid; } + /** + * @param ptgs may be null + * @return encoded size of the formula + */ + private static int getFormulaSize(Ptg[] ptgs) { + if (ptgs == null) { + return 0; + } + return Ptg.getEncodedSize(ptgs); + } + /** * called by the class that is responsible for writing this sucker. * Subclasses should implement this so that their data is passed back in a @@ -528,18 +476,20 @@ public final class CFRuleRecord extends Record * @param data byte array containing instance data * @return number of bytes written */ - public int serialize(int pOffset, byte [] data) { + int formula1Len=getFormulaSize(field_17_formula1); + int formula2Len=getFormulaSize(field_18_formula2); + int offset = pOffset; int recordsize = getRecordSize(); LittleEndian.putShort(data, 0 + offset, sid); LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4)); data[4 + offset] = field_1_condition_type; data[5 + offset] = field_2_comparison_operator; - LittleEndian.putShort(data, 6 + offset, field_3_formula1_len); - LittleEndian.putShort(data, 8 + offset, field_4_formula2_len); + LittleEndian.putUShort(data, 6 + offset, formula1Len); + LittleEndian.putUShort(data, 8 + offset, formula2Len); LittleEndian.putInt(data, 10 + offset, field_5_options); LittleEndian.putShort(data,14 + offset, field_6_not_used); @@ -562,16 +512,12 @@ public final class CFRuleRecord extends Record offset += patternFormatting.serialize(offset, data); } - if (getExpression1Length()>0) - { - Ptg.serializePtgStack(convertToTokenStack(field_17_formula1), data, offset); - offset += getExpression1Length(); + if (field_17_formula1 != null) { + offset += Ptg.serializePtgs(field_17_formula1, data, offset); } - if (getExpression2Length()>0) - { - Ptg.serializePtgStack(convertToTokenStack(field_18_formula2), data, offset); - offset += getExpression2Length(); + if (field_18_formula2 != null) { + offset += Ptg.serializePtgs(field_18_formula2, data, offset); } if(offset - pOffset != recordsize) { throw new IllegalStateException("write mismatch (" + (offset - pOffset) + "!=" + recordsize + ")"); @@ -586,24 +532,12 @@ public final class CFRuleRecord extends Record (containsFontFormattingBlock()?fontFormatting.getRawRecord().length:0)+ (containsBorderFormattingBlock()?8:0)+ (containsPatternFormattingBlock()?4:0)+ - getExpression1Length()+ - getExpression2Length() + getFormulaSize(field_17_formula1)+ + getFormulaSize(field_18_formula2) ; return retval; } - private short getTotalPtgSize(Ptg[] ptgs) - { - if( ptgs == null) { - return 0; - } - short retval = 0; - for (int i = 0; i < ptgs.length; i++) - { - retval += ptgs[i].getSize(); - } - return retval; - } public String toString() { @@ -629,8 +563,6 @@ public final class CFRuleRecord extends Record public Object clone() { CFRuleRecord rec = new CFRuleRecord(field_1_condition_type, field_2_comparison_operator); - rec.field_3_formula1_len = field_3_formula1_len; - rec.field_4_formula2_len = field_4_formula2_len; rec.field_5_options = field_5_options; rec.field_6_not_used = field_6_not_used; if (containsFontFormattingBlock()) { @@ -642,10 +574,10 @@ public final class CFRuleRecord extends Record if (containsPatternFormattingBlock()) { rec.patternFormatting = (PatternFormatting) patternFormatting.clone(); } - if (field_3_formula1_len > 0) { + if (field_17_formula1 != null) { rec.field_17_formula1 = (Ptg[]) field_17_formula1.clone(); } - if (field_4_formula2_len > 0) { + if (field_18_formula2 != null) { rec.field_18_formula2 = (Ptg[]) field_18_formula2.clone(); } @@ -653,30 +585,17 @@ public final class CFRuleRecord extends Record } /** + * TODO - parse conditional format formulas properly i.e. produce tRefN and tAreaN instead of tRef and tArea + * this call will produce the wrong results if the formula contains any cell references + * One approach might be to apply the inverse of SharedFormulaRecord.convertSharedFormulas(Stack, int, int) + * Note - two extra parameters (rowIx & colIx) will be required. They probably come from one of the Region objects. + * * @return null if formula was null. */ - private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) - { + private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) { if(formula == null) { return null; } return FormulaParser.parse(formula, workbook); } - - // TODO - treat formulas as token arrays instead of Stacks throughout the rest of POI - private static Stack convertToTokenStack(Ptg[] ptgs) - { - Stack parsedExpression = new Stack(); - // fill the Ptg Stack with Ptgs of new formula - for (int k = 0; k < ptgs.length; k++) - { - parsedExpression.push(ptgs[ k ]); - } - return parsedExpression; - } - private static Ptg[] toArray(Stack ptgs) { - Ptg[] result = new Ptg[ptgs.size()]; - ptgs.toArray(result); - return result; - } } diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java index 786c0b3d6..dbd796991 100644 --- a/src/java/org/apache/poi/hssf/record/NameRecord.java +++ b/src/java/org/apache/poi/hssf/record/NameRecord.java @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; @@ -22,9 +21,8 @@ import java.util.Iterator; import java.util.List; import java.util.Stack; +import org.apache.poi.hssf.model.FormulaParser; import org.apache.poi.hssf.record.formula.Area3DPtg; -import org.apache.poi.hssf.record.formula.DeletedArea3DPtg; -import org.apache.poi.hssf.record.formula.DeletedRef3DPtg; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.Ref3DPtg; import org.apache.poi.hssf.record.formula.UnionPtg; @@ -44,8 +42,7 @@ import org.apache.poi.util.StringUtil; * @author Glen Stampoultzis (glens at apache.org) * @version 1.0-pre */ - -public class NameRecord extends Record { +public final class NameRecord extends Record { /** */ public final static short sid = 0x18; //Docs says that it is 0x218 @@ -650,50 +647,9 @@ public class NameRecord extends Record { /** gets the reference , the area only (range) * @return area reference */ - public String getAreaReference(HSSFWorkbook book){ - if (field_13_name_definition == null || field_13_name_definition.isEmpty()) return "Error"; - Ptg ptg = (Ptg) field_13_name_definition.peek(); - String result = ""; - - // If it's a union, descend in and process - if (ptg.getClass() == UnionPtg.class) { - Iterator it =field_13_name_definition.iterator(); - while( it.hasNext() ) { - Ptg p = (Ptg)it.next(); - - String thisRes = getAreaRefString(p, book); - if(thisRes.length() > 0) { - // Add a comma to the end if needed - if(result.length() > 0 && !result.endsWith(",")) { - result += ","; - } - // And add the string it corresponds to - result += thisRes; - } - } - } else { - // Otherwise just get the string - result = getAreaRefString(ptg, book); - } - - return result; - } - - /** - * Turn the given ptg into a string, or - * return an empty string if nothing is possible - * for it. - */ - private String getAreaRefString(Ptg ptg,HSSFWorkbook book) { - if (ptg.getClass() == Area3DPtg.class){ - return ptg.toFormulaString(book); - } else if (ptg.getClass() == Ref3DPtg.class){ - return ptg.toFormulaString(book); - } else if (ptg.getClass() == DeletedArea3DPtg.class || ptg.getClass() == DeletedRef3DPtg.class) { - return "#REF!"; - } - return ""; - } + public String getAreaReference(HSSFWorkbook book){ + return FormulaParser.toFormulaString(book, field_13_name_definition); + } /** sets the reference , the area only (range) * @param ref area reference diff --git a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java index 2804e37c3..8deaa919f 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java @@ -35,7 +35,7 @@ import org.apache.poi.util.LittleEndian; * @author Jason Height (jheight at chariot dot net dot au) * @version 1.0-pre */ -public class Area3DPtg extends OperandPtg implements AreaI { +public final class Area3DPtg extends OperandPtg implements AreaI { public final static byte sid = 0x3b; private final static int SIZE = 11; // 10 + 1 for Ptg private short field_1_index_extern_sheet; diff --git a/src/java/org/apache/poi/hssf/record/formula/DeletedArea3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/DeletedArea3DPtg.java index 36d7e1686..a1c5b3db5 100644 --- a/src/java/org/apache/poi/hssf/record/formula/DeletedArea3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/DeletedArea3DPtg.java @@ -18,6 +18,9 @@ package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.ss.usermodel.ErrorConstants; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.util.LittleEndian; /** * Title: Deleted Area 3D Ptg - 3D referecnce (Sheet + Area)

@@ -26,19 +29,30 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Patrick Luby * @version 1.0-pre */ - -public class DeletedArea3DPtg extends Area3DPtg -{ +public final class DeletedArea3DPtg extends OperandPtg { public final static byte sid = 0x3d; + private final int field_1_index_extern_sheet; + private final int unused1; + private final int unused2; - /** Creates new DeletedArea3DPtg */ - public DeletedArea3DPtg( String arearef, short externIdx ) - { - super(arearef, externIdx); - } - - public DeletedArea3DPtg( RecordInputStream in) - { - super(in); - } + public DeletedArea3DPtg( RecordInputStream in) { + field_1_index_extern_sheet = in.readUShort(); + unused1 = in.readInt(); + unused2 = in.readInt(); + } + public String toFormulaString(Workbook book) { + return ErrorConstants.getText(ErrorConstants.ERROR_REF); + } + public byte getDefaultOperandClass() { + return Ptg.CLASS_REF; + } + public int getSize() { + return 11; + } + public void writeBytes(byte[] data, int offset) { + LittleEndian.putByte(data, 0 + offset, sid + getPtgClass()); + LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet); + LittleEndian.putInt(data, 3 + offset, unused1); + LittleEndian.putInt(data, 7 + offset, unused2); + } } diff --git a/src/java/org/apache/poi/hssf/record/formula/DeletedRef3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/DeletedRef3DPtg.java index a3c780965..9312b2d76 100644 --- a/src/java/org/apache/poi/hssf/record/formula/DeletedRef3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/DeletedRef3DPtg.java @@ -15,11 +15,13 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.ss.usermodel.ErrorConstants; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.util.LittleEndian; /** * Title: Deleted Reference 3D Ptg

@@ -28,16 +30,29 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Patrick Luby * @version 1.0-pre */ +public final class DeletedRef3DPtg extends OperandPtg { + public final static byte sid = 0x3c; + private final int field_1_index_extern_sheet; + private final int unused1; -public class DeletedRef3DPtg extends Ref3DPtg { - public final static byte sid = 0x3c; + /** Creates new DeletedRef3DPtg */ + public DeletedRef3DPtg(RecordInputStream in) { + field_1_index_extern_sheet = in.readUShort(); + unused1 = in.readInt(); + } - /** Creates new DeletedRef3DPtg */ - public DeletedRef3DPtg(RecordInputStream in) { - super(in); - } - - public DeletedRef3DPtg(String cellref, short externIdx ) { - super(cellref, externIdx); - } + public String toFormulaString(Workbook book) { + return ErrorConstants.getText(ErrorConstants.ERROR_REF); + } + public byte getDefaultOperandClass() { + return Ptg.CLASS_REF; + } + public int getSize() { + return 7; + } + public void writeBytes(byte[] data, int offset) { + LittleEndian.putByte(data, 0 + offset, sid + getPtgClass()); + LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet); + LittleEndian.putInt(data, 3 + offset, unused1); + } } diff --git a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java index 0ec064581..52a5518e4 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java @@ -34,7 +34,7 @@ import org.apache.poi.util.LittleEndian; * @author Jason Height (jheight at chariot dot net dot au) * @version 1.0-pre */ -public class Ref3DPtg extends OperandPtg { +public final class Ref3DPtg extends OperandPtg { public final static byte sid = 0x3a; private final static int SIZE = 7; // 6 + 1 for Ptg private short field_1_index_extern_sheet; diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFErrorConstants.java b/src/java/org/apache/poi/hssf/usermodel/HSSFErrorConstants.java index 89c25d1e8..f82ee721d 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFErrorConstants.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFErrorConstants.java @@ -16,67 +16,12 @@ ==================================================================== */ package org.apache.poi.hssf.usermodel; +import org.apache.poi.ss.usermodel.ErrorConstants; /** * Contains raw Excel error codes (as defined in OOO's excelfileformat.pdf (2.5.6) * * @author Michael Harhen */ -public final class HSSFErrorConstants { - private HSSFErrorConstants() { - // no instances of this class - } - - /** #NULL! - Intersection of two cell ranges is empty */ - public static final int ERROR_NULL = 0x00; - /** #DIV/0! - Division by zero */ - public static final int ERROR_DIV_0 = 0x07; - /** #VALUE! - Wrong type of operand */ - public static final int ERROR_VALUE = 0x0F; - /** #REF! - Illegal or deleted cell reference */ - public static final int ERROR_REF = 0x17; - /** #NAME? - Wrong function or range name */ - public static final int ERROR_NAME = 0x1D; - /** #NUM! - Value range overflow */ - public static final int ERROR_NUM = 0x24; - /** #N/A - Argument or function not available */ - public static final int ERROR_NA = 0x2A; - - - /** - * @return Standard Excel error literal for the specified error code. - * @throws IllegalArgumentException if the specified error code is not one of the 7 - * standard error codes - */ - public static final String getText(int errorCode) { - switch(errorCode) { - case ERROR_NULL: return "#NULL!"; - case ERROR_DIV_0: return "#DIV/0!"; - case ERROR_VALUE: return "#VALUE!"; - case ERROR_REF: return "#REF!"; - case ERROR_NAME: return "#NAME?"; - case ERROR_NUM: return "#NUM!"; - case ERROR_NA: return "#N/A"; - } - throw new IllegalArgumentException("Bad error code (" + errorCode + ")"); - } - - /** - * @return true if the specified error code is a standard Excel error code. - */ - public static final boolean isValidCode(int errorCode) { - // This method exists because it would be bad to force clients to catch - // IllegalArgumentException if there were potential for passing an invalid error code. - switch(errorCode) { - case ERROR_NULL: - case ERROR_DIV_0: - case ERROR_VALUE: - case ERROR_REF: - case ERROR_NAME: - case ERROR_NUM: - case ERROR_NA: - return true; - } - return false; - } +public final class HSSFErrorConstants extends ErrorConstants { } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java index c042456a4..8e8cf40a1 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java @@ -39,7 +39,8 @@ public final class HSSFSheetConditionalFormatting { /** * A factory method allowing to create a conditional formatting rule - * with a cell comparison operator + * with a cell comparison operator

+ * TODO - formulas containing cell references are currently not parsed properly * * @param comparisonOperation - a constant value from * {@link HSSFConditionalFormattingRule.ComparisonOperator}:

@@ -72,8 +73,8 @@ public final class HSSFSheetConditionalFormatting { /** * A factory method allowing to create a conditional formatting rule with a formula.
* - * The formatting rules are applied by Excel when the value of the formula not equal to 0. - * + * The formatting rules are applied by Excel when the value of the formula not equal to 0.

+ * TODO - formulas containing cell references are currently not parsed properly * @param formula - formula for the valued, compared with the cell */ public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) { diff --git a/src/java/org/apache/poi/ss/usermodel/ErrorConstants.java b/src/java/org/apache/poi/ss/usermodel/ErrorConstants.java new file mode 100644 index 000000000..1bfa18452 --- /dev/null +++ b/src/java/org/apache/poi/ss/usermodel/ErrorConstants.java @@ -0,0 +1,82 @@ +/* ==================================================================== + 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.ss.usermodel; + +/** + * Contains raw Excel error codes (as defined in OOO's excelfileformat.pdf (2.5.6) + * + * @author Michael Harhen + */ +public class ErrorConstants { + protected ErrorConstants() { + // no instances of this class + } + + /** #NULL! - Intersection of two cell ranges is empty */ + public static final int ERROR_NULL = 0x00; + /** #DIV/0! - Division by zero */ + public static final int ERROR_DIV_0 = 0x07; + /** #VALUE! - Wrong type of operand */ + public static final int ERROR_VALUE = 0x0F; + /** #REF! - Illegal or deleted cell reference */ + public static final int ERROR_REF = 0x17; + /** #NAME? - Wrong function or range name */ + public static final int ERROR_NAME = 0x1D; + /** #NUM! - Value range overflow */ + public static final int ERROR_NUM = 0x24; + /** #N/A - Argument or function not available */ + public static final int ERROR_NA = 0x2A; + + + /** + * @return Standard Excel error literal for the specified error code. + * @throws IllegalArgumentException if the specified error code is not one of the 7 + * standard error codes + */ + public static final String getText(int errorCode) { + switch(errorCode) { + case ERROR_NULL: return "#NULL!"; + case ERROR_DIV_0: return "#DIV/0!"; + case ERROR_VALUE: return "#VALUE!"; + case ERROR_REF: return "#REF!"; + case ERROR_NAME: return "#NAME?"; + case ERROR_NUM: return "#NUM!"; + case ERROR_NA: return "#N/A"; + } + throw new IllegalArgumentException("Bad error code (" + errorCode + ")"); + } + + /** + * @return true if the specified error code is a standard Excel error code. + */ + public static final boolean isValidCode(int errorCode) { + // This method exists because it would be bad to force clients to catch + // IllegalArgumentException if there were potential for passing an invalid error code. + switch(errorCode) { + case ERROR_NULL: + case ERROR_DIV_0: + case ERROR_VALUE: + case ERROR_REF: + case ERROR_NAME: + case ERROR_NUM: + case ERROR_NA: + return true; + } + return false; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java index d1a84a5e4..44cb2b241 100755 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java @@ -355,7 +355,7 @@ public abstract class TextShape extends SimpleShape { */ public float getMarginLeft(){ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); - EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM); + EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT); int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue(); return (float)val/EMU_PER_POINT; } diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java index 6324cd86a..80e9b7526 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java @@ -635,27 +635,24 @@ public class Range /** * Replace (one instance of) a piece of text with another... * - * @param pPlaceHolder The text to be replaced (e.g., "${company}") - * @param pValue The replacement text (e.g., "Cognocys, Inc.") - * @param pDocument The HWPFDocument in which the placeholder was found - * @param pStartOffset The offset or index where the CharacterRun begins - * @param pPlaceHolderIndex The offset or index of the placeholder, - * relative to the CharacterRun where - * pPlaceHolder was found + * @param pPlaceHolder The text to be replaced (e.g., "${organization}") + * @param pValue The replacement text (e.g., "Apache Software Foundation") + * @param pOffset The offset or index where the text to be replaced begins + * (relative to/within this Range) */ - protected void replaceText(String pPlaceHolder, String pValue, - int pStartOffset, int pPlaceHolderIndex, HWPFDocument pDocument) { - int absPlaceHolderIndex = pStartOffset + pPlaceHolderIndex; + public void replaceText(String pPlaceHolder, String pValue, int pOffset) + { + int absPlaceHolderIndex = getStartOffset() + pOffset; Range subRange = new Range( absPlaceHolderIndex, - (absPlaceHolderIndex + pPlaceHolder.length()), pDocument + (absPlaceHolderIndex + pPlaceHolder.length()), getDocument() ); if (subRange.usesUnicode()) { - absPlaceHolderIndex = pStartOffset + (pPlaceHolderIndex * 2); + absPlaceHolderIndex = getStartOffset() + (pOffset * 2); subRange = new Range( absPlaceHolderIndex, (absPlaceHolderIndex + (pPlaceHolder.length() * 2)), - pDocument + getDocument() ); } @@ -665,13 +662,13 @@ public class Range subRange = new Range( (absPlaceHolderIndex + pValue.length()), (absPlaceHolderIndex + pPlaceHolder.length() + pValue.length()), - pDocument + getDocument() ); if (subRange.usesUnicode()) subRange = new Range( (absPlaceHolderIndex + (pValue.length() * 2)), (absPlaceHolderIndex + (pPlaceHolder.length() * 2) + - (pValue.length() * 2)), pDocument + (pValue.length() * 2)), getDocument() ); subRange.delete(); @@ -942,4 +939,9 @@ public class Range return _end; } + + protected HWPFDocument getDocument() { + + return _doc; + } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/text-margins.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/text-margins.ppt new file mode 100755 index 0000000000000000000000000000000000000000..cf539aea7414f0121c3dbbb68c52de2cb505cbbd GIT binary patch literal 44032 zcmeEvbzE0VxA%{bZjh92=@1Di0cixJ1f^TLRk}kOky08Yq!p!8Ksuy5loU{Dfp<0@ zpX1^9+;i@|?;rQR?-@R8&+OSVvuD=Kto5ClwSV;W;?Aa*lFq@-IT08F?Bo;`hV)ZB z90)7_xW|FPZhOXW{~`_?gSy`Qtq&1_e*qBG=g5Fi0HFdR0fY_+ z0}v)4EI`T4?4~PKJML>jrhyW1-LI6Yxhz!srK;(cZ08s*>0z?gn1`sVE zIzaS*7yvN>Vgker=rSM{K&*h+0I>t&0K^H13lKLT9zeW+t^nc#bQKUkAOS#vfP?^D z10)Pc1du2oF+k#gt^<+)Bne0g&<#M+fMfv40+ItH4@dzJG}e`V^P%wncBcxn1%FPU zFQi~Lz;}S%2d(@2ju4EPA3T5q*>J*rjFWHn;s&n5@?me7mwztFj!;L&pt~JT5kxjX z0|Pi^@OD?233x9QvN)>)73c|Dm=VkwW(}S|wfgst2?h@b4<19sLG}3eDSv;027)EA z-|sH~DF(gA8fI|Tc3JQ~Q}A|&vlu5(BU=#j?;Z4hXx{wb!M{)W$0w2yvw*wsr?&p* z>cbD-|Kr_%xBbxk{`%YdA@2wOe$0PpT>m`(A%6Wl|DosqFO2=4`S$;7I0AWjq*atG zw(4X>1dZkHEuSH+TKdzx_rezi>-~LG1n~x5(_WqDzxu>h31J*Da@d+3s$+os(p{%k*(0dc4uJzRrtS*QicdLBzm|F&37rR-#PzG-mkj zM83Mz#=#dFy+>~c53;Ua!pN<4=Y99^OM%67H7Ul&gClWIfi6NXgKm|u$>Dna>N;y} z*|A0CCsQEsMLL#F{H>gB_4JP7YIabGm{SA@EltcQ8$tr+jt)I2{$ zZ77-|(H4Ius4J2G=1Kj46M}9&gRUvlV?Gu$1@bnPOW6yzlC>~bMprt^hjMg2VaiDk zU)gQv89B=SR59ANJhh+NiJ~J^^PB@UPZssmP<+2=D{6n!nYv1MKgSu@ly%x})OR~X z3eO_GO54Y8)UMv_=rn30@>}d>!qiBwt9Hv9>$YH?ot`4Vl;sf+34j)c^e;7xPRFbI zJqR5Dg0!x&gCmErt*ecLi3_`%wUuOKqZ|Skfz;mhQ|cODq2vle@*KsmU@3cQr8VRl zrD=sgCEY-}SA+FeU-vC7>GmuYR%WiXCSG5^b}ylq0A+qWIYI|hFKFs691Vl9U#;1I zT{g-@_o8Wd_BK(`a?Q;b?KlzimL<%X*>R<>7CC#qiKSG(MGj(a>yyLZikT~Vf}Ty0 z)g1A~uhr)n+xy((%0W)P_uiL><(1#OB1dJ3|9_rTU?;&PdI5~e6>lr=e5MK z+HJ1oYpz?|)|ZH8l#xbVZ8B(u>hJ}K@$VdfgJ%PH;s+137jR8aK-=emxPp+zADxbb zt&Nk3jgy|*eLEA!yAW5D<^Na!*OZ>Y0LT>y3V=k}?~Vh+=sB2JIdZT=*Yg=M*h{uU zK&{|FE(q`Z?k)qd3H61exq+Ptc;&BNd%o{}&pii#*14WkmcIZ=W*8#)+X4Q<*&TT8 z7BmpDu&LnmkwS5>VYpkWP%>CEIus8HZ)7+;PHb2(J_K~IVWIdCAcDcFupywPclM_Y z)T`PV7z)FOU>Xcohz-HHpB**~b4&XyA{84_1rWhtY1q&kAPAO@4FNak4svJ!B7P4` zgGB%w0EZzVA)t@;&+>jxlaCFl4k#6*W}vzuZhZok#)F}qwdn%%3XmighQ8$nf?goq zCY(16<~R!7*hp?qf9Ls)5lT)U3;9l?Xq%O2SmU(hepHA`O_qu|5m4Bbum(sqkBw7|Hg+PFgG zq$qjH_9fYm3;xWMMjQyMn7eeg`Kub1n|N>3vI5`~r&NPdjqoBT+&wr$c)5dvn&$_y zVG_hI-o_~|t#?Jn&yOm9So91+CfmP!&->d;gTxdL{tvpJ2PN;x)EFxC@|$2<(8w>; z-^qIOjjT*d>CS#pdD1&Rhh!sL-qgaL{`(DLB*%K+j$(uwmrjC`el4xePqd$=R#sG_ zWiuy6;HF=#Uw^IrxCBY2l5K#lJaRRfj;w-Frxt_tOkEDA)(u;sRiZ_O1uVn(%gr1`KlSj#PYJK+F|6( zX}l>+!-~BE`gukaPS+nc`h3l?t`s~q6|2*SNS4t-z_>_d5nwip?Pxsn?k`(TOrXE7f1~MSy0d0 zkC9ygBXR+ZAxKo57Y>E$r%Dr?I452M(~Y0&@hh0EeS!(#w8yg0)Z>I3TJ6URBR0mA zMs~y9uyn1=gt7@N1`%ac93nQ|XFT?riJq)!M_s)7N|iga!~O{#d*bEG0=>(TLEHT# z^us=^VoV)8RdeyW5h7kyeR=N@!?P8gZxHpYR1B6{HQp;}lXDDtn9Y5K|4!0EP zPP2U~Y=X5muA_PBF;4!{9q$!xhCdmdvb2;@H+B*W@h83O`I3~F@xw~LL-~UTbW##d zt>~(D83sMFsV>@sZfH~$A%^l3^M0p|n#B9z;*?^vs#Bzo*tf9+;U=+iB@?Feba5*C zgUg(d630!yY9hR~zoXVFn92CUVyKO0H+>w3J8NxVXj4kC%3JL*{We9cF6CIZacuuw z2Q0Oy4aTe|)TEs5>LNn?;6flNW3%`G8DbP}$jH#!DxIR~@X&ofZcBd01XCGU&36C@v-b17O zp6&yWxSXDti-=ay{eDvg1IH4@Q*3VcBb7Y*8R`su1Mt+jiu_T~XL`QfNLcQ85u3Jf zd1XFzP@HH(`&4KtO7H0NC7-(-5~*>c9VEx9owRe>)xk8xFL@>3WREP2VkTWBy3UU% z@uE@TI-kmGZ1^gS8974!r-nIuvSL=)QN2-V%2(?&?hJk8j278^i^j334rf4* za!g?zyus~+!%X0ib32Wgr$d_$pYBUy&l6J0q@9{Zf0057%#YnxN30R0^UsJ}`8WJR z{jTw`WpUl&n%G#MFH7)+)4S1`Q)IbQ9$I18#gE_Jzb~THs;o~Jc_+vEz8xEIgNj( z>4ZpedMVEA^-GbouKTy=vnER4D;Rg0F4R_jp3#9r=B-)9#j+pbJhJo~dv$;JTTo8_ z{&b`Y!3&CGxL-}N?Kt}0K`^!cEf$iO2UsXz&-ax2PUBNWZFdZ#K^nvU>_NGa%2*-n zlt~QPai!B*BBH8mDb23?@oOE}tCCzhK5SiPNCfuecY0q06i~ zXZ6rBBpcnVXt|>M1s+N+9-EUuWcG00r*@;HfM~5M2Fb|VhE^}b+z4M&er-yS-Y7M@ zzigK^60y3u(XW$`WGNZD`mp?7sz_M34g`f>R$d+Kx6PsR->){Gttf*>osr7 zX^x=LYP4H9=HinrYOLbLp8pate*`k;)e%Vcllz5oIuB^h3+Uf-{{<2{FW!F7_;--d z`JVedclci;q40A^s06tW>(59Ch+Y^f{QoT^bmOdsKO>=ZY$^~3#wFxX&_D?Jx4SCn|HH7dqD(+q5Zt?a1sQ7``#oN95(DT zfr-k z_75VQ98M;2w&D7CVp+0ddHO_H!X0YCq&dc_1Ik1NopD zXFl|D=pL#N?V3_Q%q|o)R2bTiC&l z5TH27*@3{1d#F?~&_9&0(;rPo{CQ0Vu>xAvS)BQy_{_kER&@{?e_qvbolVd%e5h-| z209{CE|{O8_)tInIs^113?C{8j2J|ya&|AjlPGNLx4AHWHlHy;kKFu49QL_>gZKoE znKK8~061(I6Jiq>V1HatX%rzhgPw=wfmDE5@W0SmR2hiyOljxG!daRBT>d}efO}N8 zQZpxx|E5fh-x5nGIX{(u($|Jw+$bjO68_|t{L{rLjqZtsEUD|y?aGF$dA?X^togYb zMkZQegx6@iBp_B;w<0DzD7|0wDT^ww&nFCyOn|z>`QiQ2aRpRa0_U_F5nU^~_qb^v zP+i0iEL$ocsSBbk`~XaelEW`Tm} zsF-r3*HNn;%bwY4xrpjiVN__R`7rqohg78==-NLoD>oJ~5? zMg7k_`TuA#{0B|-kL*Tkg64_uCeE(SE#Y99L0!qM{2jPqrz1ZLycqTMiDV;m-?lM> zx-sVbUh|gZ>z7j0OS&C!j9=bEnqYoC^06CE(zpVX)J(Qf5;xzW_HvPN)Gel6zepMt zE44nJqs%y!Jzm4E6vpI~;Q(BLjy~DQ!w~Y0yU#XF5_r;gHxr`@T>&CnYr?YT)Rad66kdY!E`WcB0+fUhBROpwWq2GTslYPzp=6%Nk0?oC) z9P?y5q)bQ0>%rF2>92(oZZB`_n5s-#zro1T*?&0rn9k=TdB}V$(oo2=#;f_hR2dZw zxt&YF7BUET9`L@kR~vr+Chzz%tEX5Q1Py<+h5bjh2NM0k{Xz+zU%35I4*Z;(6DZ%G zq{8`(=b8F@)=L2Oon!HjO=tvw{3=1p9S9f#w|WMIuwnZMO}-FH+e9D+v1d>N9vSrq zyn#}}1FfzP+d`%SVSs?3DA=d7y+#L%|X5MBL&nmXG{gp zpk6r}re|S1*bh7k50>8EzbJ+Hr&0)hDh2PSQgD7M1;Wd;h$mo1{1MSIjTp8=J5tr4 zQqW4`7n3%Dax5qXPbmKO9Ed-#znCTcrkj?6itZ|3LV7f9S_WAXJUOfjR0yj=Sag*pZ(_HT;ktd91v9B!a^USff+m3uJDRo> zd~lr5kqvYhD;fqltxz9sFI{mw|(vp z!z0m%bBDAKAya+|#3Ujn@iT_EzaE86$b|6GuhRA~uZ_ZX3_i1KRwAm)Pb7gW{z11X zVV5#Sc{!bwe`Nq_IQ4?pfQ94rIYtquN68um@2%f*(umdHET~EKHy}vcljV%WHL%19 z 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 literal 0 HcmV?d00001 diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java new file mode 100644 index 000000000..4b2b9ce37 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java @@ -0,0 +1,119 @@ + +/* ==================================================================== + 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.hwpf.usermodel; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.util.List; + +import org.apache.poi.hwpf.HWPFDocument; +import org.apache.poi.hwpf.model.PicturesTable; +import org.apache.poi.hwpf.usermodel.Picture; + +import junit.framework.TestCase; + +/** + * Test to see if Range.replaceText() works even if the Range contains a + * CharacterRun that uses Unicode characters. + */ +public class TestRangeReplacement extends TestCase { + + // u201c and u201d are "smart-quotes" + private String originalText = + "It is used to confirm that text replacement works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the ${organization} and all the POI contributors for their assistance in this matter.\r"; + private String searchText = "${organization}"; + private String replacementText = "Apache Software Foundation"; + private String expectedText = + "It is used to confirm that text replacement works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the Apache Software Foundation and all the POI contributors for their assistance in this matter.\r"; + + private String illustrativeDocFile; + + protected void setUp() throws Exception { + + String dirname = System.getProperty("HWPF.testdata.path"); + + illustrativeDocFile = dirname + "/testRangeReplacement.doc"; + } + + /** + * Test just opening the files + */ + public void testOpen() throws Exception { + + HWPFDocument docA = new HWPFDocument(new FileInputStream(illustrativeDocFile)); + } + + /** + * Test (more "confirm" than test) that we have the general structure that we expect to have. + */ + public void testDocStructure() throws Exception { + + HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile)); + + Range range = daDoc.getRange(); + + assertEquals(1, range.numSections()); + Section section = range.getSection(0); + + assertEquals(5, section.numParagraphs()); + Paragraph para = section.getParagraph(2); + + assertEquals(5, para.numCharacterRuns()); + String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() + + para.getCharacterRun(2).text() + para.getCharacterRun(3).text() + para.getCharacterRun(4).text(); + + assertEquals(originalText, text); + } + + /** + * Test that we can replace text in our Range with Unicode text. + */ + public void testRangeReplacement() throws Exception { + + HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile)); + + Range range = daDoc.getRange(); + assertEquals(1, range.numSections()); + + Section section = range.getSection(0); + assertEquals(5, section.numParagraphs()); + + Paragraph para = section.getParagraph(2); + + String text = para.text(); + assertEquals(originalText, text); + + int offset = text.indexOf(searchText); + assertEquals(181, offset); + + para.replaceText(searchText, replacementText, offset); + + // we need to let the model re-calculate the Range before we evaluate it + range = daDoc.getRange(); + + assertEquals(1, range.numSections()); + section = range.getSection(0); + + assertEquals(5, section.numParagraphs()); + para = section.getParagraph(2); + + text = para.text(); + assertEquals(expectedText, text); + } +} diff --git a/src/testcases/org/apache/poi/hssf/data/30978-alt.xls b/src/testcases/org/apache/poi/hssf/data/30978-alt.xls new file mode 100644 index 0000000000000000000000000000000000000000..c591582885aef5e605d28e22c31761b8d74540c5 GIT binary patch literal 14848 zcmeHOU2IfE6#njVx7`AT{_$5}bKRo-rN0TFw6s_tXeba`LzN}9v|Fi^uGuaLO*AeF z48ExbOzXz#7cJ-O(&$B+w0}7d!7cVE*W+ygIm$X_7SjhcuAo zVMk`Tv9I`Y=2sCWUBC^vaNfMg7`Vyc#|xMZv~-5U*1Ae-V{c!dHP!IAlA+TO8HQ+h z4MqkGn6%21%$b8lO1eB1=d1W5#ruVd8<2(8kN5$L;ZeuM%=tU>`Fx9yxmO<}0cw zDyr@%UF|P%Ui_tA^C9~2lBE0{+XCG?lbL+T#L_rZWp#2re3z<<;el@~*O=O(tSeE5 zTA)KjDYG2OqOblEMevudjuL#!eU!VSq^X0gRHBp*izb#Uvl0uHSxF@tQGv&j8?(P4 zxjiLXLX(Y+@kUpmoIMHZ2)@tGc~r4&K46B!zm-YP?HX;*uyCV`3k$xYw6t<%wOXy?34f}_uJTMvJXrI$`Xub6;dmXhvfwYOw3Fs2`6`H+fkAS-1(BAt?-hH1l)b=+kl zCo*GHaBd_+;k<~caDF6H;etq(!t){?g%N?m^CRxjXVvh2h?B;NOsO*iTRWc%ST#bq zmX$!M70UNB6DW0uIpr99&KWZG7&LN^vRM}=i-j`Y02ZBBoLQhb*dGpcc7;1?tD9R} z8Mievs;;Y9S-paZ!3LX6;){ld0cbm7;Ep(E6h>LI2O@+$HRmKv&9huF#VGy*ls{Wd zVzU`{(=la2%ViAuwg-34{CcHj*Ve`kMK4qIauvU#D3OGgAEtge@!nc#e{BN{okdMBI1)F&;qFA?9UwqL`WkX{$pOXmW}XPl_7e;H)(zYM3M+ zy25_-^9j*+`jr=TqXz@1=2JuZHZ-G-PYsr16V}qJ){~YDhFOq#9k<;1-`JibJ|vbo zmsTkqVvk^nK4f7PJ+cN>T*6t(TWk1c(Kq9sncT)iZ&G{I@KdsI;lx4tP?I3xyBDwU z+&?T-MRJPe;kc+86jFszVboJ=;+cu~ym{Vyp7gXpK2JdjHmh+fAS>5NfXS|JoJcZh zN1{{->93U(_y07KCA3>@kdhT3&N_1F z&EIZs*`0ItmpL|F>o!#b26wdJ4h^p*inXjhLa33 zx&O#QUSfMd7*J{9OFUo%mmI<)2G-Ks6$%and&1WG{at}R)o$d@krO{1y<{{oKk{1D z4;PMIGNKD&QZ#4{Xbor$Xbor$Xbor$Xbor$Xbor$Xbor$XbmK4;9mQG*VW5cPgX9@ zIsQ8L{}s2-$^QQugB-cY-hC?rZvsGm0h6PdZU*@=RQCU}Zx1ubzW+sr`3%l^z+tB4 zNaq5>`161|^~2W9MKe`hWSJ0q*@*1<G!1G@u( z@PI0>&kd*(4O#Jc=3hI&v{Qn?7$&!XX_#C z!7e4o9*3MZ=0Ct arrayA.length) { + return false; + } + if (offsetB + length > arrayB.length) { + return false; + } + for (int i = 0; i < length; i++) { + if (arrayA[i+offsetA] != arrayB[i+offsetB]) { + return false; + } + } + return true; + } public static void main(String[] ignored_args) { diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index 419bc33bb..79ef47be3 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -30,7 +30,10 @@ import junit.framework.TestCase; import org.apache.poi.ss.util.Region; import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord; +import org.apache.poi.hssf.record.NameRecord; +import org.apache.poi.hssf.record.formula.DeletedArea3DPtg; import org.apache.poi.util.TempFile; /** @@ -990,4 +993,63 @@ public final class TestBugs extends TestCase { fail(); } catch(FileNotFoundException e) {} } + + /** + * Test that we can delete sheets without + * breaking the build in named ranges + * used for printing stuff. + * Currently broken, as we change the Ptg + */ + public void test30978() throws Exception { + HSSFWorkbook wb = openSample("30978-alt.xls"); + assertEquals(1, wb.getNumberOfNames()); + assertEquals(3, wb.getNumberOfSheets()); + + // Check all names fit within range, and use + // DeletedArea3DPtg + Workbook w = wb.getWorkbook(); + for(int i=0; i