mirror of https://github.com/apache/poi.git
Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-657701,657703-657874,657876-658032,658034-658284,658286,658288-658301,658303-658307,658309-658321,658323-658335,658337-658348,658351,658353-658832,658834-658983,658985,658987-659066,659068-659402,659404-659428,659430-659451,659453-659454,659456-659461,659463-659477,659479-659524,659526-659571,659574,659576-660255,660257-660262,660264-660279,660281-660343,660345-660473,660475-660827,660829-660833,660835-660888,660890-663321,663323-663435,663437-663764,663766-663854,663856-664219,664221-664489,664494-664514,664516-668013,668015-668142,668144-668152,668154,668156-668256,668258,668260-669139,669141-669455,669457-669657,669659-669808,669810-670189,670191-671321,671323-672229,672231-672549,672551-672552,672554-672561,672563-672566,672568,672571-673049,673051-673852,673854-673862,673864-673986,673988-673996,673998-674347,674349-674890,674892-674910,674912-674936,674938-674952,674954-675078,675080-675085,675087-675217,675219-675660,675662-675670,675672-675716,675718-675726,675728-675733,675735-675775,675777-675782,675784,675786-675791,675794-675852,675854-676200,676202,676204,676206-676220,676222-676309,676311-676456,676458-676994,676996-677027,677030-677040,677042-677056,677058-677375,677377-677968,677970-677971,677973,677975-677994,677996-678286,678288-678538,678540-680393,680395-680469,680471-680529,680531-680852,680854-681529,681531-681571,681573-682224,682226,682228,682231-682281,682283-682335,682337-682507,682509,682512-682517,682519-682532,682534-682619,682622-682777,682779-682998,683000-683019,683021-683022,683024-683080,683082-683092,683094-683095,683097-683127,683129-683131,683133-683166,683168-683698,683700-683705,683707-683757,683759-683787,683789-683870,683872-683879,683881-683900,683902-684066,684068-684074,684076-684222,684224-684254,684257-684281,684283-684286,684288-684292,684294-684298,684300-684301,684303-684308,684310-684317,684320,684323-684335,684337-684348,684350-684354,684356-684361,684363-684369,684371-684453,684455-684986 via svnmerge from
https://svn.apache.org/repos/asf/poi/trunk ........ r684884 | josh | 2008-08-11 20:28:58 +0100 (Mon, 11 Aug 2008) | 1 line deleted obsolete comment (should have been done in c669809) ........ r684938 | josh | 2008-08-11 22:24:19 +0100 (Mon, 11 Aug 2008) | 1 line Refinements to fix for bug 45126. Excel does not produce any records like 'Excel_Name_Record_Titles_*' ........ r684939 | nick | 2008-08-11 22:25:17 +0100 (Mon, 11 Aug 2008) | 1 line CHPXs and PAPXs are apparently cp based, but are really byte based! Work around this ........ r684959 | nick | 2008-08-11 23:07:37 +0100 (Mon, 11 Aug 2008) | 1 line Get insert based HWPF tests working fine, delete ones still problematic ........ r684971 | josh | 2008-08-11 23:55:38 +0100 (Mon, 11 Aug 2008) | 1 line initial work on supporting calls to add-in functions ........ r684986 | nick | 2008-08-12 00:42:39 +0100 (Tue, 12 Aug 2008) | 1 line Finally get all HWPF tests to pass again, by working around how evil PAPX/CHPX/SEPX byte references are ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@684990 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
821aad8c70
commit
1073cfb53d
|
@ -58,6 +58,7 @@
|
|||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">Big improvement in how HWPF handles unicode text, and more sanity checking of text ranges within HWPF</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Include headers and footers int he extracted text from HWPF's WordExtractor</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Added support to HWPF for headers and footers</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Improve how HWPF deals with unicode internally. Should avoid some odd behaviour when manipulating unicode text</action>
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">Big improvement in how HWPF handles unicode text, and more sanity checking of text ranges within HWPF</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Include headers and footers int he extracted text from HWPF's WordExtractor</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Added support to HWPF for headers and footers</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Improve how HWPF deals with unicode internally. Should avoid some odd behaviour when manipulating unicode text</action>
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.Stack;
|
|||
import org.apache.poi.hssf.record.formula.*;
|
||||
import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
|
||||
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
|
||||
import org.apache.poi.ss.usermodel.Name;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
|
@ -370,13 +371,32 @@ public final class FormulaParser {
|
|||
* @param name case preserved function name (as it was entered/appeared in the formula).
|
||||
*/
|
||||
private ParseNode function(String name) {
|
||||
NamePtg nameToken = null;
|
||||
// Note regarding parameter -
|
||||
if(!AbstractFunctionPtg.isInternalFunctionName(name)) {
|
||||
// external functions get a Name token which points to a defined name record
|
||||
nameToken = new NamePtg(name, this.book);
|
||||
|
||||
Ptg nameToken = null;
|
||||
if(!AbstractFunctionPtg.isBuiltInFunctionName(name)) {
|
||||
// user defined function
|
||||
// in the token tree, the name is more or less the first argument
|
||||
|
||||
|
||||
int nameIndex = book.getNameIndex(name);
|
||||
if (nameIndex >= 0) {
|
||||
Name hName = book.getNameAt(nameIndex);
|
||||
if (!hName.isFunctionName()) {
|
||||
throw new FormulaParseException("Attempt to use name '" + name
|
||||
+ "' as a function, but defined name in workbook does not refer to a function");
|
||||
}
|
||||
|
||||
// calls to user-defined functions within the workbook
|
||||
// get a Name token which points to a defined name record
|
||||
nameToken = new NamePtg(name, this.book);
|
||||
} else {
|
||||
if(book instanceof HSSFWorkbook) {
|
||||
nameToken = ((HSSFWorkbook)book).getNameXPtg(name);
|
||||
}
|
||||
if (nameToken == null) {
|
||||
throw new FormulaParseException("Name '" + name
|
||||
+ "' is completely unknown in the current workbook");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Match('(');
|
||||
|
@ -390,11 +410,11 @@ public final class FormulaParser {
|
|||
* Generates the variable function ptg for the formula.
|
||||
* <p>
|
||||
* For IF Formulas, additional PTGs are added to the tokens
|
||||
* @param name
|
||||
* @param name a {@link NamePtg} or {@link NameXPtg} or <code>null</code>
|
||||
* @param numArgs
|
||||
* @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is handled in this function
|
||||
*/
|
||||
private ParseNode getFunction(String name, NamePtg namePtg, ParseNode[] args) {
|
||||
private ParseNode getFunction(String name, Ptg namePtg, ParseNode[] args) {
|
||||
|
||||
FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByName(name.toUpperCase());
|
||||
int numArgs = args.length;
|
||||
|
|
|
@ -25,11 +25,11 @@ import org.apache.poi.hssf.record.CRNCountRecord;
|
|||
import org.apache.poi.hssf.record.CRNRecord;
|
||||
import org.apache.poi.hssf.record.CountryRecord;
|
||||
import org.apache.poi.hssf.record.ExternSheetRecord;
|
||||
import org.apache.poi.hssf.record.ExternSheetSubRecord;
|
||||
import org.apache.poi.hssf.record.ExternalNameRecord;
|
||||
import org.apache.poi.hssf.record.NameRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.SupBookRecord;
|
||||
import org.apache.poi.hssf.record.formula.NameXPtg;
|
||||
|
||||
/**
|
||||
* Link Table (OOO pdf reference: 4.10.3 ) <p/>
|
||||
|
@ -122,6 +122,19 @@ final class LinkTable {
|
|||
public String getNameText(int definedNameIndex) {
|
||||
return _externalNameRecords[definedNameIndex].getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs case-insensitive search
|
||||
* @return -1 if not found
|
||||
*/
|
||||
public int getIndexOfName(String name) {
|
||||
for (int i = 0; i < _externalNameRecords.length; i++) {
|
||||
if(_externalNameRecords[i].getText().equalsIgnoreCase(name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private final ExternalBookBlock[] _externalBookBlocks;
|
||||
|
@ -192,14 +205,18 @@ final class LinkTable {
|
|||
}
|
||||
|
||||
|
||||
public NameRecord getSpecificBuiltinRecord(byte name, int sheetIndex) {
|
||||
/**
|
||||
* @param builtInCode a BUILTIN_~ constant from {@link NameRecord}
|
||||
* @param sheetNumber 1-based sheet number
|
||||
*/
|
||||
public NameRecord getSpecificBuiltinRecord(byte builtInCode, int sheetNumber) {
|
||||
|
||||
Iterator iterator = _definedNames.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
NameRecord record = ( NameRecord ) iterator.next();
|
||||
|
||||
//print areas are one based
|
||||
if (record.getBuiltInName() == name && record.getIndexToSheet() == sheetIndex) {
|
||||
if (record.getBuiltInName() == builtInCode && record.getSheetNumber() == sheetNumber) {
|
||||
return record;
|
||||
}
|
||||
}
|
||||
|
@ -241,69 +258,56 @@ final class LinkTable {
|
|||
_definedNames.remove(namenum);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if the given name is already included in the linkTable
|
||||
*/
|
||||
public boolean nameAlreadyExists(NameRecord name)
|
||||
{
|
||||
// Check to ensure no other names have the same case-insensitive name
|
||||
for ( int i = getNumNames()-1; i >=0; i-- ) {
|
||||
NameRecord rec = getNameRecord(i);
|
||||
if (rec != name) {
|
||||
if (isDuplicatedNames(name, rec))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isDuplicatedNames(NameRecord firstName, NameRecord lastName)
|
||||
{
|
||||
return lastName.getNameText().equalsIgnoreCase(firstName.getNameText())
|
||||
&& isSameSheetNames(firstName, lastName);
|
||||
}
|
||||
private boolean isSameSheetNames(NameRecord firstName, NameRecord lastName)
|
||||
{
|
||||
return lastName.getEqualsToIndexToSheet() == firstName.getEqualsToIndexToSheet();
|
||||
}
|
||||
|
||||
|
||||
public short getIndexToSheet(short num) {
|
||||
return _externSheetRecord.getREFRecordAt(num).getIndexToFirstSupBook();
|
||||
}
|
||||
|
||||
public int getSheetIndexFromExternSheetIndex(int externSheetNumber) {
|
||||
if (externSheetNumber >= _externSheetRecord.getNumOfREFStructures()) {
|
||||
return -1;
|
||||
}
|
||||
return _externSheetRecord.getREFRecordAt(externSheetNumber).getIndexToFirstSupBook();
|
||||
}
|
||||
|
||||
public short addSheetIndexToExternSheet(short sheetNumber) {
|
||||
|
||||
ExternSheetSubRecord record = new ExternSheetSubRecord();
|
||||
record.setIndexToFirstSupBook(sheetNumber);
|
||||
record.setIndexToLastSupBook(sheetNumber);
|
||||
_externSheetRecord.addREFRecord(record);
|
||||
_externSheetRecord.setNumOfREFStructures((short)(_externSheetRecord.getNumOfREFStructures() + 1));
|
||||
return (short)(_externSheetRecord.getNumOfREFStructures() - 1);
|
||||
}
|
||||
|
||||
public short checkExternSheet(int sheetNumber) {
|
||||
|
||||
//Trying to find reference to this sheet
|
||||
int nESRs = _externSheetRecord.getNumOfREFStructures();
|
||||
for(short i=0; i< nESRs; i++) {
|
||||
ExternSheetSubRecord esr = _externSheetRecord.getREFRecordAt(i);
|
||||
|
||||
if (esr.getIndexToFirstSupBook() == sheetNumber
|
||||
&& esr.getIndexToLastSupBook() == sheetNumber){
|
||||
return i;
|
||||
/**
|
||||
* checks if the given name is already included in the linkTable
|
||||
*/
|
||||
public boolean nameAlreadyExists(NameRecord name)
|
||||
{
|
||||
// Check to ensure no other names have the same case-insensitive name
|
||||
for ( int i = getNumNames()-1; i >=0; i-- ) {
|
||||
NameRecord rec = getNameRecord(i);
|
||||
if (rec != name) {
|
||||
if (isDuplicatedNames(name, rec))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isDuplicatedNames(NameRecord firstName, NameRecord lastName) {
|
||||
return lastName.getNameText().equalsIgnoreCase(firstName.getNameText())
|
||||
&& isSameSheetNames(firstName, lastName);
|
||||
}
|
||||
private static boolean isSameSheetNames(NameRecord firstName, NameRecord lastName) {
|
||||
return lastName.getSheetNumber() == firstName.getSheetNumber();
|
||||
}
|
||||
|
||||
|
||||
public int getIndexToSheet(int extRefIndex) {
|
||||
return _externSheetRecord.getFirstSheetIndexFromRefIndex(extRefIndex);
|
||||
}
|
||||
|
||||
public int getSheetIndexFromExternSheetIndex(int extRefIndex) {
|
||||
if (extRefIndex >= _externSheetRecord.getNumOfRefs()) {
|
||||
return -1;
|
||||
}
|
||||
return _externSheetRecord.getFirstSheetIndexFromRefIndex(extRefIndex);
|
||||
}
|
||||
|
||||
public int addSheetIndexToExternSheet(int sheetNumber) {
|
||||
// TODO - what about the first parameter (extBookIndex)?
|
||||
return _externSheetRecord.addRef(0, sheetNumber, sheetNumber);
|
||||
}
|
||||
|
||||
public short checkExternSheet(int sheetIndex) {
|
||||
|
||||
//Trying to find reference to this sheet
|
||||
int i = _externSheetRecord.getRefIxForSheet(sheetIndex);
|
||||
if (i>=0) {
|
||||
return (short)i;
|
||||
}
|
||||
//We Haven't found reference to this sheet
|
||||
return addSheetIndexToExternSheet((short) sheetNumber);
|
||||
return (short)addSheetIndexToExternSheet((short) sheetIndex);
|
||||
}
|
||||
|
||||
|
||||
|
@ -324,11 +328,31 @@ final class LinkTable {
|
|||
}
|
||||
|
||||
public int getNumberOfREFStructures() {
|
||||
return _externSheetRecord.getNumOfREFStructures();
|
||||
return _externSheetRecord.getNumOfRefs();
|
||||
}
|
||||
|
||||
public String resolveNameXText(int refIndex, int definedNameIndex) {
|
||||
short extBookIndex = _externSheetRecord.getREFRecordAt(refIndex).getIndexToSupBook();
|
||||
int extBookIndex = _externSheetRecord.getExtbookIndexFromRefIndex(refIndex);
|
||||
return _externalBookBlocks[extBookIndex].getNameText(definedNameIndex);
|
||||
}
|
||||
|
||||
public NameXPtg getNameXPtg(String name) {
|
||||
// first find any external book block that contains the name:
|
||||
for (int i = 0; i < _externalBookBlocks.length; i++) {
|
||||
int definedNameIndex = _externalBookBlocks[i].getIndexOfName(name);
|
||||
if (definedNameIndex < 0) {
|
||||
continue;
|
||||
}
|
||||
// found it.
|
||||
int sheetRefIndex = findRefIndexFromExtBookIndex(i);
|
||||
if (sheetRefIndex >= 0) {
|
||||
return new NameXPtg(sheetRefIndex, definedNameIndex);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int findRefIndexFromExtBookIndex(int extBookIndex) {
|
||||
return _externSheetRecord.findRefIndexFromExtBookIndex(extBookIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,21 +15,70 @@
|
|||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.model;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hssf.record.*;
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.hssf.util.SheetReferences;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.poi.ddf.EscherBSERecord;
|
||||
import org.apache.poi.ddf.EscherBoolProperty;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherDggRecord;
|
||||
import org.apache.poi.ddf.EscherOptRecord;
|
||||
import org.apache.poi.ddf.EscherProperties;
|
||||
import org.apache.poi.ddf.EscherRGBProperty;
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
import org.apache.poi.ddf.EscherSplitMenuColorsRecord;
|
||||
import org.apache.poi.hssf.record.BOFRecord;
|
||||
import org.apache.poi.hssf.record.BackupRecord;
|
||||
import org.apache.poi.hssf.record.BookBoolRecord;
|
||||
import org.apache.poi.hssf.record.BoundSheetRecord;
|
||||
import org.apache.poi.hssf.record.CodepageRecord;
|
||||
import org.apache.poi.hssf.record.CountryRecord;
|
||||
import org.apache.poi.hssf.record.DSFRecord;
|
||||
import org.apache.poi.hssf.record.DateWindow1904Record;
|
||||
import org.apache.poi.hssf.record.DrawingGroupRecord;
|
||||
import org.apache.poi.hssf.record.EOFRecord;
|
||||
import org.apache.poi.hssf.record.ExtSSTRecord;
|
||||
import org.apache.poi.hssf.record.ExtendedFormatRecord;
|
||||
import org.apache.poi.hssf.record.ExternSheetRecord;
|
||||
import org.apache.poi.hssf.record.FileSharingRecord;
|
||||
import org.apache.poi.hssf.record.FnGroupCountRecord;
|
||||
import org.apache.poi.hssf.record.FontRecord;
|
||||
import org.apache.poi.hssf.record.FormatRecord;
|
||||
import org.apache.poi.hssf.record.HideObjRecord;
|
||||
import org.apache.poi.hssf.record.HyperlinkRecord;
|
||||
import org.apache.poi.hssf.record.InterfaceEndRecord;
|
||||
import org.apache.poi.hssf.record.InterfaceHdrRecord;
|
||||
import org.apache.poi.hssf.record.MMSRecord;
|
||||
import org.apache.poi.hssf.record.NameRecord;
|
||||
import org.apache.poi.hssf.record.PaletteRecord;
|
||||
import org.apache.poi.hssf.record.PasswordRecord;
|
||||
import org.apache.poi.hssf.record.PasswordRev4Record;
|
||||
import org.apache.poi.hssf.record.PrecisionRecord;
|
||||
import org.apache.poi.hssf.record.ProtectRecord;
|
||||
import org.apache.poi.hssf.record.ProtectionRev4Record;
|
||||
import org.apache.poi.hssf.record.RecalcIdRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.RefreshAllRecord;
|
||||
import org.apache.poi.hssf.record.SSTRecord;
|
||||
import org.apache.poi.hssf.record.StyleRecord;
|
||||
import org.apache.poi.hssf.record.SupBookRecord;
|
||||
import org.apache.poi.hssf.record.TabIdRecord;
|
||||
import org.apache.poi.hssf.record.UnicodeString;
|
||||
import org.apache.poi.hssf.record.UseSelFSRecord;
|
||||
import org.apache.poi.hssf.record.WindowOneRecord;
|
||||
import org.apache.poi.hssf.record.WindowProtectRecord;
|
||||
import org.apache.poi.hssf.record.WriteAccessRecord;
|
||||
import org.apache.poi.hssf.record.WriteProtectRecord;
|
||||
import org.apache.poi.hssf.record.formula.NameXPtg;
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.hssf.util.SheetReferences;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
/**
|
||||
* Low level model implementation of a Workbook. Provides creational methods
|
||||
* for settings and objects contained in the workbook object.
|
||||
|
@ -54,18 +103,13 @@ import java.util.Locale;
|
|||
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook
|
||||
* @version 1.0-pre
|
||||
*/
|
||||
|
||||
public class Workbook implements Model
|
||||
{
|
||||
public final class Workbook implements Model {
|
||||
private static final int DEBUG = POILogger.DEBUG;
|
||||
|
||||
// public static Workbook currentBook = null;
|
||||
|
||||
/**
|
||||
* constant used to set the "codepage" wherever "codepage" is set in records
|
||||
* (which is duplciated in more than one record)
|
||||
* (which is duplicated in more than one record)
|
||||
*/
|
||||
|
||||
private final static short CODEPAGE = ( short ) 0x4b0;
|
||||
|
||||
/**
|
||||
|
@ -105,8 +149,6 @@ public class Workbook implements Model
|
|||
|
||||
private static POILogger log = POILogFactory.getLogger(Workbook.class);
|
||||
|
||||
protected static final String EXCEL_REPEATING_NAME_PREFIX_ = "Excel_Name_Record_Titles_";
|
||||
|
||||
/**
|
||||
* Creates new Workbook with no intitialization --useless right now
|
||||
* @see #createWorkbook(List)
|
||||
|
@ -250,9 +292,9 @@ public class Workbook implements Model
|
|||
for ( ; k < recs.size(); k++) {
|
||||
Record rec = ( Record ) recs.get(k);
|
||||
switch (rec.getSid()) {
|
||||
case HyperlinkRecord.sid:
|
||||
retval.hyperlinks.add(rec);
|
||||
break;
|
||||
case HyperlinkRecord.sid:
|
||||
retval.hyperlinks.add(rec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,22 +400,22 @@ public class Workbook implements Model
|
|||
}
|
||||
|
||||
|
||||
/**Retrieves the Builtin NameRecord that matches the name and index
|
||||
* There shouldn't be too many names to make the sequential search too slow
|
||||
* @param name byte representation of the builtin name to match
|
||||
* @param sheetIndex Index to match
|
||||
* @return null if no builtin NameRecord matches
|
||||
*/
|
||||
public NameRecord getSpecificBuiltinRecord(byte name, int sheetIndex)
|
||||
/**Retrieves the Builtin NameRecord that matches the name and index
|
||||
* There shouldn't be too many names to make the sequential search too slow
|
||||
* @param name byte representation of the builtin name to match
|
||||
* @param sheetNumber 1-based sheet number
|
||||
* @return null if no builtin NameRecord matches
|
||||
*/
|
||||
public NameRecord getSpecificBuiltinRecord(byte name, int sheetNumber)
|
||||
{
|
||||
return getOrCreateLinkTable().getSpecificBuiltinRecord(name, sheetIndex);
|
||||
return getOrCreateLinkTable().getSpecificBuiltinRecord(name, sheetNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified Builtin NameRecord that matches the name and index
|
||||
* @param name byte representation of the builtin to match
|
||||
* @param sheetIndex zero-based sheet reference
|
||||
*/
|
||||
/**
|
||||
* Removes the specified Builtin NameRecord that matches the name and index
|
||||
* @param name byte representation of the builtin to match
|
||||
* @param sheetIndex zero-based sheet reference
|
||||
*/
|
||||
public void removeBuiltinRecord(byte name, int sheetIndex) {
|
||||
linkTable.removeBuiltinRecord(name, sheetIndex);
|
||||
// TODO - do we need "this.records.remove(...);" similar to that in this.removeName(int namenum) {}?
|
||||
|
@ -413,18 +455,18 @@ public class Workbook implements Model
|
|||
* Retrieves the index of the given font
|
||||
*/
|
||||
public int getFontIndex(FontRecord font) {
|
||||
for(int i=0; i<=numfonts; i++) {
|
||||
for(int i=0; i<=numfonts; i++) {
|
||||
FontRecord thisFont =
|
||||
( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + i);
|
||||
if(thisFont == font) {
|
||||
// There is no 4!
|
||||
if(i > 3) {
|
||||
return (i+1);
|
||||
}
|
||||
return i;
|
||||
// There is no 4!
|
||||
if(i > 3) {
|
||||
return (i+1);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Could not find that font!");
|
||||
}
|
||||
throw new IllegalArgumentException("Could not find that font!");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -451,7 +493,7 @@ public class Workbook implements Model
|
|||
* so you'll need to update those yourself!
|
||||
*/
|
||||
public void removeFontRecord(FontRecord rec) {
|
||||
records.remove(rec); // this updates FontPos for us
|
||||
records.remove(rec); // this updates FontPos for us
|
||||
numfonts--;
|
||||
}
|
||||
|
||||
|
@ -468,19 +510,23 @@ public class Workbook implements Model
|
|||
/**
|
||||
* Sets the BOF for a given sheet
|
||||
*
|
||||
* @param sheetnum the number of the sheet to set the positing of the bof for
|
||||
* @param sheetIndex the number of the sheet to set the positing of the bof for
|
||||
* @param pos the actual bof position
|
||||
*/
|
||||
|
||||
public void setSheetBof(int sheetnum, int pos) {
|
||||
public void setSheetBof(int sheetIndex, int pos) {
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
log.log(DEBUG, "setting bof for sheetnum =", new Integer(sheetnum),
|
||||
log.log(DEBUG, "setting bof for sheetnum =", new Integer(sheetIndex),
|
||||
" at pos=", new Integer(pos));
|
||||
checkSheets(sheetnum);
|
||||
(( BoundSheetRecord ) boundsheets.get(sheetnum))
|
||||
checkSheets(sheetIndex);
|
||||
getBoundSheetRec(sheetIndex)
|
||||
.setPositionOfBof(pos);
|
||||
}
|
||||
|
||||
private BoundSheetRecord getBoundSheetRec(int sheetIndex) {
|
||||
return ((BoundSheetRecord) boundsheets.get(sheetIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the backup record.
|
||||
*/
|
||||
|
@ -516,7 +562,7 @@ public class Workbook implements Model
|
|||
{
|
||||
for ( int i = 0; i < boundsheets.size(); i++ )
|
||||
{
|
||||
BoundSheetRecord boundSheetRecord = (BoundSheetRecord) boundsheets.get( i );
|
||||
BoundSheetRecord boundSheetRecord = getBoundSheetRec(i);
|
||||
if (excludeSheetIdx != i && name.equalsIgnoreCase(boundSheetRecord.getSheetname()))
|
||||
return true;
|
||||
}
|
||||
|
@ -533,35 +579,33 @@ public class Workbook implements Model
|
|||
*/
|
||||
public void setSheetName(int sheetnum, String sheetname, short encoding ) {
|
||||
checkSheets(sheetnum);
|
||||
BoundSheetRecord sheet = (BoundSheetRecord)boundsheets.get( sheetnum );
|
||||
BoundSheetRecord sheet = getBoundSheetRec(sheetnum);
|
||||
sheet.setSheetname(sheetname);
|
||||
sheet.setSheetnameLength( (byte)sheetname.length() );
|
||||
sheet.setCompressedUnicodeFlag( (byte)encoding );
|
||||
sheet.setCompressedUnicodeFlag( (byte)encoding );
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the order of appearance for a given sheet.
|
||||
*
|
||||
* @param sheetname the name of the sheet to reorder
|
||||
* @param pos the position that we want to insert the sheet into (0 based)
|
||||
*/
|
||||
* sets the order of appearance for a given sheet.
|
||||
*
|
||||
* @param sheetname the name of the sheet to reorder
|
||||
* @param pos the position that we want to insert the sheet into (0 based)
|
||||
*/
|
||||
|
||||
public void setSheetOrder(String sheetname, int pos ) {
|
||||
int sheetNumber = getSheetIndex(sheetname);
|
||||
//remove the sheet that needs to be reordered and place it in the spot we want
|
||||
boundsheets.add(pos, boundsheets.remove(sheetNumber));
|
||||
int sheetNumber = getSheetIndex(sheetname);
|
||||
//remove the sheet that needs to be reordered and place it in the spot we want
|
||||
boundsheets.add(pos, boundsheets.remove(sheetNumber));
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the name for a given sheet.
|
||||
*
|
||||
* @param sheetnum the sheet number (0 based)
|
||||
* @param sheetIndex the sheet number (0 based)
|
||||
* @return sheetname the name for the sheet
|
||||
*/
|
||||
|
||||
public String getSheetName(int sheetnum) {
|
||||
return (( BoundSheetRecord ) boundsheets.get(sheetnum))
|
||||
.getSheetname();
|
||||
public String getSheetName(int sheetIndex) {
|
||||
return getBoundSheetRec(sheetIndex).getSheetname();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -572,8 +616,7 @@ public class Workbook implements Model
|
|||
*/
|
||||
|
||||
public boolean isSheetHidden(int sheetnum) {
|
||||
BoundSheetRecord bsr = ( BoundSheetRecord ) boundsheets.get(sheetnum);
|
||||
return bsr.isHidden();
|
||||
return getBoundSheetRec(sheetnum).isHidden();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -584,8 +627,7 @@ public class Workbook implements Model
|
|||
*/
|
||||
|
||||
public void setSheetHidden(int sheetnum, boolean hidden) {
|
||||
BoundSheetRecord bsr = ( BoundSheetRecord ) boundsheets.get(sheetnum);
|
||||
bsr.setHidden(hidden);
|
||||
getBoundSheetRec(sheetnum).setHidden(hidden);
|
||||
}
|
||||
/**
|
||||
* get the sheet's index
|
||||
|
@ -627,11 +669,13 @@ public class Workbook implements Model
|
|||
}
|
||||
}
|
||||
|
||||
public void removeSheet(int sheetnum) {
|
||||
if (boundsheets.size() > sheetnum) {
|
||||
records.remove(records.getBspos() - (boundsheets.size() - 1) + sheetnum);
|
||||
// records.bspos--;
|
||||
boundsheets.remove(sheetnum);
|
||||
/**
|
||||
* @param sheetIndex zero based sheet index
|
||||
*/
|
||||
public void removeSheet(int sheetIndex) {
|
||||
if (boundsheets.size() > sheetIndex) {
|
||||
records.remove(records.getBspos() - (boundsheets.size() - 1) + sheetIndex);
|
||||
boundsheets.remove(sheetIndex);
|
||||
fixTabIdRecord();
|
||||
}
|
||||
|
||||
|
@ -642,20 +686,18 @@ public class Workbook implements Model
|
|||
// 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;
|
||||
int sheetNum1Based = sheetIndex + 1;
|
||||
for(int i=0; i<getNumNames(); i++) {
|
||||
NameRecord nr = getNameRecord(i);
|
||||
|
||||
if(nr.getIndexToSheet() == sheetNum1Based) {
|
||||
// Excel re-writes these to point to no sheet
|
||||
nr.setEqualsToIndexToSheet((short)0);
|
||||
} else if(nr.getIndexToSheet() > sheetNum1Based) {
|
||||
// Bump down by one, so still points
|
||||
// at the same sheet
|
||||
nr.setEqualsToIndexToSheet((short)(
|
||||
nr.getEqualsToIndexToSheet()-1
|
||||
));
|
||||
}
|
||||
NameRecord nr = getNameRecord(i);
|
||||
|
||||
if(nr.getSheetNumber() == sheetNum1Based) {
|
||||
// Excel re-writes these to point to no sheet
|
||||
nr.setSheetNumber(0);
|
||||
} else if(nr.getSheetNumber() > sheetNum1Based) {
|
||||
// Bump down by one, so still points
|
||||
// at the same sheet
|
||||
nr.setSheetNumber(nr.getSheetNumber()-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -721,7 +763,7 @@ public class Workbook implements Model
|
|||
* so you'll need to update those yourself!
|
||||
*/
|
||||
public void removeExFormatRecord(ExtendedFormatRecord rec) {
|
||||
records.remove(rec); // this updates XfPos for us
|
||||
records.remove(rec); // this updates XfPos for us
|
||||
numxfs--;
|
||||
}
|
||||
|
||||
|
@ -813,9 +855,9 @@ public class Workbook implements Model
|
|||
//
|
||||
// Record record = records.get(k);
|
||||
//// Let's skip RECALCID records, as they are only use for optimization
|
||||
// if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) {
|
||||
// if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) {
|
||||
// pos += record.serialize(pos, retval); // rec.length;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// log.log(DEBUG, "Exiting serialize workbook");
|
||||
// return retval;
|
||||
|
@ -858,7 +900,7 @@ public class Workbook implements Model
|
|||
if (record instanceof BoundSheetRecord) {
|
||||
if(!wroteBoundSheets) {
|
||||
for (int i = 0; i < boundsheets.size(); i++) {
|
||||
len+= ((BoundSheetRecord)boundsheets.get(i))
|
||||
len+= getBoundSheetRec(i)
|
||||
.serialize(pos+offset+len, data);
|
||||
}
|
||||
wroteBoundSheets = true;
|
||||
|
@ -1141,8 +1183,8 @@ public class Workbook implements Model
|
|||
retval.setWidth(( short ) 0x3a5c);
|
||||
retval.setHeight(( short ) 0x23be);
|
||||
retval.setOptions(( short ) 0x38);
|
||||
retval.setSelectedTab(( short ) 0x0);
|
||||
retval.setDisplayedTab(( short ) 0x0);
|
||||
retval.setActiveSheetIndex( 0x0);
|
||||
retval.setFirstVisibleTab(0x0);
|
||||
retval.setNumSelectedTabs(( short ) 1);
|
||||
retval.setTabWidthRatio(( short ) 0x258);
|
||||
return retval;
|
||||
|
@ -1821,10 +1863,10 @@ public class Workbook implements Model
|
|||
|
||||
// from Russia with love ;)
|
||||
if ( Locale.getDefault().toString().equals( "ru_RU" ) ) {
|
||||
retval.setCurrentCountry(( short ) 7);
|
||||
retval.setCurrentCountry(( short ) 7);
|
||||
}
|
||||
else {
|
||||
retval.setCurrentCountry(( short ) 1);
|
||||
retval.setCurrentCountry(( short ) 1);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
@ -1889,15 +1931,15 @@ public class Workbook implements Model
|
|||
* @return sheet name
|
||||
*/
|
||||
public String findSheetNameFromExternSheet(short num){
|
||||
String result="";
|
||||
|
||||
short indexToSheet = linkTable.getIndexToSheet(num);
|
||||
int indexToSheet = linkTable.getIndexToSheet(num);
|
||||
|
||||
if (indexToSheet>-1) { //error check, bail out gracefully!
|
||||
result = getSheetName(indexToSheet);
|
||||
if (indexToSheet < 0) {
|
||||
// TODO - what does '-1' mean here?
|
||||
//error check, bail out gracefully!
|
||||
return "";
|
||||
}
|
||||
|
||||
return result;
|
||||
return getSheetName(indexToSheet);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1950,10 +1992,10 @@ public class Workbook implements Model
|
|||
*/
|
||||
public NameRecord addName(NameRecord name)
|
||||
{
|
||||
|
||||
|
||||
LinkTable linkTable = getOrCreateLinkTable();
|
||||
if(linkTable.nameAlreadyExists(name)) {
|
||||
throw new IllegalArgumentException(
|
||||
throw new IllegalArgumentException(
|
||||
"You are trying to assign a duplicated name record: "
|
||||
+ name.getNameText());
|
||||
}
|
||||
|
@ -1964,27 +2006,18 @@ public class Workbook implements Model
|
|||
|
||||
/**
|
||||
* Generates a NameRecord to represent a built-in region
|
||||
* @return a new NameRecord unless the index is invalid
|
||||
* @return a new NameRecord
|
||||
*/
|
||||
public NameRecord createBuiltInName(byte builtInName, int index)
|
||||
{
|
||||
if (index == -1 || index+1 > Short.MAX_VALUE)
|
||||
throw new IllegalArgumentException("Index is not valid ["+index+"]");
|
||||
public NameRecord createBuiltInName(byte builtInName, int sheetNumber) {
|
||||
if (sheetNumber < 0 || sheetNumber+1 > Short.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Sheet number ["+sheetNumber+"]is not valid ");
|
||||
}
|
||||
|
||||
NameRecord name = new NameRecord(builtInName, (short)(index));
|
||||
NameRecord name = new NameRecord(builtInName, sheetNumber);
|
||||
|
||||
String prefix = EXCEL_REPEATING_NAME_PREFIX_ + index + "_";
|
||||
int cont = 0;
|
||||
while(linkTable.nameAlreadyExists(name)) {
|
||||
cont++;
|
||||
String altNameName = prefix + cont;
|
||||
|
||||
// It would be better to set a different builtInName here.
|
||||
// It does not seem possible, so we create it as a
|
||||
// non built-in name from this point on
|
||||
name = new NameRecord();
|
||||
name.setNameText(altNameName);
|
||||
name.setNameTextLength((byte)altNameName.length());
|
||||
throw new RuntimeException("Builtin (" + builtInName
|
||||
+ ") already exists for sheet (" + sheetNumber + ")");
|
||||
}
|
||||
addName(name);
|
||||
return name;
|
||||
|
@ -1992,16 +2025,15 @@ public class Workbook implements Model
|
|||
|
||||
|
||||
/** removes the name
|
||||
* @param namenum name index
|
||||
* @param nameIndex name index
|
||||
*/
|
||||
public void removeName(int namenum){
|
||||
public void removeName(int nameIndex){
|
||||
|
||||
if (linkTable.getNumNames() > namenum) {
|
||||
if (linkTable.getNumNames() > nameIndex) {
|
||||
int idx = findFirstRecordLocBySid(NameRecord.sid);
|
||||
records.remove(idx + namenum);
|
||||
linkTable.removeName(namenum);
|
||||
records.remove(idx + nameIndex);
|
||||
linkTable.removeName(nameIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2011,19 +2043,19 @@ public class Workbook implements Model
|
|||
* @return the format id of a format that matches or -1 if none found and createIfNotFound
|
||||
*/
|
||||
public short getFormat(String format, boolean createIfNotFound) {
|
||||
Iterator iterator;
|
||||
for (iterator = formats.iterator(); iterator.hasNext();) {
|
||||
FormatRecord r = (FormatRecord)iterator.next();
|
||||
if (r.getFormatString().equals(format)) {
|
||||
return r.getIndexCode();
|
||||
}
|
||||
}
|
||||
Iterator iterator;
|
||||
for (iterator = formats.iterator(); iterator.hasNext();) {
|
||||
FormatRecord r = (FormatRecord)iterator.next();
|
||||
if (r.getFormatString().equals(format)) {
|
||||
return r.getIndexCode();
|
||||
}
|
||||
}
|
||||
|
||||
if (createIfNotFound) {
|
||||
return createFormat(format);
|
||||
}
|
||||
if (createIfNotFound) {
|
||||
return createFormat(format);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2031,7 +2063,7 @@ public class Workbook implements Model
|
|||
* @return ArrayList of FormatRecords in the notebook
|
||||
*/
|
||||
public ArrayList getFormats() {
|
||||
return formats;
|
||||
return formats;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2043,7 +2075,7 @@ public class Workbook implements Model
|
|||
*/
|
||||
public short createFormat( String format )
|
||||
{
|
||||
// ++xfpos; //These are to ensure that positions are updated properly
|
||||
// ++xfpos; //These are to ensure that positions are updated properly
|
||||
// ++palettepos;
|
||||
// ++bspos;
|
||||
FormatRecord rec = new FormatRecord();
|
||||
|
@ -2113,7 +2145,7 @@ public class Workbook implements Model
|
|||
|
||||
public List getHyperlinks()
|
||||
{
|
||||
return hyperlinks;
|
||||
return hyperlinks;
|
||||
}
|
||||
|
||||
public List getRecords()
|
||||
|
@ -2170,54 +2202,54 @@ public class Workbook implements Model
|
|||
* Finds the primary drawing group, if one already exists
|
||||
*/
|
||||
public void findDrawingGroup() {
|
||||
// Need to find a DrawingGroupRecord that
|
||||
// contains a EscherDggRecord
|
||||
for(Iterator rit = records.iterator(); rit.hasNext();) {
|
||||
Record r = (Record)rit.next();
|
||||
|
||||
if(r instanceof DrawingGroupRecord) {
|
||||
DrawingGroupRecord dg = (DrawingGroupRecord)r;
|
||||
dg.processChildRecords();
|
||||
|
||||
EscherContainerRecord cr =
|
||||
dg.getEscherContainer();
|
||||
if(cr == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EscherDggRecord dgg = null;
|
||||
for(Iterator it = cr.getChildRecords().iterator(); it.hasNext();) {
|
||||
Object er = it.next();
|
||||
if(er instanceof EscherDggRecord) {
|
||||
dgg = (EscherDggRecord)er;
|
||||
}
|
||||
}
|
||||
|
||||
if(dgg != null) {
|
||||
drawingManager = new DrawingManager2(dgg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Need to find a DrawingGroupRecord that
|
||||
// contains a EscherDggRecord
|
||||
for(Iterator rit = records.iterator(); rit.hasNext();) {
|
||||
Record r = (Record)rit.next();
|
||||
|
||||
if(r instanceof DrawingGroupRecord) {
|
||||
DrawingGroupRecord dg = (DrawingGroupRecord)r;
|
||||
dg.processChildRecords();
|
||||
|
||||
EscherContainerRecord cr =
|
||||
dg.getEscherContainer();
|
||||
if(cr == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EscherDggRecord dgg = null;
|
||||
for(Iterator it = cr.getChildRecords().iterator(); it.hasNext();) {
|
||||
Object er = it.next();
|
||||
if(er instanceof EscherDggRecord) {
|
||||
dgg = (EscherDggRecord)er;
|
||||
}
|
||||
}
|
||||
|
||||
if(dgg != null) {
|
||||
drawingManager = new DrawingManager2(dgg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the DrawingGroup record
|
||||
// Look for the DrawingGroup record
|
||||
int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
|
||||
|
||||
// If there is one, does it have a EscherDggRecord?
|
||||
// If there is one, does it have a EscherDggRecord?
|
||||
if(dgLoc != -1) {
|
||||
DrawingGroupRecord dg =
|
||||
(DrawingGroupRecord)records.get(dgLoc);
|
||||
EscherDggRecord dgg = null;
|
||||
for(Iterator it = dg.getEscherRecords().iterator(); it.hasNext();) {
|
||||
Object er = it.next();
|
||||
if(er instanceof EscherDggRecord) {
|
||||
dgg = (EscherDggRecord)er;
|
||||
}
|
||||
}
|
||||
|
||||
if(dgg != null) {
|
||||
drawingManager = new DrawingManager2(dgg);
|
||||
}
|
||||
DrawingGroupRecord dg =
|
||||
(DrawingGroupRecord)records.get(dgLoc);
|
||||
EscherDggRecord dgg = null;
|
||||
for(Iterator it = dg.getEscherRecords().iterator(); it.hasNext();) {
|
||||
Object er = it.next();
|
||||
if(er instanceof EscherDggRecord) {
|
||||
dgg = (EscherDggRecord)er;
|
||||
}
|
||||
}
|
||||
|
||||
if(dgg != null) {
|
||||
drawingManager = new DrawingManager2(dgg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2379,7 +2411,7 @@ public class Workbook implements Model
|
|||
*/
|
||||
public boolean isWriteProtected() {
|
||||
if (this.fileShare == null) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
FileSharingRecord frec = getFileSharing();
|
||||
return (frec.getReadOnly() == 1);
|
||||
|
@ -2419,6 +2451,8 @@ public class Workbook implements Model
|
|||
public String resolveNameXText(int refIndex, int definedNameIndex) {
|
||||
return linkTable.resolveNameXText(refIndex, definedNameIndex);
|
||||
}
|
||||
|
||||
public NameXPtg getNameXPtg(String name) {
|
||||
return getOrCreateLinkTable().getNameXPtg(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -15,29 +14,85 @@
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Title: Extern Sheet <P>
|
||||
* Description: A List of Inndexes to SupBook <P>
|
||||
* REFERENCE: <P>
|
||||
* EXTERNSHEET (0x0017)<br/>
|
||||
* A List of Indexes to EXTERNALBOOK (supplemental book) Records <p/>
|
||||
*
|
||||
* @author Libin Roman (Vista Portal LDT. Developer)
|
||||
* @version 1.0-pre
|
||||
*/
|
||||
|
||||
public class ExternSheetRecord extends Record {
|
||||
public final static short sid = 0x17;
|
||||
private short field_1_number_of_REF_sturcutres;
|
||||
private ArrayList field_2_REF_structures;
|
||||
public final static short sid = 0x0017;
|
||||
private List _list;
|
||||
|
||||
private final class RefSubRecord {
|
||||
public static final int ENCODED_SIZE = 6;
|
||||
|
||||
/** index to External Book Block (which starts with a EXTERNALBOOK record) */
|
||||
private int _extBookIndex;
|
||||
private int _firstSheetIndex; // may be -1 (0xFFFF)
|
||||
private int _lastSheetIndex; // may be -1 (0xFFFF)
|
||||
|
||||
|
||||
/** a Constructor for making new sub record
|
||||
*/
|
||||
public RefSubRecord(int extBookIndex, int firstSheetIndex, int lastSheetIndex) {
|
||||
_extBookIndex = extBookIndex;
|
||||
_firstSheetIndex = firstSheetIndex;
|
||||
_lastSheetIndex = lastSheetIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
public RefSubRecord(RecordInputStream in) {
|
||||
this(in.readShort(), in.readShort(), in.readShort());
|
||||
}
|
||||
public int getExtBookIndex(){
|
||||
return _extBookIndex;
|
||||
}
|
||||
public int getFirstSheetIndex(){
|
||||
return _firstSheetIndex;
|
||||
}
|
||||
public int getLastSheetIndex(){
|
||||
return _lastSheetIndex;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("extBook=").append(_extBookIndex);
|
||||
buffer.append(" firstSheet=").append(_firstSheetIndex);
|
||||
buffer.append(" lastSheet=").append(_lastSheetIndex);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* called by the class that is responsible for writing this sucker.
|
||||
* Subclasses should implement this so that their data is passed back in a
|
||||
* byte array.
|
||||
*
|
||||
* @param offset to begin writing at
|
||||
* @param data byte array containing instance data
|
||||
* @return number of bytes written
|
||||
*/
|
||||
public void serialize(int offset, byte [] data) {
|
||||
LittleEndian.putUShort(data, 0 + offset, _extBookIndex);
|
||||
LittleEndian.putUShort(data, 2 + offset, _firstSheetIndex);
|
||||
LittleEndian.putUShort(data, 4 + offset, _lastSheetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public ExternSheetRecord() {
|
||||
field_2_REF_structures = new ArrayList();
|
||||
_list = new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,72 +123,60 @@ public class ExternSheetRecord extends Record {
|
|||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
protected void fillFields(RecordInputStream in) {
|
||||
field_2_REF_structures = new ArrayList();
|
||||
_list = new ArrayList();
|
||||
|
||||
field_1_number_of_REF_sturcutres = in.readShort();
|
||||
int nItems = in.readShort();
|
||||
|
||||
for (int i = 0 ; i < field_1_number_of_REF_sturcutres ; ++i) {
|
||||
ExternSheetSubRecord rec = new ExternSheetSubRecord(in);
|
||||
for (int i = 0 ; i < nItems ; ++i) {
|
||||
RefSubRecord rec = new RefSubRecord(in);
|
||||
|
||||
field_2_REF_structures.add( rec);
|
||||
_list.add( rec);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the number of the REF structors , that is in Excel file
|
||||
* @param numStruct number of REF structs
|
||||
*/
|
||||
public void setNumOfREFStructures(short numStruct) {
|
||||
field_1_number_of_REF_sturcutres = numStruct;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return the number of the REF structors , that is in Excel file
|
||||
* @return number of REF structs
|
||||
* @return number of REF structures
|
||||
*/
|
||||
public short getNumOfREFStructures() {
|
||||
return field_1_number_of_REF_sturcutres;
|
||||
public int getNumOfRefs() {
|
||||
return _list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* adds REF struct (ExternSheetSubRecord)
|
||||
* @param rec REF struct
|
||||
*/
|
||||
public void addREFRecord(ExternSheetSubRecord rec) {
|
||||
field_2_REF_structures.add(rec);
|
||||
public void addREFRecord(RefSubRecord rec) {
|
||||
_list.add(rec);
|
||||
}
|
||||
|
||||
/** returns the number of REF Records, which is in model
|
||||
* @return number of REF records
|
||||
*/
|
||||
public int getNumOfREFRecords() {
|
||||
return field_2_REF_structures.size();
|
||||
return _list.size();
|
||||
}
|
||||
|
||||
/** returns the REF record (ExternSheetSubRecord)
|
||||
* @param elem index to place
|
||||
* @return REF record
|
||||
*/
|
||||
public ExternSheetSubRecord getREFRecordAt(int elem) {
|
||||
ExternSheetSubRecord result = ( ExternSheetSubRecord ) field_2_REF_structures.get(elem);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append("[EXTERNSHEET]\n");
|
||||
buffer.append(" numOfRefs = ").append(getNumOfREFStructures()).append("\n");
|
||||
for (int k=0; k < this.getNumOfREFRecords(); k++) {
|
||||
buffer.append("refrec #").append(k).append('\n');
|
||||
buffer.append(getREFRecordAt(k).toString());
|
||||
buffer.append("----refrec #").append(k).append('\n');
|
||||
StringBuffer sb = new StringBuffer();
|
||||
int nItems = _list.size();
|
||||
sb.append("[EXTERNSHEET]\n");
|
||||
sb.append(" numOfRefs = ").append(nItems).append("\n");
|
||||
for (int i=0; i < nItems; i++) {
|
||||
sb.append("refrec #").append(i).append(": ");
|
||||
sb.append(getRef(i).toString());
|
||||
sb.append('\n');
|
||||
}
|
||||
buffer.append("[/EXTERNSHEET]\n");
|
||||
sb.append("[/EXTERNSHEET]\n");
|
||||
|
||||
|
||||
return buffer.toString();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
private int getDataSize() {
|
||||
return 2 + _list.size() * RefSubRecord.ENCODED_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,24 +189,29 @@ public class ExternSheetRecord extends Record {
|
|||
* @return number of bytes written
|
||||
*/
|
||||
public int serialize(int offset, byte [] data) {
|
||||
LittleEndian.putShort(data, 0 + offset, sid);
|
||||
LittleEndian.putShort(data, 2 + offset,(short)(2 + (getNumOfREFRecords() *6)));
|
||||
int dataSize = getDataSize();
|
||||
|
||||
LittleEndian.putShort(data, 4 + offset, getNumOfREFStructures());
|
||||
int nItems = _list.size();
|
||||
|
||||
LittleEndian.putShort(data, 0 + offset, sid);
|
||||
LittleEndian.putUShort(data, 2 + offset, dataSize);
|
||||
LittleEndian.putUShort(data, 4 + offset, nItems);
|
||||
|
||||
int pos = 6 ;
|
||||
|
||||
for (int k = 0; k < getNumOfREFRecords(); k++) {
|
||||
ExternSheetSubRecord record = getREFRecordAt(k);
|
||||
System.arraycopy(record.serialize(), 0, data, pos + offset, 6);
|
||||
|
||||
for (int i = 0; i < nItems; i++) {
|
||||
getRef(i).serialize(offset + pos, data);
|
||||
pos +=6;
|
||||
}
|
||||
return getRecordSize();
|
||||
return dataSize + 4;
|
||||
}
|
||||
|
||||
private RefSubRecord getRef(int i) {
|
||||
return (RefSubRecord) _list.get(i);
|
||||
}
|
||||
|
||||
public int getRecordSize() {
|
||||
return 4 + 2 + getNumOfREFRecords() * 6;
|
||||
return 4 + getDataSize();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,4 +220,44 @@ public class ExternSheetRecord extends Record {
|
|||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
public int getExtbookIndexFromRefIndex(int refIndex) {
|
||||
return getRef(refIndex).getExtBookIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return -1 if not found
|
||||
*/
|
||||
public int findRefIndexFromExtBookIndex(int extBookIndex) {
|
||||
int nItems = _list.size();
|
||||
for (int i = 0; i < nItems; i++) {
|
||||
if (getRef(i).getExtBookIndex() == extBookIndex) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getFirstSheetIndexFromRefIndex(int extRefIndex) {
|
||||
return getRef(extRefIndex).getFirstSheetIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return index of newly added ref
|
||||
*/
|
||||
public int addRef(int extBookIndex, int firstSheetIndex, int lastSheetIndex) {
|
||||
_list.add(new RefSubRecord(extBookIndex, firstSheetIndex, lastSheetIndex));
|
||||
return _list.size() - 1;
|
||||
}
|
||||
|
||||
public int getRefIxForSheet(int sheetIndex) {
|
||||
int nItems = _list.size();
|
||||
for (int i = 0; i < nItems; i++) {
|
||||
RefSubRecord ref = getRef(i);
|
||||
if (ref.getFirstSheetIndex() == sheetIndex && ref.getLastSheetIndex() == sheetIndex) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,154 +0,0 @@
|
|||
|
||||
/* ====================================================================
|
||||
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.hssf.record;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Title: A sub Record for Extern Sheet <P>
|
||||
* Description: Defines a named range within a workbook. <P>
|
||||
* REFERENCE: <P>
|
||||
* @author Libin Roman (Vista Portal LDT. Developer)
|
||||
* @version 1.0-pre
|
||||
*/
|
||||
|
||||
public class ExternSheetSubRecord extends Record {
|
||||
public final static short sid = 0xFFF; // only here for conformance, doesn't really have an sid
|
||||
private short field_1_index_to_supbook;
|
||||
private short field_2_index_to_first_supbook_sheet;
|
||||
private short field_3_index_to_last_supbook_sheet;
|
||||
|
||||
|
||||
/** a Constractor for making new sub record
|
||||
*/
|
||||
public ExternSheetSubRecord() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Extern Sheet Sub Record record and sets its fields appropriately.
|
||||
*
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
public ExternSheetSubRecord(RecordInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
|
||||
/** Sets the Index to the sup book
|
||||
* @param index sup book index
|
||||
*/
|
||||
public void setIndexToSupBook(short index){
|
||||
field_1_index_to_supbook = index;
|
||||
}
|
||||
|
||||
/** gets the index to sup book
|
||||
* @return sup book index
|
||||
*/
|
||||
public short getIndexToSupBook(){
|
||||
return field_1_index_to_supbook;
|
||||
}
|
||||
|
||||
/** sets the index to first sheet in supbook
|
||||
* @param index index to first sheet
|
||||
*/
|
||||
public void setIndexToFirstSupBook(short index){
|
||||
field_2_index_to_first_supbook_sheet = index;
|
||||
}
|
||||
|
||||
/** gets the index to first sheet from supbook
|
||||
* @return index to first supbook
|
||||
*/
|
||||
public short getIndexToFirstSupBook(){
|
||||
return field_2_index_to_first_supbook_sheet;
|
||||
}
|
||||
|
||||
/** sets the index to last sheet in supbook
|
||||
* @param index index to last sheet
|
||||
*/
|
||||
public void setIndexToLastSupBook(short index){
|
||||
field_3_index_to_last_supbook_sheet = index;
|
||||
}
|
||||
|
||||
/** gets the index to last sheet in supbook
|
||||
* @return index to last supbook
|
||||
*/
|
||||
public short getIndexToLastSupBook(){
|
||||
return field_3_index_to_last_supbook_sheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* called by constructor, should throw runtime exception in the event of a
|
||||
* record passed with a differing ID.
|
||||
*
|
||||
* @param id alleged id for this record
|
||||
*/
|
||||
protected void validateSid(short id) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
protected void fillFields(RecordInputStream in) {
|
||||
field_1_index_to_supbook = in.readShort();
|
||||
field_2_index_to_first_supbook_sheet = in.readShort();
|
||||
field_3_index_to_last_supbook_sheet = in.readShort();
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(" supbookindex =").append(getIndexToSupBook()).append('\n');
|
||||
buffer.append(" 1stsbindex =").append(getIndexToFirstSupBook()).append('\n');
|
||||
buffer.append(" lastsbindex =").append(getIndexToLastSupBook()).append('\n');
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* called by the class that is responsible for writing this sucker.
|
||||
* Subclasses should implement this so that their data is passed back in a
|
||||
* byte array.
|
||||
*
|
||||
* @param offset to begin writing at
|
||||
* @param data byte array containing instance data
|
||||
* @return number of bytes written
|
||||
*/
|
||||
public int serialize(int offset, byte [] data) {
|
||||
LittleEndian.putShort(data, 0 + offset, getIndexToSupBook());
|
||||
LittleEndian.putShort(data, 2 + offset, getIndexToFirstSupBook());
|
||||
LittleEndian.putShort(data, 4 + offset, getIndexToLastSupBook());
|
||||
|
||||
return getRecordSize();
|
||||
}
|
||||
|
||||
|
||||
/** returns the record size
|
||||
*/
|
||||
public int getRecordSize() {
|
||||
return 6;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the non static version of the id for this record.
|
||||
*/
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -22,7 +22,7 @@ import org.apache.poi.util.LittleEndian;
|
|||
|
||||
/**
|
||||
* Title: Sup Book (EXTERNALBOOK) <P>
|
||||
* Description: A External Workbook Description (Suplemental Book)
|
||||
* Description: A External Workbook Description (Supplemental Book)
|
||||
* Its only a dummy record for making new ExternSheet Record <P>
|
||||
* REFERENCE: 5.38<P>
|
||||
* @author Libin Roman (Vista Portal LDT. Developer)
|
||||
|
|
|
@ -110,7 +110,7 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
|
|||
* @return <code>true</code> if the name specifies a standard worksheet function,
|
||||
* <code>false</code> if the name should be assumed to be an external function.
|
||||
*/
|
||||
public static final boolean isInternalFunctionName(String name) {
|
||||
public static final boolean isBuiltInFunctionName(String name) {
|
||||
short ix = FunctionMetadataRegistry.lookupIndexByName(name.toUpperCase());
|
||||
return ix >= 0;
|
||||
}
|
||||
|
|
|
@ -22,41 +22,55 @@ import org.apache.poi.ss.usermodel.Workbook;
|
|||
import org.apache.poi.hssf.record.RecordInputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author aviks
|
||||
*
|
||||
* @author aviks
|
||||
*/
|
||||
public final class NameXPtg extends OperandPtg {
|
||||
public final static short sid = 0x39;
|
||||
private final static int SIZE = 7;
|
||||
private short field_1_ixals; // index to REF entry in externsheet record
|
||||
private short field_2_ilbl; //index to defined name or externname table(1 based)
|
||||
private short field_3_reserved; // reserved must be 0
|
||||
public final static short sid = 0x39;
|
||||
private final static int SIZE = 7;
|
||||
|
||||
/** index to REF entry in externsheet record */
|
||||
private int _sheetRefIndex;
|
||||
/** index to defined name or externname table(1 based) */
|
||||
private int _nameNumber;
|
||||
/** reserved must be 0 */
|
||||
private int _reserved;
|
||||
|
||||
public NameXPtg(RecordInputStream in) {
|
||||
field_1_ixals = in.readShort();
|
||||
field_2_ilbl = in.readShort();
|
||||
field_3_reserved = in.readShort();
|
||||
}
|
||||
private NameXPtg(int sheetRefIndex, int nameNumber, int reserved) {
|
||||
_sheetRefIndex = sheetRefIndex;
|
||||
_nameNumber = nameNumber;
|
||||
_reserved = reserved;
|
||||
}
|
||||
|
||||
public void writeBytes(byte [] array, int offset) {
|
||||
array[ offset + 0 ] = (byte)(sid + getPtgClass());
|
||||
LittleEndian.putShort(array, offset + 1, field_1_ixals);
|
||||
LittleEndian.putShort(array,offset+3, field_2_ilbl);
|
||||
LittleEndian.putShort(array, offset + 5, field_3_reserved);
|
||||
}
|
||||
/**
|
||||
* @param sheetRefIndex index to REF entry in externsheet record
|
||||
* @param nameIndex index to defined name or externname table
|
||||
*/
|
||||
public NameXPtg(int sheetRefIndex, int nameIndex) {
|
||||
this(sheetRefIndex, nameIndex + 1, 0);
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return SIZE;
|
||||
}
|
||||
public NameXPtg(RecordInputStream in) {
|
||||
this(in.readUShort(), in.readUShort(), in.readUShort());
|
||||
}
|
||||
|
||||
public String toFormulaString(Workbook book)
|
||||
{
|
||||
// -1 to convert definedNameIndex from 1-based to zero-based
|
||||
return book.resolveNameXText(field_1_ixals, field_2_ilbl-1);
|
||||
}
|
||||
|
||||
public byte getDefaultOperandClass() {
|
||||
public void writeBytes(byte[] array, int offset) {
|
||||
LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
|
||||
LittleEndian.putUShort(array, offset + 1, _sheetRefIndex);
|
||||
LittleEndian.putUShort(array, offset + 3, _nameNumber);
|
||||
LittleEndian.putUShort(array, offset + 5, _reserved);
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
public String toFormulaString(Workbook book) {
|
||||
// -1 to convert definedNameIndex from 1-based to zero-based
|
||||
return book.resolveNameXText(_sheetRefIndex, _nameNumber - 1);
|
||||
}
|
||||
|
||||
public byte getDefaultOperandClass() {
|
||||
return Ptg.CLASS_VALUE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,67 +23,57 @@ import org.apache.poi.hssf.util.RangeAddress;
|
|||
import org.apache.poi.ss.usermodel.Name;
|
||||
|
||||
/**
|
||||
* Title: High Level Represantion of Named Range <P>
|
||||
* REFERENCE: <P>
|
||||
* High Level Representation of a 'defined name' which could be a 'built-in' name,
|
||||
* 'named range' or name of a user defined function.
|
||||
*
|
||||
* @author Libin Roman (Vista Portal LDT. Developer)
|
||||
*/
|
||||
|
||||
public class HSSFName implements Name {
|
||||
private HSSFWorkbook book;
|
||||
private NameRecord name;
|
||||
private HSSFWorkbook _book;
|
||||
private NameRecord _definedNameRec;
|
||||
|
||||
/** Creates new HSSFName - called by HSSFWorkbook to create a sheet from
|
||||
* scratch.
|
||||
*
|
||||
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createName()
|
||||
* @param name the Name Record
|
||||
* @param book lowlevel Workbook object associated with the sheet.
|
||||
* @param book workbook object associated with the sheet.
|
||||
*/
|
||||
|
||||
protected HSSFName(HSSFWorkbook book, NameRecord name) {
|
||||
this.book = book;
|
||||
this.name = name;
|
||||
/* package */ HSSFName(HSSFWorkbook book, NameRecord name) {
|
||||
_book = book;
|
||||
_definedNameRec = name;
|
||||
}
|
||||
|
||||
/** Get the sheets name which this named range is referenced to
|
||||
* @return sheet name, which this named range refered to
|
||||
* @return sheet name, which this named range referred to
|
||||
*/
|
||||
|
||||
public String getSheetName() {
|
||||
String result ;
|
||||
short indexToExternSheet = name.getExternSheetNumber();
|
||||
short indexToExternSheet = _definedNameRec.getExternSheetNumber();
|
||||
|
||||
result = book.getWorkbook().findSheetNameFromExternSheet(indexToExternSheet);
|
||||
|
||||
return result;
|
||||
return _book.getWorkbook().findSheetNameFromExternSheet(indexToExternSheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the name of the named range
|
||||
* @return named range name
|
||||
* @return text name of this defined name
|
||||
*/
|
||||
|
||||
public String getNameName(){
|
||||
String result = name.getNameText();
|
||||
|
||||
return result;
|
||||
return _definedNameRec.getNameText();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the name of the named range
|
||||
* @param nameName named range name to set
|
||||
*/
|
||||
|
||||
public void setNameName(String nameName){
|
||||
name.setNameText(nameName);
|
||||
name.setNameTextLength((byte)nameName.length());
|
||||
Workbook wb = book.getWorkbook();
|
||||
_definedNameRec.setNameText(nameName);
|
||||
_definedNameRec.setNameTextLength((byte)nameName.length());
|
||||
Workbook wb = _book.getWorkbook();
|
||||
|
||||
//Check to ensure no other names have the same case-insensitive name
|
||||
for ( int i = wb.getNumNames()-1; i >=0; i-- )
|
||||
{
|
||||
NameRecord rec = wb.getNameRecord(i);
|
||||
if (rec != name) {
|
||||
if (rec != _definedNameRec) {
|
||||
if (rec.getNameText().equalsIgnoreCase(getNameName()))
|
||||
throw new IllegalArgumentException("The workbook already contains this name (case-insensitive)");
|
||||
}
|
||||
|
@ -91,32 +81,25 @@ public class HSSFName implements Name {
|
|||
}
|
||||
|
||||
/**
|
||||
* gets the reference of the named range
|
||||
* @return reference of the named range
|
||||
* Note - this method only applies to named ranges
|
||||
* @return the formula text defining the named range
|
||||
*/
|
||||
|
||||
public String getReference() {
|
||||
String result;
|
||||
result = name.getAreaReference(book);
|
||||
|
||||
return result;
|
||||
if (_definedNameRec.isFunctionName()) {
|
||||
throw new IllegalStateException("Only applicable to named ranges");
|
||||
}
|
||||
return _definedNameRec.getAreaReference(_book);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* sets the sheet name which this named range referenced to
|
||||
* @param sheetName the sheet name of the reference
|
||||
*/
|
||||
|
||||
private void setSheetName(String sheetName){
|
||||
int sheetNumber = book.getSheetIndex(sheetName);
|
||||
|
||||
int sheetNumber = _book.getSheetIndex(sheetName);
|
||||
short externSheetNumber = (short)
|
||||
book.getExternalSheetIndex(sheetNumber);
|
||||
name.setExternSheetNumber(externSheetNumber);
|
||||
// name.setIndexToSheet(externSheetNumber);
|
||||
|
||||
_book.getExternalSheetIndex(sheetNumber);
|
||||
_definedNameRec.setExternSheetNumber(externSheetNumber);
|
||||
}
|
||||
|
||||
|
||||
|
@ -124,7 +107,6 @@ public class HSSFName implements Name {
|
|||
* sets the reference of this named range
|
||||
* @param ref the reference to set
|
||||
*/
|
||||
|
||||
public void setReference(String ref){
|
||||
|
||||
RangeAddress ra = new RangeAddress(ref);
|
||||
|
@ -136,8 +118,7 @@ public class HSSFName implements Name {
|
|||
}
|
||||
|
||||
//allow the poi utilities to parse it out
|
||||
name.setAreaReference(ref);
|
||||
|
||||
_definedNameRec.setAreaReference(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,4 +130,14 @@ public class HSSFName implements Name {
|
|||
String ref = getReference();
|
||||
return "#REF!".endsWith(ref);
|
||||
}
|
||||
public boolean isFunctionName() {
|
||||
return _definedNameRec.isFunctionName();
|
||||
}
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(64);
|
||||
sb.append(getClass().getName()).append(" [");
|
||||
sb.append(_definedNameRec.getNameText());
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ import org.apache.poi.hssf.record.UnicodeString;
|
|||
import org.apache.poi.hssf.record.UnknownRecord;
|
||||
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.MemFuncPtg;
|
||||
import org.apache.poi.hssf.record.formula.NameXPtg;
|
||||
import org.apache.poi.hssf.record.formula.UnionPtg;
|
||||
import org.apache.poi.hssf.util.CellReference;
|
||||
import org.apache.poi.hssf.util.SheetReferences;
|
||||
|
@ -77,6 +78,9 @@ import org.apache.poi.util.POILogger;
|
|||
*/
|
||||
public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook
|
||||
{
|
||||
private static final int MAX_ROW = 0xFFFF;
|
||||
private static final short MAX_COLUMN = (short)0x00FF;
|
||||
|
||||
private static final int DEBUG = POILogger.DEBUG;
|
||||
|
||||
/**
|
||||
|
@ -856,7 +860,8 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
|||
|
||||
/**
|
||||
* Sets the repeating rows and columns for a sheet (as found in
|
||||
* File->PageSetup->Sheet). This is function is included in the workbook
|
||||
* 2003:File->PageSetup->Sheet, 2007:Page Layout->Print Titles).
|
||||
* This is function is included in the workbook
|
||||
* because it creates/modifies name records which are stored at the
|
||||
* workbook level.
|
||||
* <p>
|
||||
|
@ -886,10 +891,10 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
|||
// Check arguments
|
||||
if (startColumn == -1 && endColumn != -1) throw new IllegalArgumentException("Invalid column range specification");
|
||||
if (startRow == -1 && endRow != -1) throw new IllegalArgumentException("Invalid row range specification");
|
||||
if (startColumn < -1 || startColumn >= 0xFF) throw new IllegalArgumentException("Invalid column range specification");
|
||||
if (endColumn < -1 || endColumn >= 0xFF) throw new IllegalArgumentException("Invalid column range specification");
|
||||
if (startRow < -1 || startRow > 65535) throw new IllegalArgumentException("Invalid row range specification");
|
||||
if (endRow < -1 || endRow > 65535) throw new IllegalArgumentException("Invalid row range specification");
|
||||
if (startColumn < -1 || startColumn >= MAX_COLUMN) throw new IllegalArgumentException("Invalid column range specification");
|
||||
if (endColumn < -1 || endColumn >= MAX_COLUMN) throw new IllegalArgumentException("Invalid column range specification");
|
||||
if (startRow < -1 || startRow > MAX_ROW) throw new IllegalArgumentException("Invalid row range specification");
|
||||
if (endRow < -1 || endRow > MAX_ROW) throw new IllegalArgumentException("Invalid row range specification");
|
||||
if (startColumn > endColumn) throw new IllegalArgumentException("Invalid column range specification");
|
||||
if (startRow > endRow) throw new IllegalArgumentException("Invalid row range specification");
|
||||
|
||||
|
@ -901,50 +906,60 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
|||
boolean removingRange =
|
||||
startColumn == -1 && endColumn == -1 && startRow == -1 && endRow == -1;
|
||||
|
||||
boolean isNewRecord = false;
|
||||
NameRecord nameRecord;
|
||||
nameRecord = findExistingRowColHeaderNameRecord(sheetIndex);
|
||||
if (removingRange )
|
||||
{
|
||||
if (nameRecord != null)
|
||||
workbook.removeName(findExistingRowColHeaderNameRecordIdx(sheetIndex+1));
|
||||
int rowColHeaderNameIndex = findExistingRowColHeaderNameRecordIdx(sheetIndex);
|
||||
if (removingRange) {
|
||||
if (rowColHeaderNameIndex >= 0) {
|
||||
workbook.removeName(rowColHeaderNameIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( nameRecord == null )
|
||||
{
|
||||
nameRecord = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_TITLE, sheetIndex+1);
|
||||
boolean isNewRecord;
|
||||
NameRecord nameRecord;
|
||||
if (rowColHeaderNameIndex < 0) {
|
||||
//does a lot of the house keeping for builtin records, like setting lengths to zero etc
|
||||
nameRecord = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_TITLE, sheetIndex+1);
|
||||
isNewRecord = true;
|
||||
} else {
|
||||
nameRecord = workbook.getNameRecord(rowColHeaderNameIndex);
|
||||
isNewRecord = false;
|
||||
}
|
||||
|
||||
short definitionTextLength = settingRowAndColumn ? (short)0x001a : (short)0x000b;
|
||||
nameRecord.setDefinitionTextLength(definitionTextLength);
|
||||
nameRecord.setDefinitionTextLength(definitionTextLength); // TODO - remove
|
||||
|
||||
Stack ptgs = new Stack();
|
||||
|
||||
if (settingRowAndColumn)
|
||||
{
|
||||
ptgs.add(new MemFuncPtg(23)); // TODO - where did constant '23' come from?
|
||||
if (settingRowAndColumn) {
|
||||
final int exprsSize = 2 * 11 + 1; // Area3DPtg.SIZE + UnionPtg.SIZE
|
||||
ptgs.add(new MemFuncPtg(exprsSize));
|
||||
}
|
||||
if (startColumn >= 0)
|
||||
{
|
||||
Area3DPtg area3DPtg1 = new Area3DPtg();
|
||||
area3DPtg1.setExternSheetIndex(externSheetIndex);
|
||||
area3DPtg1.setFirstColumn((short)startColumn);
|
||||
area3DPtg1.setLastColumn((short)endColumn);
|
||||
area3DPtg1.setFirstRow((short)0);
|
||||
area3DPtg1.setLastRow((short)0xFFFF);
|
||||
ptgs.add(area3DPtg1);
|
||||
Area3DPtg colArea = new Area3DPtg();
|
||||
colArea.setExternSheetIndex(externSheetIndex);
|
||||
colArea.setFirstColumn((short)startColumn);
|
||||
colArea.setLastColumn((short)endColumn);
|
||||
colArea.setFirstRow(0);
|
||||
colArea.setLastRow(MAX_ROW);
|
||||
colArea.setFirstColRelative(false);
|
||||
colArea.setLastColRelative(false);
|
||||
colArea.setFirstRowRelative(false);
|
||||
colArea.setLastRowRelative(false);
|
||||
ptgs.add(colArea);
|
||||
}
|
||||
if (startRow >= 0)
|
||||
{
|
||||
Area3DPtg area3DPtg2 = new Area3DPtg();
|
||||
area3DPtg2.setExternSheetIndex(externSheetIndex);
|
||||
area3DPtg2.setFirstColumn((short)0);
|
||||
area3DPtg2.setLastColumn((short)0x00FF);
|
||||
area3DPtg2.setFirstRow((short)startRow);
|
||||
area3DPtg2.setLastRow((short)endRow);
|
||||
ptgs.add(area3DPtg2);
|
||||
Area3DPtg rowArea = new Area3DPtg();
|
||||
rowArea.setExternSheetIndex(externSheetIndex);
|
||||
rowArea.setFirstColumn((short)0);
|
||||
rowArea.setLastColumn(MAX_COLUMN);
|
||||
rowArea.setFirstRow(startRow);
|
||||
rowArea.setLastRow(endRow);
|
||||
rowArea.setFirstColRelative(false);
|
||||
rowArea.setLastColRelative(false);
|
||||
rowArea.setFirstRowRelative(false);
|
||||
rowArea.setLastRowRelative(false);
|
||||
ptgs.add(rowArea);
|
||||
}
|
||||
if (settingRowAndColumn)
|
||||
{
|
||||
|
@ -964,38 +979,31 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
|||
sheet.setActive(true);
|
||||
}
|
||||
|
||||
private NameRecord findExistingRowColHeaderNameRecord( int sheetIndex )
|
||||
{
|
||||
int index = findExistingRowColHeaderNameRecordIdx(sheetIndex);
|
||||
if (index == -1)
|
||||
return null;
|
||||
else
|
||||
return (NameRecord)workbook.findNextRecordBySid(NameRecord.sid, index);
|
||||
}
|
||||
|
||||
private int findExistingRowColHeaderNameRecordIdx( int sheetIndex )
|
||||
{
|
||||
int index = 0;
|
||||
NameRecord r = null;
|
||||
while ((r = (NameRecord) workbook.findNextRecordBySid(NameRecord.sid, index)) != null)
|
||||
{
|
||||
int indexToSheet = r.getEqualsToIndexToSheet() -1;
|
||||
if(indexToSheet > -1) { //ignore "GLOBAL" name records
|
||||
int nameRecordSheetIndex = workbook.getSheetIndexFromExternSheetIndex(indexToSheet);
|
||||
if (isRowColHeaderRecord( r ) && nameRecordSheetIndex == sheetIndex)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
private int findExistingRowColHeaderNameRecordIdx(int sheetIndex) {
|
||||
for(int defNameIndex =0; defNameIndex<names.size(); defNameIndex++) {
|
||||
NameRecord r = workbook.getNameRecord(defNameIndex);
|
||||
if (r == null) {
|
||||
throw new RuntimeException("Unable to find all defined names to iterate over");
|
||||
}
|
||||
if (!isRowColHeaderRecord( r )) {
|
||||
continue;
|
||||
}
|
||||
if(r.getSheetNumber() == 0) {
|
||||
//ignore "GLOBAL" name records
|
||||
continue;
|
||||
}
|
||||
int externIndex = r.getSheetNumber() -1;
|
||||
int nameRecordSheetIndex = workbook.getSheetIndexFromExternSheetIndex(externIndex);
|
||||
if (nameRecordSheetIndex == sheetIndex) {
|
||||
return defNameIndex;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private boolean isRowColHeaderRecord( NameRecord r )
|
||||
{
|
||||
return r.getOptionFlag() == 0x20 && ("" + ((char)7)).equals(r.getNameText());
|
||||
private static boolean isRowColHeaderRecord(NameRecord r) {
|
||||
return r.isBuiltInName() && r.getBuiltInName() == NameRecord.BUILTIN_PRINT_TITLE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1089,7 +1097,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
|||
* and that's not something you should normally do
|
||||
*/
|
||||
protected void resetFontCache() {
|
||||
fonts = new Hashtable();
|
||||
fonts = new Hashtable();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1658,9 +1666,16 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
|||
return new HSSFCreationHelper(this);
|
||||
}
|
||||
|
||||
private byte[] newUID()
|
||||
{
|
||||
byte[] bytes = new byte[16];
|
||||
return bytes;
|
||||
private static byte[] newUID() {
|
||||
return new byte[16];
|
||||
}
|
||||
|
||||
/**
|
||||
* Note - This method should only used by POI internally.
|
||||
* It may get deleted or change definition in future POI versions
|
||||
*/
|
||||
public NameXPtg getNameXPtg(String name) {
|
||||
return workbook.getNameXPtg(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,4 +19,5 @@ package org.apache.poi.ss.usermodel;
|
|||
|
||||
public interface Name {
|
||||
void setNameName(String nameName);
|
||||
boolean isFunctionName();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ public interface Workbook {
|
|||
|
||||
HSSFName createName();
|
||||
HSSFName getNameAt(int index);
|
||||
int getNameIndex(String name);
|
||||
String getNameName(int index);
|
||||
String resolveNameXText(int refIndex, int definedNameIndex);
|
||||
|
||||
|
|
|
@ -53,4 +53,5 @@ public interface Name {
|
|||
|
||||
void setReference(String ref);
|
||||
|
||||
}
|
||||
boolean isFunctionName();
|
||||
}
|
||||
|
|
|
@ -219,24 +219,25 @@ public class HWPFDocument extends POIDocument
|
|||
_dataStream = new byte[0];
|
||||
}
|
||||
|
||||
// get the start of text in the main stream
|
||||
int fcMin = _fib.getFcMin();
|
||||
// Get the cp of the start of text in the main stream
|
||||
// The latest spec doc says this is always zero!
|
||||
int fcMin = 0;
|
||||
//fcMin = _fib.getFcMin()
|
||||
|
||||
// load up our standard structures.
|
||||
// Start to load up our standard structures.
|
||||
_dop = new DocumentProperties(_tableStream, _fib.getFcDop());
|
||||
_cft = new ComplexFileTable(_mainStream, _tableStream, _fib.getFcClx(), fcMin);
|
||||
_tpt = _cft.getTextPieceTable();
|
||||
_cbt = new CHPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbteChpx(), _fib.getLcbPlcfbteChpx(), fcMin);
|
||||
_pbt = new PAPBinTable(_mainStream, _tableStream, _dataStream, _fib.getFcPlcfbtePapx(), _fib.getLcbPlcfbtePapx(), fcMin);
|
||||
|
||||
// Word XP puts in a zero filled buffer in front of the text and it screws
|
||||
// up my system for offsets. This is an adjustment.
|
||||
|
||||
// Word XP and later all put in a zero filled buffer in
|
||||
// front of the text. This screws up the system for offsets,
|
||||
// which assume we always start at zero. This is an adjustment.
|
||||
int cpMin = _tpt.getCpMin();
|
||||
if (cpMin > 0)
|
||||
{
|
||||
_cbt.adjustForDelete(0, 0, cpMin);
|
||||
_pbt.adjustForDelete(0, 0, cpMin);
|
||||
}
|
||||
|
||||
// Now load the rest of the properties, which need to be adjusted
|
||||
// for where text really begin
|
||||
_cbt = new CHPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbteChpx(), _fib.getLcbPlcfbteChpx(), cpMin, _tpt);
|
||||
_pbt = new PAPBinTable(_mainStream, _tableStream, _dataStream, _fib.getFcPlcfbtePapx(), _fib.getLcbPlcfbtePapx(), cpMin, _tpt);
|
||||
|
||||
// Read FSPA and Escher information
|
||||
_fspa = new FSPATable(_tableStream, _fib.getFcPlcspaMom(), _fib.getLcbPlcspaMom(), getTextTable().getTextPieces());
|
||||
|
@ -252,7 +253,7 @@ public class HWPFDocument extends POIDocument
|
|||
// read in the pictures stream
|
||||
_pictures = new PicturesTable(this, _dataStream, _mainStream, _fspa, _dgg);
|
||||
|
||||
_st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin, getTextTable().getTextPieces());
|
||||
_st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin, _tpt, _cpSplit);
|
||||
_ss = new StyleSheet(_tableStream, _fib.getFcStshf());
|
||||
_ft = new FontTable(_tableStream, _fib.getFcSttbfffn(), _fib.getLcbSttbfffn());
|
||||
|
||||
|
@ -316,6 +317,11 @@ public class HWPFDocument extends POIDocument
|
|||
* document, but excludes any headers and footers.
|
||||
*/
|
||||
public Range getRange() {
|
||||
// First up, trigger a full-recalculate
|
||||
// Needed in case of deletes etc
|
||||
getOverallRange();
|
||||
|
||||
// Now, return the real one
|
||||
return new Range(
|
||||
_cpSplit.getMainDocumentStart(),
|
||||
_cpSplit.getMainDocumentEnd(),
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/* ====================================================================
|
||||
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.model;
|
||||
|
||||
/**
|
||||
* Normally PropertyNodes only ever work in characters, but
|
||||
* a few cases actually store bytes, and this lets everything
|
||||
* still work despite that.
|
||||
* It handles the conversion as required between bytes
|
||||
* and characters.
|
||||
*/
|
||||
public abstract class BytePropertyNode extends PropertyNode {
|
||||
private boolean isUnicode;
|
||||
|
||||
/**
|
||||
* @param fcStart The start of the text for this property, in _bytes_
|
||||
* @param fcEnd The end of the text for this property, in _bytes_
|
||||
*/
|
||||
public BytePropertyNode(int fcStart, int fcEnd, Object buf, boolean isUnicode) {
|
||||
super(
|
||||
generateCp(fcStart, isUnicode),
|
||||
generateCp(fcEnd, isUnicode),
|
||||
buf
|
||||
);
|
||||
this.isUnicode = isUnicode;
|
||||
}
|
||||
private static int generateCp(int val, boolean isUnicode) {
|
||||
if(isUnicode)
|
||||
return val/2;
|
||||
return val;
|
||||
}
|
||||
|
||||
public boolean isUnicode() {
|
||||
return isUnicode;
|
||||
}
|
||||
public int getStartBytes() {
|
||||
if(isUnicode)
|
||||
return getStart()*2;
|
||||
return getStart();
|
||||
}
|
||||
public int getEndBytes() {
|
||||
if(isUnicode)
|
||||
return getEnd()*2;
|
||||
return getEnd();
|
||||
}
|
||||
}
|
|
@ -37,6 +37,8 @@ public class CHPBinTable
|
|||
/** List of character properties.*/
|
||||
protected ArrayList _textRuns = new ArrayList();
|
||||
|
||||
/** So we can know if things are unicode or not */
|
||||
private TextPieceTable tpt;
|
||||
|
||||
public CHPBinTable()
|
||||
{
|
||||
|
@ -52,9 +54,10 @@ public class CHPBinTable
|
|||
* @param fcMin
|
||||
*/
|
||||
public CHPBinTable(byte[] documentStream, byte[] tableStream, int offset,
|
||||
int size, int fcMin)
|
||||
int size, int fcMin, TextPieceTable tpt)
|
||||
{
|
||||
PlexOfCps binTable = new PlexOfCps(tableStream, offset, size, 4);
|
||||
this.tpt = tpt;
|
||||
|
||||
int length = binTable.length();
|
||||
for (int x = 0; x < length; x++)
|
||||
|
@ -65,7 +68,7 @@ public class CHPBinTable
|
|||
int pageOffset = POIFSConstants.BIG_BLOCK_SIZE * pageNum;
|
||||
|
||||
CHPFormattedDiskPage cfkp = new CHPFormattedDiskPage(documentStream,
|
||||
pageOffset, fcMin);
|
||||
pageOffset, fcMin, tpt);
|
||||
|
||||
int fkpSize = cfkp.size();
|
||||
|
||||
|
@ -116,7 +119,14 @@ public class CHPBinTable
|
|||
|
||||
public void insert(int listIndex, int cpStart, SprmBuffer buf)
|
||||
{
|
||||
CHPX insertChpx = new CHPX(cpStart, cpStart, buf);
|
||||
boolean needsToBeUnicode = tpt.isUnicodeAtCharOffset(cpStart);
|
||||
|
||||
CHPX insertChpx = new CHPX(0, 0, buf, needsToBeUnicode);
|
||||
|
||||
// Ensure character offsets are really characters
|
||||
insertChpx.setStart(cpStart);
|
||||
insertChpx.setEnd(cpStart);
|
||||
|
||||
if (listIndex == _textRuns.size())
|
||||
{
|
||||
_textRuns.add(insertChpx);
|
||||
|
@ -126,7 +136,16 @@ public class CHPBinTable
|
|||
CHPX chpx = (CHPX)_textRuns.get(listIndex);
|
||||
if (chpx.getStart() < cpStart)
|
||||
{
|
||||
CHPX clone = new CHPX(cpStart, chpx.getEnd(), chpx.getSprmBuf());
|
||||
// Copy the properties of the one before to afterwards
|
||||
// Will go:
|
||||
// Original, until insert at point
|
||||
// New one
|
||||
// Clone of original, on to the old end
|
||||
CHPX clone = new CHPX(0, 0, chpx.getSprmBuf(), needsToBeUnicode);
|
||||
// Again ensure contains character based offsets no matter what
|
||||
clone.setStart(cpStart);
|
||||
clone.setEnd(chpx.getEnd());
|
||||
|
||||
chpx.setEnd(cpStart);
|
||||
|
||||
_textRuns.add(listIndex + 1, insertChpx);
|
||||
|
|
|
@ -55,13 +55,14 @@ public class CHPFormattedDiskPage extends FormattedDiskPage
|
|||
* This constructs a CHPFormattedDiskPage from a raw fkp (512 byte array
|
||||
* read from a Word file).
|
||||
*/
|
||||
public CHPFormattedDiskPage(byte[] documentStream, int offset, int fcMin)
|
||||
public CHPFormattedDiskPage(byte[] documentStream, int offset, int fcMin, TextPieceTable tpt)
|
||||
{
|
||||
super(documentStream, offset);
|
||||
|
||||
for (int x = 0; x < _crun; x++)
|
||||
{
|
||||
_chpxList.add(new CHPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x)));
|
||||
boolean isUnicode = tpt.isUnicodeAtByteOffset( getStart(x) );
|
||||
_chpxList.add(new CHPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x), isUnicode));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +158,7 @@ public class CHPFormattedDiskPage extends FormattedDiskPage
|
|||
chpx = (CHPX)_chpxList.get(x);
|
||||
byte[] grpprl = chpx.getGrpprl();
|
||||
|
||||
LittleEndian.putInt(buf, fcOffset, chpx.getStart() + fcMin);
|
||||
LittleEndian.putInt(buf, fcOffset, chpx.getStartBytes() + fcMin);
|
||||
grpprlOffset -= (1 + grpprl.length);
|
||||
grpprlOffset -= (grpprlOffset % 2);
|
||||
buf[offsetOffset] = (byte)(grpprlOffset/2);
|
||||
|
@ -168,7 +169,7 @@ public class CHPFormattedDiskPage extends FormattedDiskPage
|
|||
fcOffset += FC_SIZE;
|
||||
}
|
||||
// put the last chpx's end in
|
||||
LittleEndian.putInt(buf, fcOffset, chpx.getEnd() + fcMin);
|
||||
LittleEndian.putInt(buf, fcOffset, chpx.getEndBytes() + fcMin);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,22 +25,26 @@ import org.apache.poi.hwpf.sprm.SprmBuffer;
|
|||
import org.apache.poi.hwpf.sprm.CharacterSprmUncompressor;
|
||||
|
||||
/**
|
||||
* Comment me
|
||||
* DANGER - works in bytes!
|
||||
*
|
||||
* Make sure you call getStart() / getEnd() when you want characters
|
||||
* (normal use), but getStartByte() / getEndByte() when you're
|
||||
* reading in / writing out!
|
||||
*
|
||||
* @author Ryan Ackley
|
||||
*/
|
||||
|
||||
public class CHPX extends PropertyNode
|
||||
public class CHPX extends BytePropertyNode
|
||||
{
|
||||
|
||||
public CHPX(int fcStart, int fcEnd, byte[] grpprl)
|
||||
public CHPX(int fcStart, int fcEnd, byte[] grpprl, boolean isUnicode)
|
||||
{
|
||||
super(fcStart, fcEnd, new SprmBuffer(grpprl));
|
||||
super(fcStart, fcEnd, new SprmBuffer(grpprl), isUnicode);
|
||||
}
|
||||
|
||||
public CHPX(int fcStart, int fcEnd, SprmBuffer buf)
|
||||
public CHPX(int fcStart, int fcEnd, SprmBuffer buf, boolean isUnicode)
|
||||
{
|
||||
super(fcStart, fcEnd, buf);
|
||||
super(fcStart, fcEnd, buf, isUnicode);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -39,14 +39,18 @@ public class PAPBinTable
|
|||
protected ArrayList _paragraphs = new ArrayList();
|
||||
byte[] _dataStream;
|
||||
|
||||
/** So we can know if things are unicode or not */
|
||||
private TextPieceTable tpt;
|
||||
|
||||
public PAPBinTable()
|
||||
{
|
||||
}
|
||||
|
||||
public PAPBinTable(byte[] documentStream, byte[] tableStream, byte[] dataStream, int offset,
|
||||
int size, int fcMin)
|
||||
int size, int fcMin, TextPieceTable tpt)
|
||||
{
|
||||
PlexOfCps binTable = new PlexOfCps(tableStream, offset, size, 4);
|
||||
this.tpt = tpt;
|
||||
|
||||
int length = binTable.length();
|
||||
for (int x = 0; x < length; x++)
|
||||
|
@ -57,13 +61,14 @@ public class PAPBinTable
|
|||
int pageOffset = POIFSConstants.BIG_BLOCK_SIZE * pageNum;
|
||||
|
||||
PAPFormattedDiskPage pfkp = new PAPFormattedDiskPage(documentStream,
|
||||
dataStream, pageOffset, fcMin);
|
||||
dataStream, pageOffset, fcMin, tpt);
|
||||
|
||||
int fkpSize = pfkp.size();
|
||||
|
||||
for (int y = 0; y < fkpSize; y++)
|
||||
{
|
||||
_paragraphs.add(pfkp.getPAPX(y));
|
||||
PAPX papx = pfkp.getPAPX(y);
|
||||
_paragraphs.add(papx);
|
||||
}
|
||||
}
|
||||
_dataStream = dataStream;
|
||||
|
@ -71,7 +76,14 @@ public class PAPBinTable
|
|||
|
||||
public void insert(int listIndex, int cpStart, SprmBuffer buf)
|
||||
{
|
||||
PAPX forInsert = new PAPX(cpStart, cpStart, buf, _dataStream);
|
||||
boolean needsToBeUnicode = tpt.isUnicodeAtCharOffset(cpStart);
|
||||
|
||||
PAPX forInsert = new PAPX(0, 0, buf, _dataStream, needsToBeUnicode);
|
||||
|
||||
// Ensure character offsets are really characters
|
||||
forInsert.setStart(cpStart);
|
||||
forInsert.setEnd(cpStart);
|
||||
|
||||
if (listIndex == _paragraphs.size())
|
||||
{
|
||||
_paragraphs.add(forInsert);
|
||||
|
@ -90,10 +102,21 @@ public class PAPBinTable
|
|||
{
|
||||
exc.printStackTrace();
|
||||
}
|
||||
|
||||
// Copy the properties of the one before to afterwards
|
||||
// Will go:
|
||||
// Original, until insert at point
|
||||
// New one
|
||||
// Clone of original, on to the old end
|
||||
PAPX clone = new PAPX(0, 0, clonedBuf, _dataStream, needsToBeUnicode);
|
||||
// Again ensure contains character based offsets no matter what
|
||||
clone.setStart(cpStart);
|
||||
clone.setEnd(currentPap.getEnd());
|
||||
|
||||
currentPap.setEnd(cpStart);
|
||||
PAPX splitPap = new PAPX(cpStart, currentPap.getEnd(), clonedBuf, _dataStream);
|
||||
_paragraphs.add(++listIndex, forInsert);
|
||||
_paragraphs.add(++listIndex, splitPap);
|
||||
|
||||
_paragraphs.add(listIndex + 1, forInsert);
|
||||
_paragraphs.add(listIndex + 2, clone);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -60,13 +60,17 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
|
|||
/**
|
||||
* Creates a PAPFormattedDiskPage from a 512 byte array
|
||||
*/
|
||||
public PAPFormattedDiskPage(byte[] documentStream, byte[] dataStream, int offset, int fcMin)
|
||||
public PAPFormattedDiskPage(byte[] documentStream, byte[] dataStream, int offset, int fcMin, TextPieceTable tpt)
|
||||
{
|
||||
super(documentStream, offset);
|
||||
|
||||
for (int x = 0; x < _crun; x++)
|
||||
{
|
||||
_papxList.add(new PAPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x), getParagraphHeight(x), dataStream));
|
||||
for (int x = 0; x < _crun; x++) {
|
||||
int startAt = getStart(x) - fcMin;
|
||||
int endAt = getEnd(x) - fcMin;
|
||||
boolean isUnicode = tpt.isUnicodeAtByteOffset(startAt);
|
||||
//System.err.println(startAt + " -> " + endAt + " = " + isUnicode);
|
||||
|
||||
_papxList.add(new PAPX(startAt, endAt, getGrpprl(x), getParagraphHeight(x), dataStream, isUnicode));
|
||||
}
|
||||
_fkp = null;
|
||||
_dataStream = dataStream;
|
||||
|
@ -110,7 +114,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the papx for the paragraph at index in this fkp.
|
||||
* Gets the papx grpprl for the paragraph at index in this fkp.
|
||||
*
|
||||
* @param index The index of the papx to get.
|
||||
* @return a papx grpprl.
|
||||
|
@ -259,7 +263,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
|
|||
grpprlOffset -= (grpprl.length + (2 - grpprl.length % 2));
|
||||
grpprlOffset -= (grpprlOffset % 2);
|
||||
}
|
||||
LittleEndian.putInt(buf, fcOffset, papx.getStart() + fcMin);
|
||||
LittleEndian.putInt(buf, fcOffset, papx.getStartBytes() + fcMin);
|
||||
buf[bxOffset] = (byte)(grpprlOffset/2);
|
||||
System.arraycopy(phe, 0, buf, bxOffset + 1, phe.length);
|
||||
|
||||
|
@ -287,7 +291,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
|
|||
|
||||
}
|
||||
|
||||
LittleEndian.putInt(buf, fcOffset, papx.getEnd() + fcMin);
|
||||
LittleEndian.putInt(buf, fcOffset, papx.getEndBytes() + fcMin);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,29 +29,32 @@ import org.apache.poi.hwpf.sprm.SprmBuffer;
|
|||
import org.apache.poi.hwpf.sprm.SprmOperation;
|
||||
|
||||
/**
|
||||
* Comment me
|
||||
* DANGER - works in bytes!
|
||||
*
|
||||
* Make sure you call getStart() / getEnd() when you want characters
|
||||
* (normal use), but getStartByte() / getEndByte() when you're
|
||||
* reading in / writing out!
|
||||
*
|
||||
* @author Ryan Ackley
|
||||
*/
|
||||
|
||||
public class PAPX extends PropertyNode
|
||||
{
|
||||
public class PAPX extends BytePropertyNode {
|
||||
|
||||
private ParagraphHeight _phe;
|
||||
private int _hugeGrpprlOffset = -1;
|
||||
|
||||
public PAPX(int fcStart, int fcEnd, byte[] papx, ParagraphHeight phe, byte[] dataStream)
|
||||
public PAPX(int fcStart, int fcEnd, byte[] papx, ParagraphHeight phe, byte[] dataStream, boolean isUnicode)
|
||||
{
|
||||
super(fcStart, fcEnd, new SprmBuffer(papx));
|
||||
super(fcStart, fcEnd, new SprmBuffer(papx), isUnicode);
|
||||
_phe = phe;
|
||||
SprmBuffer buf = findHuge(new SprmBuffer(papx), dataStream);
|
||||
if(buf != null)
|
||||
_buf = buf;
|
||||
}
|
||||
|
||||
public PAPX(int fcStart, int fcEnd, SprmBuffer buf, byte[] dataStream)
|
||||
public PAPX(int fcStart, int fcEnd, SprmBuffer buf, byte[] dataStream, boolean isUnicode)
|
||||
{
|
||||
super(fcStart, fcEnd, buf);
|
||||
super(fcStart, fcEnd, buf, isUnicode);
|
||||
_phe = new ParagraphHeight();
|
||||
buf = findHuge(buf, dataStream);
|
||||
if(buf != null)
|
||||
|
|
|
@ -22,7 +22,10 @@ import java.util.Arrays;
|
|||
|
||||
/**
|
||||
* Represents a lightweight node in the Trees used to store content
|
||||
* properties. Works only in characters.
|
||||
* properties.
|
||||
* This only ever works in characters. For the few odd cases when
|
||||
* the start and end aren't in characters (eg PAPX and CHPX), use
|
||||
* {@link BytePropertyNode} between you and this.
|
||||
*
|
||||
* @author Ryan Ackley
|
||||
*/
|
||||
|
@ -45,6 +48,11 @@ public abstract class PropertyNode implements Comparable, Cloneable
|
|||
_cpStart = fcStart;
|
||||
_cpEnd = fcEnd;
|
||||
_buf = buf;
|
||||
|
||||
if(_cpStart < 0) {
|
||||
System.err.println("A property claimed to start before zero, at " + _cpStart + "! Resetting it to zero, and hoping for the best");
|
||||
_cpStart = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,18 +90,18 @@ public abstract class PropertyNode implements Comparable, Cloneable
|
|||
{
|
||||
int end = start + length;
|
||||
|
||||
if (_cpEnd > start)
|
||||
{
|
||||
if (_cpStart < end)
|
||||
{
|
||||
_cpEnd = end >= _cpEnd ? start : _cpEnd - length;
|
||||
_cpStart = Math.min(start, _cpStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cpEnd -= length;
|
||||
_cpStart -= length;
|
||||
}
|
||||
if (_cpEnd > start) {
|
||||
// The start of the change is before we end
|
||||
|
||||
if (_cpStart < end) {
|
||||
// The delete was somewhere in the middle of us
|
||||
_cpEnd = end >= _cpEnd ? start : _cpEnd - length;
|
||||
_cpStart = Math.min(start, _cpStart);
|
||||
} else {
|
||||
// The delete was before us
|
||||
_cpEnd -= length;
|
||||
_cpStart -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,19 +20,20 @@
|
|||
|
||||
package org.apache.poi.hwpf.model;
|
||||
|
||||
import org.apache.poi.hwpf.sprm.SprmBuffer;
|
||||
import org.apache.poi.hwpf.sprm.SectionSprmUncompressor;
|
||||
import org.apache.poi.hwpf.sprm.SectionSprmCompressor;
|
||||
import org.apache.poi.hwpf.sprm.SectionSprmUncompressor;
|
||||
import org.apache.poi.hwpf.usermodel.SectionProperties;
|
||||
|
||||
public class SEPX extends PropertyNode
|
||||
/**
|
||||
*/
|
||||
public class SEPX extends BytePropertyNode
|
||||
{
|
||||
|
||||
SectionDescriptor _sed;
|
||||
|
||||
public SEPX(SectionDescriptor sed, int start, int end, byte[] grpprl)
|
||||
public SEPX(SectionDescriptor sed, int start, int end, byte[] grpprl, boolean isUnicode)
|
||||
{
|
||||
super(start, end, SectionSprmUncompressor.uncompressSEP(grpprl, 0));
|
||||
super(start, end, SectionSprmUncompressor.uncompressSEP(grpprl, 0), isUnicode);
|
||||
_sed = sed;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@ public class SectionTable
|
|||
protected ArrayList _sections = new ArrayList();
|
||||
protected List _text;
|
||||
|
||||
/** So we can know if things are unicode or not */
|
||||
private TextPieceTable tpt;
|
||||
|
||||
public SectionTable()
|
||||
{
|
||||
}
|
||||
|
@ -41,10 +44,11 @@ public class SectionTable
|
|||
|
||||
public SectionTable(byte[] documentStream, byte[] tableStream, int offset,
|
||||
int size, int fcMin,
|
||||
List tpt)
|
||||
TextPieceTable tpt, CPSplitCalculator cps)
|
||||
{
|
||||
PlexOfCps sedPlex = new PlexOfCps(tableStream, offset, size, SED_SIZE);
|
||||
_text = tpt;
|
||||
this.tpt = tpt;
|
||||
this._text = tpt.getTextPieces();
|
||||
|
||||
int length = sedPlex.length();
|
||||
|
||||
|
@ -54,11 +58,16 @@ public class SectionTable
|
|||
SectionDescriptor sed = new SectionDescriptor(node.getBytes(), 0);
|
||||
|
||||
int fileOffset = sed.getFc();
|
||||
int startAt = CPtoFC(node.getStart());
|
||||
int endAt = CPtoFC(node.getEnd());
|
||||
|
||||
boolean isUnicodeAtStart = tpt.isUnicodeAtByteOffset( startAt );
|
||||
// System.err.println(startAt + " -> " + endAt + " = " + isUnicodeAtStart);
|
||||
|
||||
// check for the optimization
|
||||
if (fileOffset == 0xffffffff)
|
||||
{
|
||||
_sections.add(new SEPX(sed, CPtoFC(node.getStart()), CPtoFC(node.getEnd()), new byte[0]));
|
||||
_sections.add(new SEPX(sed, startAt, endAt, new byte[0], isUnicodeAtStart));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -67,9 +76,34 @@ public class SectionTable
|
|||
byte[] buf = new byte[sepxSize];
|
||||
fileOffset += LittleEndian.SHORT_SIZE;
|
||||
System.arraycopy(documentStream, fileOffset, buf, 0, buf.length);
|
||||
_sections.add(new SEPX(sed, CPtoFC(node.getStart()), CPtoFC(node.getEnd()), buf));
|
||||
_sections.add(new SEPX(sed, startAt, endAt, buf, isUnicodeAtStart));
|
||||
}
|
||||
}
|
||||
|
||||
// Some files seem to lie about their unicode status, which
|
||||
// is very very pesky. Try to work around these, but this
|
||||
// is getting on for black magic...
|
||||
int mainEndsAt = cps.getMainDocumentEnd();
|
||||
boolean matchAt = false;
|
||||
boolean matchHalf = false;
|
||||
for(int i=0; i<_sections.size(); i++) {
|
||||
SEPX s = (SEPX)_sections.get(i);
|
||||
if(s.getEnd() == mainEndsAt) {
|
||||
matchAt = true;
|
||||
} else if(s.getEndBytes() == mainEndsAt || s.getEndBytes() == mainEndsAt-1) {
|
||||
matchHalf = true;
|
||||
}
|
||||
}
|
||||
if(! matchAt && matchHalf) {
|
||||
System.err.println("Your document seemed to be mostly unicode, but the section definition was in bytes! Trying anyway, but things may well go wrong!");
|
||||
for(int i=0; i<_sections.size(); i++) {
|
||||
SEPX s = (SEPX)_sections.get(i);
|
||||
GenericPropertyNode node = sedPlex.getProperty(i);
|
||||
|
||||
s.setStart( CPtoFC(node.getStart()) );
|
||||
s.setEnd( CPtoFC(node.getEnd()) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void adjustForInsert(int listIndex, int length)
|
||||
|
@ -171,7 +205,7 @@ public class SectionTable
|
|||
|
||||
// Line using Ryan's FCtoCP() conversion method -
|
||||
// unable to observe any effect on our testcases when using this code - piers
|
||||
GenericPropertyNode property = new GenericPropertyNode(FCtoCP(sepx.getStart()), FCtoCP(sepx.getEnd()), sed.toByteArray());
|
||||
GenericPropertyNode property = new GenericPropertyNode(FCtoCP(sepx.getStartBytes()), FCtoCP(sepx.getEndBytes()), sed.toByteArray());
|
||||
|
||||
|
||||
plex.addProperty(property);
|
||||
|
|
|
@ -118,6 +118,9 @@ public class TextPiece extends PropertyNode implements Comparable
|
|||
if(end > buf.length()) {
|
||||
throw new StringIndexOutOfBoundsException("Index " + end + " out of range 0 -> " + buf.length());
|
||||
}
|
||||
if(end < start) {
|
||||
throw new StringIndexOutOfBoundsException("Asked for text from " + start + " to " + end + ", which has an end before the start!");
|
||||
}
|
||||
return buf.substring(start, end);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@ import org.apache.poi.poifs.common.POIFSConstants;
|
|||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -62,8 +65,17 @@ public class TextPieceTable
|
|||
pieces[x] = new PieceDescriptor(node.getBytes(), 0);
|
||||
}
|
||||
|
||||
int firstPieceFilePosition = pieces[0].getFilePosition();
|
||||
_cpMin = firstPieceFilePosition - fcMin;
|
||||
|
||||
// Figure out the cp of the earliest text piece
|
||||
// Note that text pieces don't have to be stored in order!
|
||||
_cpMin = pieces[0].getFilePosition() - fcMin;
|
||||
for (int x = 0; x < pieces.length; x++) {
|
||||
int start = pieces[x].getFilePosition() - fcMin;
|
||||
if(start < _cpMin) {
|
||||
_cpMin = start;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// using the PieceDescriptors, build our list of TextPieces.
|
||||
for (int x = 0; x < pieces.length; x++)
|
||||
|
@ -93,6 +105,15 @@ public class TextPieceTable
|
|||
// And now build the piece
|
||||
_textPieces.add(new TextPiece(nodeStartChars, nodeEndChars, buf, pieces[x], node.getStart()));
|
||||
}
|
||||
|
||||
// In the interest of our sanity, now sort the text pieces
|
||||
// into order, if they're not already
|
||||
TextPiece[] tp = (TextPiece[])
|
||||
_textPieces.toArray(new TextPiece[_textPieces.size()]);
|
||||
Arrays.sort(tp);
|
||||
for(int i=0; i<tp.length; i++) {
|
||||
_textPieces.set(i, tp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public int getCpMin()
|
||||
|
@ -104,6 +125,62 @@ public class TextPieceTable
|
|||
{
|
||||
return _textPieces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the text at the given Character offset
|
||||
* unicode, or plain old ascii?
|
||||
* In a very evil fashion, you have to actually
|
||||
* know this to make sense of character and
|
||||
* paragraph properties :(
|
||||
* @param cp The character offset to check about
|
||||
*/
|
||||
public boolean isUnicodeAtCharOffset(int cp) {
|
||||
boolean lastWas = false;
|
||||
|
||||
Iterator it = _textPieces.iterator();
|
||||
while(it.hasNext()) {
|
||||
TextPiece tp = (TextPiece)it.next();
|
||||
// If the text piece covers the character, all good
|
||||
if(tp.getStart() <= cp && tp.getEnd() >= cp) {
|
||||
return tp.isUnicode();
|
||||
}
|
||||
// Otherwise keep track for the last one
|
||||
lastWas = tp.isUnicode();
|
||||
}
|
||||
|
||||
// If they ask off the end, just go with the last one...
|
||||
return lastWas;
|
||||
}
|
||||
/**
|
||||
* Is the text at the given byte offset
|
||||
* unicode, or plain old ascii?
|
||||
* In a very evil fashion, you have to actually
|
||||
* know this to make sense of character and
|
||||
* paragraph properties :(
|
||||
* @param cp The character offset to check about
|
||||
*/
|
||||
public boolean isUnicodeAtByteOffset(int bytePos) {
|
||||
boolean lastWas = false;
|
||||
int curByte = 0;
|
||||
|
||||
Iterator it = _textPieces.iterator();
|
||||
while(it.hasNext()) {
|
||||
TextPiece tp = (TextPiece)it.next();
|
||||
int nextByte = curByte + tp.bytesLength();
|
||||
|
||||
// If the text piece covers the character, all good
|
||||
if(curByte <= bytePos && nextByte >= bytePos) {
|
||||
return tp.isUnicode();
|
||||
}
|
||||
// Otherwise keep track for the last one
|
||||
lastWas = tp.isUnicode();
|
||||
// Move along
|
||||
curByte = nextByte;
|
||||
}
|
||||
|
||||
// If they ask off the end, just go with the last one...
|
||||
return lastWas;
|
||||
}
|
||||
|
||||
public byte[] writeTo(HWPFOutputStream docStream)
|
||||
throws IOException
|
||||
|
|
|
@ -70,10 +70,10 @@ public abstract class FIBAbstractType
|
|||
private static BitField fFutureSavedUndo = BitFieldFactory.getInstance(0x0008);
|
||||
private static BitField fWord97Saved = BitFieldFactory.getInstance(0x0010);
|
||||
private static BitField fSpare0 = BitFieldFactory.getInstance(0x00FE);
|
||||
protected int field_11_chs;
|
||||
protected int field_12_chsTables;
|
||||
protected int field_13_fcMin;
|
||||
protected int field_14_fcMac;
|
||||
protected int field_11_chs; /** Latest docs say this is Reserved3! */
|
||||
protected int field_12_chsTables; /** Latest docs say this is Reserved4! */
|
||||
protected int field_13_fcMin; /** Latest docs say this is Reserved5! */
|
||||
protected int field_14_fcMac; /** Latest docs say this is Reserved6! */
|
||||
|
||||
|
||||
public FIBAbstractType()
|
||||
|
|
|
@ -155,6 +155,8 @@ public class Range
|
|||
_characters = _doc.getCharacterTable().getTextRuns();
|
||||
_text = _doc.getTextTable().getTextPieces();
|
||||
_parent = new WeakReference(null);
|
||||
|
||||
sanityCheckStartEnd();
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,6 +177,8 @@ public class Range
|
|||
_characters = parent._characters;
|
||||
_text = parent._text;
|
||||
_parent = new WeakReference(parent);
|
||||
|
||||
sanityCheckStartEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,6 +230,22 @@ public class Range
|
|||
_textRangeFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
sanityCheckStartEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the start and end were were given
|
||||
* are actually valid, to avoid issues later on
|
||||
* if they're not
|
||||
*/
|
||||
private void sanityCheckStartEnd() {
|
||||
if(_start < 0) {
|
||||
throw new IllegalArgumentException("Range start must not be negative. Given " + _start);
|
||||
}
|
||||
if(_end < _start) {
|
||||
throw new IllegalArgumentException("The end (" + _end + ") must not be before the start ("+_start+")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -537,13 +557,17 @@ public class Range
|
|||
for (int x = _parStart; x < numParagraphs; x++)
|
||||
{
|
||||
PAPX papx = (PAPX)_paragraphs.get(x);
|
||||
//System.err.println("Paragraph " + x + " was " + papx.getStart() + " -> " + papx.getEnd());
|
||||
papx.adjustForDelete(_start, _end - _start);
|
||||
//System.err.println("Paragraph " + x + " is now " + papx.getStart() + " -> " + papx.getEnd());
|
||||
}
|
||||
|
||||
for (int x = _sectionStart; x < numSections; x++)
|
||||
{
|
||||
SEPX sepx = (SEPX)_sections.get(x);
|
||||
//System.err.println("Section " + x + " was " + sepx.getStart() + " -> " + sepx.getEnd());
|
||||
sepx.adjustForDelete(_start, _end - _start);
|
||||
//System.err.println("Section " + x + " is now " + sepx.getStart() + " -> " + sepx.getEnd());
|
||||
}
|
||||
|
||||
for (int x = _textStart; x < numTextPieces; x++)
|
||||
|
@ -650,14 +674,6 @@ public class Range
|
|||
absPlaceHolderIndex,
|
||||
(absPlaceHolderIndex + pPlaceHolder.length()), getDocument()
|
||||
);
|
||||
if (subRange.usesUnicode()) {
|
||||
absPlaceHolderIndex = getStartOffset() + (pOffset * 2);
|
||||
subRange = new Range(
|
||||
absPlaceHolderIndex,
|
||||
(absPlaceHolderIndex + (pPlaceHolder.length() * 2)),
|
||||
getDocument()
|
||||
);
|
||||
}
|
||||
|
||||
// this Range isn't a proper parent of the subRange() so we'll have to keep
|
||||
// track of an updated endOffset on our own
|
||||
|
@ -674,12 +690,6 @@ public class Range
|
|||
(absPlaceHolderIndex + pPlaceHolder.length() + pValue.length()),
|
||||
getDocument()
|
||||
);
|
||||
if (subRange.usesUnicode())
|
||||
subRange = new Range(
|
||||
(absPlaceHolderIndex + (pValue.length() * 2)),
|
||||
(absPlaceHolderIndex + (pPlaceHolder.length() * 2) +
|
||||
(pValue.length() * 2)), getDocument()
|
||||
);
|
||||
|
||||
// deletes are automagically propagated
|
||||
subRange.delete();
|
||||
|
@ -820,6 +830,10 @@ public class Range
|
|||
{
|
||||
throw new ArrayIndexOutOfBoundsException("The table's bounds fall outside of this Range");
|
||||
}
|
||||
if (tableEnd < 0)
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("The table's end is negative, which isn't allowed!");
|
||||
}
|
||||
return new Table(r._parStart, tableEnd, r._doc.getRange(), paragraph.getTableLevel());
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ public class TestCHPBinTable
|
|||
{
|
||||
private CHPBinTable _cHPBinTable = null;
|
||||
private HWPFDocFixture _hWPFDocFixture;
|
||||
|
||||
private TextPieceTable fakeTPT = new TextPieceTable();
|
||||
|
||||
public TestCHPBinTable(String name)
|
||||
{
|
||||
|
@ -46,7 +48,7 @@ public class TestCHPBinTable
|
|||
byte[] tableStream = _hWPFDocFixture._tableStream;
|
||||
int fcMin = fib.getFcMin();
|
||||
|
||||
_cHPBinTable = new CHPBinTable(mainStream, tableStream, fib.getFcPlcfbteChpx(), fib.getLcbPlcfbteChpx(), fcMin);
|
||||
_cHPBinTable = new CHPBinTable(mainStream, tableStream, fib.getFcPlcfbteChpx(), fib.getLcbPlcfbteChpx(), fcMin, fakeTPT);
|
||||
|
||||
HWPFFileSystem fileSys = new HWPFFileSystem();
|
||||
|
||||
|
@ -57,7 +59,7 @@ public class TestCHPBinTable
|
|||
byte[] newTableStream = tableOut.toByteArray();
|
||||
byte[] newMainStream = mainOut.toByteArray();
|
||||
|
||||
CHPBinTable newBinTable = new CHPBinTable(newMainStream, newTableStream, 0, newTableStream.length, 0);
|
||||
CHPBinTable newBinTable = new CHPBinTable(newMainStream, newTableStream, 0, newTableStream.length, 0, fakeTPT);
|
||||
|
||||
ArrayList oldTextRuns = _cHPBinTable._textRuns;
|
||||
ArrayList newTextRuns = newBinTable._textRuns;
|
||||
|
|
|
@ -32,6 +32,8 @@ public class TestPAPBinTable
|
|||
private PAPBinTable _pAPBinTable = null;
|
||||
private HWPFDocFixture _hWPFDocFixture;
|
||||
|
||||
private TextPieceTable fakeTPT = new TextPieceTable();
|
||||
|
||||
public TestPAPBinTable(String name)
|
||||
{
|
||||
super(name);
|
||||
|
@ -45,7 +47,7 @@ public class TestPAPBinTable
|
|||
byte[] tableStream = _hWPFDocFixture._tableStream;
|
||||
int fcMin = fib.getFcMin();
|
||||
|
||||
_pAPBinTable = new PAPBinTable(mainStream, tableStream, null, fib.getFcPlcfbtePapx(), fib.getLcbPlcfbtePapx(), fcMin);
|
||||
_pAPBinTable = new PAPBinTable(mainStream, tableStream, null, fib.getFcPlcfbtePapx(), fib.getLcbPlcfbtePapx(), fcMin, fakeTPT);
|
||||
|
||||
HWPFFileSystem fileSys = new HWPFFileSystem();
|
||||
|
||||
|
@ -56,7 +58,7 @@ public class TestPAPBinTable
|
|||
byte[] newTableStream = tableOut.toByteArray();
|
||||
byte[] newMainStream = mainOut.toByteArray();
|
||||
|
||||
PAPBinTable newBinTable = new PAPBinTable(newMainStream, newTableStream, null,0, newTableStream.length, 0);
|
||||
PAPBinTable newBinTable = new PAPBinTable(newMainStream, newTableStream, null,0, newTableStream.length, 0, fakeTPT);
|
||||
|
||||
ArrayList oldTextRuns = _pAPBinTable.getParagraphs();
|
||||
ArrayList newTextRuns = newBinTable.getParagraphs();
|
||||
|
|
|
@ -45,13 +45,15 @@ public class TestSectionTable
|
|||
byte[] tableStream = _hWPFDocFixture._tableStream;
|
||||
int fcMin = fib.getFcMin();
|
||||
|
||||
CPSplitCalculator cps = new CPSplitCalculator(fib);
|
||||
|
||||
ComplexFileTable cft = new ComplexFileTable(mainStream, tableStream, fib.getFcClx(), fcMin);
|
||||
TextPieceTable tpt = cft.getTextPieceTable();
|
||||
|
||||
SectionTable sectionTable = new SectionTable(mainStream, tableStream,
|
||||
fib.getFcPlcfsed(),
|
||||
fib.getLcbPlcfsed(),
|
||||
fcMin, tpt.getTextPieces());
|
||||
fcMin, tpt, cps);
|
||||
HWPFFileSystem fileSys = new HWPFFileSystem();
|
||||
|
||||
sectionTable.writeTo(fileSys, 0);
|
||||
|
@ -61,7 +63,9 @@ public class TestSectionTable
|
|||
byte[] newTableStream = tableOut.toByteArray();
|
||||
byte[] newMainStream = mainOut.toByteArray();
|
||||
|
||||
SectionTable newSectionTable = new SectionTable(newMainStream, newTableStream, 0, newTableStream.length, 0, tpt.getTextPieces());
|
||||
SectionTable newSectionTable = new SectionTable(
|
||||
newMainStream, newTableStream, 0,
|
||||
newTableStream.length, 0, tpt, cps);
|
||||
|
||||
ArrayList oldSections = sectionTable.getSections();
|
||||
ArrayList newSections = newSectionTable.getSections();
|
||||
|
|
|
@ -81,9 +81,16 @@ public class TestProblems extends TestCase {
|
|||
HWPFDocument doc = new HWPFDocument(new FileInputStream(
|
||||
new File(dirname, "Bug44292.doc")));
|
||||
Range r = doc.getRange();
|
||||
assertEquals(6, r.numParagraphs());
|
||||
assertEquals(0, r.getStartOffset());
|
||||
assertEquals(87, r.getEndOffset());
|
||||
|
||||
//get the table
|
||||
// Paragraph with table
|
||||
Paragraph p = r.getParagraph(0);
|
||||
assertEquals(0, p.getStartOffset());
|
||||
assertEquals(20, p.getEndOffset());
|
||||
|
||||
// Get the table
|
||||
Table t = r.getTable(p);
|
||||
|
||||
//get the only row
|
||||
|
|
|
@ -18,27 +18,28 @@
|
|||
|
||||
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;
|
||||
|
||||
import org.apache.poi.hwpf.HWPFDocument;
|
||||
import org.apache.poi.hwpf.model.PAPX;
|
||||
|
||||
/**
|
||||
* Test to see if Range.delete() works even if the Range contains a
|
||||
* CharacterRun that uses Unicode characters.
|
||||
*
|
||||
* TODO - re-enable me when unicode paragraph stuff is fixed!
|
||||
*/
|
||||
public abstract class TestRangeDelete extends TestCase {
|
||||
public class TestRangeDelete extends TestCase {
|
||||
|
||||
// u201c and u201d are "smart-quotes"
|
||||
private String introText =
|
||||
"Introduction\r";
|
||||
private String fillerText =
|
||||
"${delete} This is an MS-Word 97 formatted document created using NeoOffice v. 2.2.4 Patch 0 (OpenOffice.org v. 2.2.1).\r";
|
||||
private String originalText =
|
||||
"It is used to confirm that text delete 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} ${delete} and all the POI contributors for their assistance in this matter.\r";
|
||||
private String lastText =
|
||||
"Thank you, ${organization} ${delete}!\r";
|
||||
private String searchText = "${delete}";
|
||||
private String expectedText1 = " This is an MS-Word 97 formatted document created using NeoOffice v. 2.2.4 Patch 0 (OpenOffice.org v. 2.2.1).\r";
|
||||
private String expectedText2 =
|
||||
|
@ -68,32 +69,63 @@ public abstract class TestRangeDelete extends TestCase {
|
|||
public void testDocStructure() throws Exception {
|
||||
|
||||
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
|
||||
Range range;
|
||||
Section section;
|
||||
Paragraph para;
|
||||
PAPX paraDef;
|
||||
|
||||
Range range = daDoc.getOverallRange();
|
||||
|
||||
// First, check overall
|
||||
range = daDoc.getOverallRange();
|
||||
assertEquals(1, range.numSections());
|
||||
Section section = range.getSection(0);
|
||||
|
||||
assertEquals(5, section.numParagraphs());
|
||||
Paragraph para = section.getParagraph(2);
|
||||
|
||||
assertEquals(5, para.numCharacterRuns());
|
||||
|
||||
assertEquals(originalText, para.text());
|
||||
assertEquals(5, range.numParagraphs());
|
||||
|
||||
|
||||
// Now check on just the main text
|
||||
// Now, onto just the doc bit
|
||||
range = daDoc.getRange();
|
||||
|
||||
|
||||
assertEquals(1, range.numSections());
|
||||
assertEquals(1, daDoc.getSectionTable().getSections().size());
|
||||
section = range.getSection(0);
|
||||
|
||||
|
||||
assertEquals(5, section.numParagraphs());
|
||||
para = section.getParagraph(2);
|
||||
|
||||
|
||||
para = section.getParagraph(0);
|
||||
assertEquals(1, para.numCharacterRuns());
|
||||
assertEquals(introText, para.text());
|
||||
|
||||
para = section.getParagraph(1);
|
||||
assertEquals(5, para.numCharacterRuns());
|
||||
assertEquals(fillerText, para.text());
|
||||
|
||||
|
||||
paraDef = (PAPX)daDoc.getParagraphTable().getParagraphs().get(2);
|
||||
assertEquals(132, paraDef.getStart());
|
||||
assertEquals(400, paraDef.getEnd());
|
||||
|
||||
para = section.getParagraph(2);
|
||||
assertEquals(5, para.numCharacterRuns());
|
||||
|
||||
assertEquals(originalText, para.text());
|
||||
|
||||
|
||||
paraDef = (PAPX)daDoc.getParagraphTable().getParagraphs().get(3);
|
||||
assertEquals(400, paraDef.getStart());
|
||||
assertEquals(438, paraDef.getEnd());
|
||||
|
||||
para = section.getParagraph(3);
|
||||
assertEquals(1, para.numCharacterRuns());
|
||||
assertEquals(lastText, para.text());
|
||||
|
||||
|
||||
// Check things match on text length
|
||||
assertEquals(439, range.text().length());
|
||||
assertEquals(439, section.text().length());
|
||||
assertEquals(439,
|
||||
section.getParagraph(0).text().length() +
|
||||
section.getParagraph(1).text().length() +
|
||||
section.getParagraph(2).text().length() +
|
||||
section.getParagraph(3).text().length() +
|
||||
section.getParagraph(4).text().length()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,12 +150,7 @@ public abstract class TestRangeDelete extends TestCase {
|
|||
assertEquals(192, offset);
|
||||
|
||||
int absOffset = para.getStartOffset() + offset;
|
||||
if (para.usesUnicode())
|
||||
absOffset = para.getStartOffset() + (offset * 2);
|
||||
|
||||
Range subRange = new Range(absOffset, (absOffset + searchText.length()), para.getDocument());
|
||||
if (subRange.usesUnicode())
|
||||
subRange = new Range(absOffset, (absOffset + (searchText.length() * 2)), para.getDocument());
|
||||
|
||||
assertEquals(searchText, subRange.text());
|
||||
|
||||
|
@ -167,26 +194,23 @@ public abstract class TestRangeDelete extends TestCase {
|
|||
|
||||
boolean keepLooking = true;
|
||||
while (keepLooking) {
|
||||
|
||||
// Reload the range every time
|
||||
range = daDoc.getRange();
|
||||
int offset = range.text().indexOf(searchText);
|
||||
if (offset >= 0) {
|
||||
|
||||
int absOffset = range.getStartOffset() + offset;
|
||||
if (range.usesUnicode())
|
||||
absOffset = range.getStartOffset() + (offset * 2);
|
||||
|
||||
Range subRange = new Range(
|
||||
absOffset, (absOffset + searchText.length()), range.getDocument());
|
||||
if (subRange.usesUnicode())
|
||||
subRange = new Range(
|
||||
absOffset, (absOffset + (searchText.length() * 2)), range.getDocument());
|
||||
|
||||
assertEquals(searchText, subRange.text());
|
||||
|
||||
subRange.delete();
|
||||
|
||||
} else
|
||||
} else {
|
||||
keepLooking = false;
|
||||
}
|
||||
}
|
||||
|
||||
// we need to let the model re-calculate the Range before we use it
|
||||
|
@ -197,6 +221,10 @@ public abstract class TestRangeDelete extends TestCase {
|
|||
|
||||
assertEquals(5, section.numParagraphs());
|
||||
|
||||
para = section.getParagraph(0);
|
||||
text = para.text();
|
||||
assertEquals(introText, text);
|
||||
|
||||
para = section.getParagraph(1);
|
||||
text = para.text();
|
||||
assertEquals(expectedText1, text);
|
||||
|
|
|
@ -18,29 +18,25 @@
|
|||
|
||||
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;
|
||||
|
||||
import org.apache.poi.hwpf.HWPFDocument;
|
||||
|
||||
/**
|
||||
* Test to see if Range.insertBefore() works even if the Range contains a
|
||||
* CharacterRun that uses Unicode characters.
|
||||
*
|
||||
* TODO - re-enable me when unicode paragraph stuff is fixed!
|
||||
*/
|
||||
public abstract class TestRangeInsertion extends TestCase {
|
||||
public class TestRangeInsertion extends TestCase {
|
||||
|
||||
// u201c and u201d are "smart-quotes"
|
||||
private String originalText =
|
||||
"It is used to confirm that text insertion 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.\r";
|
||||
private String textToInsert = "Look at me! I'm cool! ";
|
||||
private int insertionPoint = 244;
|
||||
private int insertionPoint = 122;
|
||||
|
||||
private String illustrativeDocFile;
|
||||
|
||||
|
@ -73,12 +69,18 @@ public abstract class TestRangeInsertion extends TestCase {
|
|||
|
||||
assertEquals(3, section.numParagraphs());
|
||||
Paragraph para = section.getParagraph(2);
|
||||
assertEquals(originalText, para.text());
|
||||
|
||||
assertEquals(3, para.numCharacterRuns());
|
||||
String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() +
|
||||
para.getCharacterRun(2).text();
|
||||
String text =
|
||||
para.getCharacterRun(0).text() +
|
||||
para.getCharacterRun(1).text() +
|
||||
para.getCharacterRun(2).text()
|
||||
;
|
||||
|
||||
assertEquals(originalText, text);
|
||||
|
||||
assertEquals(insertionPoint, para.getStartOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,10 +111,14 @@ public abstract class TestRangeInsertion extends TestCase {
|
|||
|
||||
assertEquals(3, section.numParagraphs());
|
||||
Paragraph para = section.getParagraph(2);
|
||||
assertEquals((textToInsert + originalText), para.text());
|
||||
|
||||
assertEquals(3, para.numCharacterRuns());
|
||||
String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() +
|
||||
para.getCharacterRun(2).text();
|
||||
String text =
|
||||
para.getCharacterRun(0).text() +
|
||||
para.getCharacterRun(1).text() +
|
||||
para.getCharacterRun(2).text()
|
||||
;
|
||||
|
||||
// System.out.println(text);
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@ package org.apache.poi.hwpf.usermodel;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hwpf.HWPFDocument;
|
||||
import org.apache.poi.hwpf.model.PropertyNode;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
|
@ -30,7 +32,7 @@ import junit.framework.TestCase;
|
|||
*
|
||||
* TODO - re-enable me when unicode paragraph stuff is fixed!
|
||||
*/
|
||||
public abstract class TestRangeProperties extends TestCase {
|
||||
public class TestRangeProperties extends TestCase {
|
||||
private static final char page_break = (char)12;
|
||||
|
||||
private static final String u_page_1 =
|
||||
|
@ -85,6 +87,16 @@ public abstract class TestRangeProperties extends TestCase {
|
|||
r.text()
|
||||
);
|
||||
|
||||
assertEquals(1, r.numSections());
|
||||
assertEquals(1, a.getSectionTable().getSections().size());
|
||||
Section s = r.getSection(0);
|
||||
assertEquals(
|
||||
a_page_1 +
|
||||
page_break + "\r" +
|
||||
a_page_2,
|
||||
s.text()
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
7,
|
||||
r.numParagraphs()
|
||||
|
@ -142,8 +154,102 @@ public abstract class TestRangeProperties extends TestCase {
|
|||
assertEquals(22, c1.getFontSize());
|
||||
assertEquals(32, c7.getFontSize());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests the raw definitions of the paragraphs of
|
||||
* a unicode document
|
||||
*/
|
||||
public void testUnicodeParagraphDefinitions() throws Exception {
|
||||
Range r = u.getRange();
|
||||
String[] p1_parts = u_page_1.split("\r");
|
||||
String[] p2_parts = u_page_2.split("\r");
|
||||
|
||||
assertEquals(
|
||||
u_page_1 + page_break + "\r" + u_page_2,
|
||||
r.text()
|
||||
);
|
||||
assertEquals(
|
||||
408, r.text().length()
|
||||
);
|
||||
|
||||
|
||||
assertEquals(1, r.numSections());
|
||||
assertEquals(1, u.getSectionTable().getSections().size());
|
||||
Section s = r.getSection(0);
|
||||
assertEquals(
|
||||
u_page_1 +
|
||||
page_break + "\r" +
|
||||
u_page_2,
|
||||
s.text()
|
||||
);
|
||||
assertEquals(0, s.getStartOffset());
|
||||
assertEquals(408, s.getEndOffset());
|
||||
|
||||
|
||||
List pDefs = r._paragraphs;
|
||||
assertEquals(35, pDefs.size());
|
||||
|
||||
// Check that the last paragraph ends where it should do
|
||||
assertEquals(531, u.getOverallRange().text().length());
|
||||
assertEquals(530, u.getCPSplitCalculator().getHeaderTextboxEnd());
|
||||
PropertyNode pLast = (PropertyNode)pDefs.get(34);
|
||||
// assertEquals(530, pLast.getEnd());
|
||||
|
||||
// Only care about the first few really though
|
||||
PropertyNode p0 = (PropertyNode)pDefs.get(0);
|
||||
PropertyNode p1 = (PropertyNode)pDefs.get(1);
|
||||
PropertyNode p2 = (PropertyNode)pDefs.get(2);
|
||||
PropertyNode p3 = (PropertyNode)pDefs.get(3);
|
||||
PropertyNode p4 = (PropertyNode)pDefs.get(4);
|
||||
|
||||
// 5 paragraphs should get us to the end of our text
|
||||
assertTrue(p0.getStart() < 408);
|
||||
assertTrue(p0.getEnd() < 408);
|
||||
assertTrue(p1.getStart() < 408);
|
||||
assertTrue(p1.getEnd() < 408);
|
||||
assertTrue(p2.getStart() < 408);
|
||||
assertTrue(p2.getEnd() < 408);
|
||||
assertTrue(p3.getStart() < 408);
|
||||
assertTrue(p3.getEnd() < 408);
|
||||
assertTrue(p4.getStart() < 408);
|
||||
assertTrue(p4.getEnd() < 408);
|
||||
|
||||
// Paragraphs should match with lines
|
||||
assertEquals(
|
||||
0,
|
||||
p0.getStart()
|
||||
);
|
||||
assertEquals(
|
||||
p1_parts[0].length() + 1,
|
||||
p0.getEnd()
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
p1_parts[0].length() + 1,
|
||||
p1.getStart()
|
||||
);
|
||||
assertEquals(
|
||||
p1_parts[0].length() + 1 +
|
||||
p1_parts[1].length() + 1,
|
||||
p1.getEnd()
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
p1_parts[0].length() + 1 +
|
||||
p1_parts[1].length() + 1,
|
||||
p2.getStart()
|
||||
);
|
||||
assertEquals(
|
||||
p1_parts[0].length() + 1 +
|
||||
p1_parts[1].length() + 1 +
|
||||
p1_parts[2].length() + 1,
|
||||
p2.getEnd()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the paragraph text of a unicode document
|
||||
*/
|
||||
public void testUnicodeTextParagraphs() throws Exception {
|
||||
Range r = u.getRange();
|
||||
assertEquals(
|
||||
|
@ -154,16 +260,112 @@ public abstract class TestRangeProperties extends TestCase {
|
|||
);
|
||||
|
||||
assertEquals(
|
||||
5,
|
||||
12,
|
||||
r.numParagraphs()
|
||||
);
|
||||
String[] p1_parts = u_page_1.split("\r");
|
||||
String[] p2_parts = u_page_2.split("\r");
|
||||
|
||||
System.out.println(r.getParagraph(2).text());
|
||||
// TODO
|
||||
// Check text all matches up properly
|
||||
assertEquals(p1_parts[0] + "\r", r.getParagraph(0).text());
|
||||
assertEquals(p1_parts[1] + "\r", r.getParagraph(1).text());
|
||||
assertEquals(p1_parts[2] + "\r", r.getParagraph(2).text());
|
||||
assertEquals(p1_parts[3] + "\r", r.getParagraph(3).text());
|
||||
assertEquals(p1_parts[4] + "\r", r.getParagraph(4).text());
|
||||
assertEquals(p1_parts[5] + "\r", r.getParagraph(5).text());
|
||||
assertEquals(p1_parts[6] + "\r", r.getParagraph(6).text());
|
||||
assertEquals(p1_parts[7] + "\r", r.getParagraph(7).text());
|
||||
assertEquals(p1_parts[8] + "\r", r.getParagraph(8).text());
|
||||
assertEquals(p1_parts[9] + "\r", r.getParagraph(9).text());
|
||||
assertEquals(page_break + "\r", r.getParagraph(10).text());
|
||||
assertEquals(p2_parts[0] + "\r", r.getParagraph(11).text());
|
||||
}
|
||||
public void testUnicodeStyling() throws Exception {
|
||||
// TODO
|
||||
Range r = u.getRange();
|
||||
String[] p1_parts = u_page_1.split("\r");
|
||||
|
||||
Paragraph p1 = r.getParagraph(0);
|
||||
Paragraph p7 = r.getParagraph(6);
|
||||
|
||||
// Line ending in its own run each time!
|
||||
assertEquals(2, p1.numCharacterRuns());
|
||||
assertEquals(2, p7.numCharacterRuns());
|
||||
|
||||
CharacterRun c1a = p1.getCharacterRun(0);
|
||||
CharacterRun c1b = p1.getCharacterRun(1);
|
||||
CharacterRun c7a = p7.getCharacterRun(0);
|
||||
CharacterRun c7b = p7.getCharacterRun(1);
|
||||
|
||||
assertEquals("Times New Roman", c1a.getFontName()); // No Calibri
|
||||
assertEquals(22, c1a.getFontSize());
|
||||
|
||||
assertEquals("Times New Roman", c1b.getFontName()); // No Calibri
|
||||
assertEquals(22, c1b.getFontSize());
|
||||
|
||||
assertEquals("Times New Roman", c7a.getFontName());
|
||||
assertEquals(48, c7a.getFontSize());
|
||||
|
||||
assertEquals("Times New Roman", c7b.getFontName());
|
||||
assertEquals(48, c7b.getFontSize());
|
||||
|
||||
// Now check where they crop up
|
||||
assertEquals(
|
||||
0,
|
||||
c1a.getStartOffset()
|
||||
);
|
||||
assertEquals(
|
||||
p1_parts[0].length(),
|
||||
c1a.getEndOffset()
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
p1_parts[0].length(),
|
||||
c1b.getStartOffset()
|
||||
);
|
||||
assertEquals(
|
||||
p1_parts[0].length()+1,
|
||||
c1b.getEndOffset()
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
p1_parts[0].length() + 1 +
|
||||
p1_parts[1].length() + 1 +
|
||||
p1_parts[2].length() + 1 +
|
||||
p1_parts[3].length() + 1 +
|
||||
p1_parts[4].length() + 1 +
|
||||
p1_parts[5].length() + 1,
|
||||
c7a.getStartOffset()
|
||||
);
|
||||
assertEquals(
|
||||
p1_parts[0].length() + 1 +
|
||||
p1_parts[1].length() + 1 +
|
||||
p1_parts[2].length() + 1 +
|
||||
p1_parts[3].length() + 1 +
|
||||
p1_parts[4].length() + 1 +
|
||||
p1_parts[5].length() + 1 +
|
||||
1,
|
||||
c7a.getEndOffset()
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
p1_parts[0].length() + 1 +
|
||||
p1_parts[1].length() + 1 +
|
||||
p1_parts[2].length() + 1 +
|
||||
p1_parts[3].length() + 1 +
|
||||
p1_parts[4].length() + 1 +
|
||||
p1_parts[5].length() + 1 +
|
||||
1,
|
||||
c7b.getStartOffset()
|
||||
);
|
||||
assertEquals(
|
||||
p1_parts[0].length() + 1 +
|
||||
p1_parts[1].length() + 1 +
|
||||
p1_parts[2].length() + 1 +
|
||||
p1_parts[3].length() + 1 +
|
||||
p1_parts[4].length() + 1 +
|
||||
p1_parts[5].length() + 1 +
|
||||
p1_parts[6].length() + 1,
|
||||
c7b.getEndOffset()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,23 +18,19 @@
|
|||
|
||||
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;
|
||||
|
||||
import org.apache.poi.hwpf.HWPFDocument;
|
||||
|
||||
/**
|
||||
* Test to see if Range.replaceText() works even if the Range contains a
|
||||
* CharacterRun that uses Unicode characters.
|
||||
*
|
||||
* TODO - re-enable me when unicode paragraph stuff is fixed!
|
||||
*/
|
||||
public abstract class TestRangeReplacement extends TestCase {
|
||||
public class TestRangeReplacement extends TestCase {
|
||||
|
||||
// u201c and u201d are "smart-quotes"
|
||||
private String originalText =
|
||||
|
@ -70,16 +66,23 @@ public abstract class TestRangeReplacement extends TestCase {
|
|||
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
|
||||
|
||||
Range range = daDoc.getRange();
|
||||
assertEquals(414, range.text().length());
|
||||
|
||||
assertEquals(1, range.numSections());
|
||||
Section section = range.getSection(0);
|
||||
assertEquals(414, section.text().length());
|
||||
|
||||
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();
|
||||
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);
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -20,6 +20,7 @@ package org.apache.poi.hssf.model;
|
|||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.model.FormulaParser.FormulaParseException;
|
||||
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
|
||||
import org.apache.poi.hssf.record.formula.AddPtg;
|
||||
|
@ -123,12 +124,15 @@ public final class TestFormulaParser extends TestCase {
|
|||
}
|
||||
|
||||
public void testMacroFunction() {
|
||||
HSSFWorkbook w = new HSSFWorkbook();
|
||||
Ptg[] ptg = FormulaParser.parse("FOO()", w);
|
||||
// testNames.xls contains a VB function called 'myFunc'
|
||||
HSSFWorkbook w = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
|
||||
|
||||
Ptg[] ptg = FormulaParser.parse("myFunc()", w);
|
||||
// myFunc() actually takes 1 parameter. Don't know if POI will ever be able to detect this problem
|
||||
|
||||
// the name gets encoded as the first arg
|
||||
NamePtg tname = (NamePtg) ptg[0];
|
||||
assertEquals("FOO", tname.toFormulaString(w));
|
||||
assertEquals("myFunc", tname.toFormulaString(w));
|
||||
|
||||
AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[1];
|
||||
assertTrue(tfunc.isExternalFunction());
|
||||
|
|
|
@ -17,11 +17,19 @@
|
|||
|
||||
package org.apache.poi.hssf.record.formula;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.model.FormulaParser;
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue;
|
||||
/**
|
||||
* Tests for functions from external workbooks (e.g. YEARFRAC).
|
||||
*
|
||||
|
@ -30,17 +38,45 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|||
*/
|
||||
public final class TestExternalFunctionFormulas extends TestCase {
|
||||
|
||||
|
||||
/**
|
||||
* tests <tt>NameXPtg.toFormulaString(Workbook)</tt> and logic in Workbook below that
|
||||
*/
|
||||
public void testReadFormulaContainingExternalFunction() {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
|
||||
|
||||
String expectedFormula = "YEARFRAC(B1,C1)";
|
||||
HSSFSheet sht = wb.getSheetAt(0);
|
||||
String cellFormula = sht.getRow(0).getCell((short)0).getCellFormula();
|
||||
assertEquals(expectedFormula, cellFormula);
|
||||
}
|
||||
|
||||
/**
|
||||
* tests <tt>NameXPtg.toFormulaString(Workbook)</tt> and logic in Workbook below that
|
||||
*/
|
||||
public void testReadFormulaContainingExternalFunction() {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
|
||||
|
||||
String expectedFormula = "YEARFRAC(B1,C1)";
|
||||
HSSFSheet sht = wb.getSheetAt(0);
|
||||
String cellFormula = sht.getRow(0).getCell(0).getCellFormula();
|
||||
assertEquals(expectedFormula, cellFormula);
|
||||
}
|
||||
|
||||
public void testParse() {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
|
||||
Ptg[] ptgs = FormulaParser.parse("YEARFRAC(B1,C1)", wb);
|
||||
assertEquals(4, ptgs.length);
|
||||
assertEquals(NameXPtg.class, ptgs[0].getClass());
|
||||
|
||||
wb.getSheetAt(0).getRow(0).createCell(6).setCellFormula("YEARFRAC(C1,B1)");
|
||||
if (false) {
|
||||
// In case you fancy checking in excel
|
||||
try {
|
||||
File tempFile = File.createTempFile("testExtFunc", ".xls");
|
||||
FileOutputStream fout = new FileOutputStream(tempFile);
|
||||
wb.write(fout);
|
||||
fout.close();
|
||||
System.out.println("check out " + tempFile.getAbsolutePath());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DISABLEDtestEvaluate() {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
|
||||
HSSFSheet sheet = wb.getSheetAt(0);
|
||||
HSSFCell cell = sheet.getRow(0).getCell(0);
|
||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
|
||||
CellValue evalResult = fe.evaluate(cell);
|
||||
evalResult.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,11 @@
|
|||
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||
import org.apache.poi.hssf.usermodel.HSSFName;
|
||||
|
@ -34,20 +37,33 @@ public final class TestExternalFunction extends TestCase {
|
|||
|
||||
/**
|
||||
* Checks that an external function can get invoked from the formula evaluator.
|
||||
* @throws IOException
|
||||
|
||||
*/
|
||||
public void testInvoke() {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet sheet = wb.createSheet();
|
||||
wb.setSheetName(0, "Sheet1");
|
||||
HSSFRow row = sheet.createRow(0);
|
||||
HSSFCell cell = row.createCell(0);
|
||||
|
||||
HSSFName hssfName = wb.createName();
|
||||
hssfName.setNameName("myFunc");
|
||||
|
||||
cell.setCellFormula("myFunc()");
|
||||
String actualFormula=cell.getCellFormula();
|
||||
assertEquals("myFunc()", actualFormula);
|
||||
|
||||
HSSFWorkbook wb;
|
||||
HSSFSheet sheet;
|
||||
HSSFCell cell;
|
||||
if (false) {
|
||||
// TODO - this code won't work until we can create user-defined functions directly with POI
|
||||
wb = new HSSFWorkbook();
|
||||
sheet = wb.createSheet();
|
||||
wb.setSheetName(0, "Sheet1");
|
||||
HSSFName hssfName = wb.createName();
|
||||
hssfName.setNameName("myFunc");
|
||||
|
||||
} else {
|
||||
// This sample spreadsheet already has a VB function called 'myFunc'
|
||||
wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
|
||||
sheet = wb.getSheetAt(0);
|
||||
HSSFRow row = sheet.createRow(0);
|
||||
cell = row.createCell(1);
|
||||
}
|
||||
|
||||
cell.setCellFormula("myFunc()");
|
||||
String actualFormula=cell.getCellFormula();
|
||||
assertEquals("myFunc()", actualFormula);
|
||||
|
||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
|
||||
CellValue evalResult = fe.evaluate(cell);
|
||||
|
|
|
@ -417,6 +417,9 @@ public final class TestBugs extends TestCase {
|
|||
for(int i = 0 ; i < wb.getNumberOfNames(); i++){
|
||||
HSSFName name = wb.getNameAt(i);
|
||||
name.getNameName();
|
||||
if (name.isFunctionName()) {
|
||||
continue;
|
||||
}
|
||||
name.getReference();
|
||||
}
|
||||
}
|
||||
|
@ -1004,7 +1007,6 @@ public final class TestBugs extends TestCase {
|
|||
* 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() {
|
||||
HSSFWorkbook wb = openSample("30978-alt.xls");
|
||||
|
@ -1016,7 +1018,7 @@ public final class TestBugs extends TestCase {
|
|||
Workbook w = wb.getWorkbook();
|
||||
for(int i=0; i<w.getNumNames(); i++) {
|
||||
NameRecord r = w.getNameRecord(i);
|
||||
assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
|
||||
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
||||
|
||||
List nd = r.getNameDefinition();
|
||||
assertEquals(1, nd.size());
|
||||
|
@ -1034,7 +1036,7 @@ public final class TestBugs extends TestCase {
|
|||
|
||||
for(int i=0; i<w.getNumNames(); i++) {
|
||||
NameRecord r = w.getNameRecord(i);
|
||||
assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
|
||||
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
||||
|
||||
List nd = r.getNameDefinition();
|
||||
assertEquals(1, nd.size());
|
||||
|
@ -1051,7 +1053,7 @@ public final class TestBugs extends TestCase {
|
|||
|
||||
for(int i=0; i<w.getNumNames(); i++) {
|
||||
NameRecord r = w.getNameRecord(i);
|
||||
assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
|
||||
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
|
||||
|
||||
List nd = r.getNameDefinition();
|
||||
assertEquals(1, nd.size());
|
||||
|
|
|
@ -50,7 +50,7 @@ public final class TestHSSFWorkbook extends TestCase {
|
|||
b.createSheet();
|
||||
b.setRepeatingRowsAndColumns( 2, 0,1,-1,-1 );
|
||||
NameRecord nameRecord = b.getWorkbook().getNameRecord( 0 );
|
||||
assertEquals( 3, nameRecord.getIndexToSheet() );
|
||||
assertEquals(3, nameRecord.getSheetNumber());
|
||||
}
|
||||
|
||||
public void testCaseInsensitiveNames() {
|
||||
|
@ -411,84 +411,84 @@ public final class TestHSSFWorkbook extends TestCase {
|
|||
* that point to deleted sheets
|
||||
*/
|
||||
public void testNamesToDeleteSheets() throws Exception {
|
||||
HSSFWorkbook b = openSample("30978-deleted.xls");
|
||||
assertEquals(3, b.getNumberOfNames());
|
||||
|
||||
// Sheet 2 is deleted
|
||||
assertEquals("Sheet1", b.getSheetName(0));
|
||||
assertEquals("Sheet3", b.getSheetName(1));
|
||||
|
||||
Area3DPtg ptg;
|
||||
NameRecord nr;
|
||||
HSSFName n;
|
||||
|
||||
/* ======= Name pointing to deleted sheet ====== */
|
||||
|
||||
// First at low level
|
||||
nr = b.getWorkbook().getNameRecord(0);
|
||||
assertEquals("On2", nr.getNameText());
|
||||
assertEquals(0, nr.getIndexToSheet());
|
||||
assertEquals(1, nr.getExternSheetNumber());
|
||||
assertEquals(1, nr.getNameDefinition().size());
|
||||
|
||||
ptg = (Area3DPtg)nr.getNameDefinition().get(0);
|
||||
assertEquals(1, ptg.getExternSheetIndex());
|
||||
assertEquals(0, ptg.getFirstColumn());
|
||||
assertEquals(0, ptg.getFirstRow());
|
||||
assertEquals(0, ptg.getLastColumn());
|
||||
assertEquals(2, ptg.getLastRow());
|
||||
|
||||
// Now at high level
|
||||
n = b.getNameAt(0);
|
||||
assertEquals("On2", n.getNameName());
|
||||
assertEquals("", n.getSheetName());
|
||||
assertEquals("#REF!$A$1:$A$3", n.getReference());
|
||||
|
||||
|
||||
/* ======= Name pointing to 1st sheet ====== */
|
||||
|
||||
// First at low level
|
||||
nr = b.getWorkbook().getNameRecord(1);
|
||||
assertEquals("OnOne", nr.getNameText());
|
||||
assertEquals(0, nr.getIndexToSheet());
|
||||
assertEquals(0, nr.getExternSheetNumber());
|
||||
assertEquals(1, nr.getNameDefinition().size());
|
||||
|
||||
ptg = (Area3DPtg)nr.getNameDefinition().get(0);
|
||||
assertEquals(0, ptg.getExternSheetIndex());
|
||||
assertEquals(0, ptg.getFirstColumn());
|
||||
assertEquals(2, ptg.getFirstRow());
|
||||
assertEquals(0, ptg.getLastColumn());
|
||||
assertEquals(3, ptg.getLastRow());
|
||||
|
||||
// Now at high level
|
||||
n = b.getNameAt(1);
|
||||
assertEquals("OnOne", n.getNameName());
|
||||
assertEquals("Sheet1", n.getSheetName());
|
||||
assertEquals("Sheet1!$A$3:$A$4", n.getReference());
|
||||
|
||||
|
||||
/* ======= Name pointing to 3rd sheet ====== */
|
||||
|
||||
// First at low level
|
||||
nr = b.getWorkbook().getNameRecord(2);
|
||||
assertEquals("OnSheet3", nr.getNameText());
|
||||
assertEquals(0, nr.getIndexToSheet());
|
||||
assertEquals(2, nr.getExternSheetNumber());
|
||||
assertEquals(1, nr.getNameDefinition().size());
|
||||
|
||||
ptg = (Area3DPtg)nr.getNameDefinition().get(0);
|
||||
assertEquals(2, ptg.getExternSheetIndex());
|
||||
assertEquals(0, ptg.getFirstColumn());
|
||||
assertEquals(0, ptg.getFirstRow());
|
||||
assertEquals(0, ptg.getLastColumn());
|
||||
assertEquals(1, ptg.getLastRow());
|
||||
|
||||
// Now at high level
|
||||
n = b.getNameAt(2);
|
||||
assertEquals("OnSheet3", n.getNameName());
|
||||
assertEquals("Sheet3", n.getSheetName());
|
||||
assertEquals("Sheet3!$A$1:$A$2", n.getReference());
|
||||
HSSFWorkbook b = openSample("30978-deleted.xls");
|
||||
assertEquals(3, b.getNumberOfNames());
|
||||
|
||||
// Sheet 2 is deleted
|
||||
assertEquals("Sheet1", b.getSheetName(0));
|
||||
assertEquals("Sheet3", b.getSheetName(1));
|
||||
|
||||
Area3DPtg ptg;
|
||||
NameRecord nr;
|
||||
HSSFName n;
|
||||
|
||||
/* ======= Name pointing to deleted sheet ====== */
|
||||
|
||||
// First at low level
|
||||
nr = b.getWorkbook().getNameRecord(0);
|
||||
assertEquals("On2", nr.getNameText());
|
||||
assertEquals(0, nr.getSheetNumber());
|
||||
assertEquals(1, nr.getExternSheetNumber());
|
||||
assertEquals(1, nr.getNameDefinition().size());
|
||||
|
||||
ptg = (Area3DPtg)nr.getNameDefinition().get(0);
|
||||
assertEquals(1, ptg.getExternSheetIndex());
|
||||
assertEquals(0, ptg.getFirstColumn());
|
||||
assertEquals(0, ptg.getFirstRow());
|
||||
assertEquals(0, ptg.getLastColumn());
|
||||
assertEquals(2, ptg.getLastRow());
|
||||
|
||||
// Now at high level
|
||||
n = b.getNameAt(0);
|
||||
assertEquals("On2", n.getNameName());
|
||||
assertEquals("", n.getSheetName());
|
||||
assertEquals("#REF!$A$1:$A$3", n.getReference());
|
||||
|
||||
|
||||
/* ======= Name pointing to 1st sheet ====== */
|
||||
|
||||
// First at low level
|
||||
nr = b.getWorkbook().getNameRecord(1);
|
||||
assertEquals("OnOne", nr.getNameText());
|
||||
assertEquals(0, nr.getSheetNumber());
|
||||
assertEquals(0, nr.getExternSheetNumber());
|
||||
assertEquals(1, nr.getNameDefinition().size());
|
||||
|
||||
ptg = (Area3DPtg)nr.getNameDefinition().get(0);
|
||||
assertEquals(0, ptg.getExternSheetIndex());
|
||||
assertEquals(0, ptg.getFirstColumn());
|
||||
assertEquals(2, ptg.getFirstRow());
|
||||
assertEquals(0, ptg.getLastColumn());
|
||||
assertEquals(3, ptg.getLastRow());
|
||||
|
||||
// Now at high level
|
||||
n = b.getNameAt(1);
|
||||
assertEquals("OnOne", n.getNameName());
|
||||
assertEquals("Sheet1", n.getSheetName());
|
||||
assertEquals("Sheet1!$A$3:$A$4", n.getReference());
|
||||
|
||||
|
||||
/* ======= Name pointing to 3rd sheet ====== */
|
||||
|
||||
// First at low level
|
||||
nr = b.getWorkbook().getNameRecord(2);
|
||||
assertEquals("OnSheet3", nr.getNameText());
|
||||
assertEquals(0, nr.getSheetNumber());
|
||||
assertEquals(2, nr.getExternSheetNumber());
|
||||
assertEquals(1, nr.getNameDefinition().size());
|
||||
|
||||
ptg = (Area3DPtg)nr.getNameDefinition().get(0);
|
||||
assertEquals(2, ptg.getExternSheetIndex());
|
||||
assertEquals(0, ptg.getFirstColumn());
|
||||
assertEquals(0, ptg.getFirstRow());
|
||||
assertEquals(0, ptg.getLastColumn());
|
||||
assertEquals(1, ptg.getLastRow());
|
||||
|
||||
// Now at high level
|
||||
n = b.getNameAt(2);
|
||||
assertEquals("OnSheet3", n.getNameName());
|
||||
assertEquals("Sheet3", n.getSheetName());
|
||||
assertEquals("Sheet3!$A$1:$A$2", n.getReference());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -519,12 +519,12 @@ public final class TestHSSFWorkbook extends TestCase {
|
|||
* The sample file provided with bug 45582 seems to have one extra byte after the EOFRecord
|
||||
*/
|
||||
public void testExtraDataAfterEOFRecord() {
|
||||
try {
|
||||
HSSFTestDataSamples.openSampleWorkbook("ex45582-22397.xls");
|
||||
} catch (RecordFormatException e) {
|
||||
if (e.getCause() instanceof LittleEndian.BufferUnderrunException) {
|
||||
throw new AssertionFailedError("Identified bug 45582");
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
HSSFTestDataSamples.openSampleWorkbook("ex45582-22397.xls");
|
||||
} catch (RecordFormatException e) {
|
||||
if (e.getCause() instanceof LittleEndian.BufferUnderrunException) {
|
||||
throw new AssertionFailedError("Identified bug 45582");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,17 +17,15 @@
|
|||
|
||||
package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.util.AreaReference;
|
||||
import org.apache.poi.hssf.util.CellReference;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -42,10 +40,6 @@ public final class TestNamedRange extends TestCase {
|
|||
return HSSFTestDataSamples.openSampleWorkbook(sampleFileName);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(TestNamedRange.class);
|
||||
}
|
||||
|
||||
/** Test of TestCase method, of class test.RangeTest. */
|
||||
public void testNamedRange() {
|
||||
HSSFWorkbook wb = openSample("Simple.xls");
|
||||
|
@ -411,7 +405,7 @@ public final class TestNamedRange extends TestCase {
|
|||
String cellValue = "TEST Value";
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet sheet = wb.createSheet(sheetName);
|
||||
sheet.createRow(0).createCell((short) 0).setCellValue(cellValue);
|
||||
sheet.createRow(0).createCell(0).setCellValue(new HSSFRichTextString(cellValue));
|
||||
|
||||
// create named range for a single cell using areareference
|
||||
HSSFName namedCell = wb.createName();
|
||||
|
@ -447,7 +441,7 @@ public final class TestNamedRange extends TestCase {
|
|||
String sname = "TestSheet", cname = "TestName", cvalue = "TestVal";
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet sheet = wb.createSheet(sname);
|
||||
sheet.createRow(0).createCell((short) 0).setCellValue(cvalue);
|
||||
sheet.createRow(0).createCell(0).setCellValue(new HSSFRichTextString(cvalue));
|
||||
|
||||
// create named range for a single cell using cellreference
|
||||
HSSFName namedCell = wb.createName();
|
||||
|
@ -492,56 +486,60 @@ public final class TestNamedRange extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public void testRepeatingRowsAndColumsNames() throws Exception {
|
||||
public void testRepeatingRowsAndColumsNames() {
|
||||
// First test that setting RR&C for same sheet more than once only creates a
|
||||
// single Print_Titles built-in record
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet sheet = wb.createSheet();
|
||||
HSSFSheet sheet = wb.createSheet("FirstSheet");
|
||||
|
||||
for (int rowItem = 0; rowItem < 10; rowItem++) {
|
||||
HSSFRow r = sheet.createRow(rowItem);
|
||||
for (int column = 0; column < 2; column++) {
|
||||
HSSFCell cellItem = r.createCell((short) column);
|
||||
cellItem.setCellType(HSSFCell.CELL_TYPE_STRING);
|
||||
cellItem.setCellValue(new HSSFRichTextString("Some value here"));
|
||||
if (rowItem == 2) {
|
||||
wb.setRepeatingRowsAndColumns(0, 0, 0, 0, 3 - 1);
|
||||
sheet.createFreezePane(0, 3);
|
||||
}
|
||||
}
|
||||
// set repeating rows and columns twice for the first sheet
|
||||
for (int i = 0; i < 2; i++) {
|
||||
wb.setRepeatingRowsAndColumns(0, 0, 0, 0, 3-1);
|
||||
sheet.createFreezePane(0, 3);
|
||||
}
|
||||
|
||||
assertEquals(2, wb.getNumberOfNames());
|
||||
assertEquals(1, wb.getNumberOfNames());
|
||||
HSSFName nr1 = wb.getNameAt(0);
|
||||
HSSFName nr2 = wb.getNameAt(1);
|
||||
|
||||
assertEquals("Print_Titles", nr1.getNameName());
|
||||
assertEquals("Sheet0!$A$1:$A$0,Sheet0!$A$1:$IV$3", nr1.getReference());
|
||||
|
||||
assertEquals("Excel_Name_Record_Titles_1_1", nr2.getNameName());
|
||||
assertEquals("Sheet0!$A$1:$A$0,Sheet0!$A$1:$IV$3", nr2.getReference());
|
||||
if (false) {
|
||||
// TODO - full column references not rendering properly, absolute markers not present either
|
||||
assertEquals("FirstSheet!$A:$A,FirstSheet!$1:$3", nr1.getReference());
|
||||
} else {
|
||||
assertEquals("FirstSheet!A:A,FirstSheet!$A$1:$IV$3", nr1.getReference());
|
||||
}
|
||||
|
||||
// Save and re-open
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
wb.write(baos);
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
HSSFWorkbook nwb = new HSSFWorkbook(new POIFSFileSystem(bais));
|
||||
HSSFWorkbook nwb = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||
|
||||
assertEquals(1, nwb.getNumberOfNames());
|
||||
nr1 = nwb.getNameAt(0);
|
||||
|
||||
assertEquals("Print_Titles", nr1.getNameName());
|
||||
assertEquals("FirstSheet!A:A,FirstSheet!$A$1:$IV$3", nr1.getReference());
|
||||
|
||||
// check that setting RR&C on a second sheet causes a new Print_Titles built-in
|
||||
// name to be created
|
||||
sheet = nwb.createSheet("SecondSheet");
|
||||
nwb.setRepeatingRowsAndColumns(1, 1, 2, 0, 0);
|
||||
|
||||
assertEquals(2, nwb.getNumberOfNames());
|
||||
nr1 = nwb.getNameAt(0);
|
||||
nr2 = nwb.getNameAt(1);
|
||||
HSSFName nr2 = nwb.getNameAt(1);
|
||||
|
||||
// TODO -
|
||||
// should these references really have been corrected?
|
||||
// and if so, why not also above?
|
||||
assertEquals("Print_Titles", nr1.getNameName());
|
||||
assertEquals("Sheet0!A:A,Sheet0!$A$1:$IV$3", nr1.getReference());
|
||||
assertEquals("Print_Titles", nr2.getNameName());
|
||||
assertEquals("SecondSheet!B:C,SecondSheet!$A$1:$IV$1", nr2.getReference());
|
||||
|
||||
assertEquals("Excel_Name_Record_Titles_1_1", nr2.getNameName());
|
||||
assertEquals("Sheet0!A:A,Sheet0!$A$1:$IV$3", nr2.getReference());
|
||||
|
||||
// In case you fancy checking in excel, to ensure it
|
||||
// won't complain about the file now
|
||||
FileOutputStream fout = new FileOutputStream(File.createTempFile("POI-45126-", ".xls"));
|
||||
wb.write(fout);
|
||||
fout.close();
|
||||
if (false) {
|
||||
// In case you fancy checking in excel, to ensure it
|
||||
// won't complain about the file now
|
||||
try {
|
||||
File tempFile = File.createTempFile("POI-45126-", ".xls");
|
||||
FileOutputStream fout = new FileOutputStream(tempFile);
|
||||
nwb.write(fout);
|
||||
fout.close();
|
||||
System.out.println("check out " + tempFile.getAbsolutePath());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue