12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393 |
- /* ====================================================================
- 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.model;
-
- import java.security.AccessControlException;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Locale;
- import java.util.Map;
- import java.util.Map.Entry;
-
- import org.apache.poi.ddf.EscherBSERecord;
- import org.apache.poi.ddf.EscherBoolProperty;
- import org.apache.poi.ddf.EscherContainerRecord;
- import org.apache.poi.ddf.EscherDgRecord;
- 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.EscherSpRecord;
- 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.EscherAggregate;
- 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.NameCommentRecord;
- 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.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.common.UnicodeString;
- import org.apache.poi.ss.formula.ptg.NameXPtg;
- import org.apache.poi.ss.formula.FormulaShifter;
- import org.apache.poi.ss.formula.udf.UDFFinder;
- import org.apache.poi.ss.formula.ptg.Ptg;
- import org.apache.poi.hssf.util.HSSFColor;
- import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
- import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
- import org.apache.poi.ss.usermodel.BuiltinFormats;
- import org.apache.poi.util.Internal;
- 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.
- * <P>
- * This file contains the low level binary records starting at the workbook's BOF and
- * ending with the workbook's EOF. Use HSSFWorkbook for a high level representation.
- * <P>
- * The structures of the highlevel API use references to this to perform most of their
- * operations. Its probably unwise to use these low level structures directly unless you
- * really know what you're doing. I recommend you read the Microsoft Excel 97 Developer's
- * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf
- * before even attempting to use this.
- *
- *
- * @author Luc Girardin (luc dot girardin at macrofocus dot com)
- * @author Sergei Kozello (sergeikozello at mail.ru)
- * @author Shawn Laubach (slaubach at apache dot org) (Data Formats)
- * @author Andrew C. Oliver (acoliver at apache dot org)
- * @author Brian Sanders (bsanders at risklabs dot com) - custom palette
- * @author Dan Sherman (dsherman at isisph.com)
- * @author Glen Stampoultzis (glens at apache.org)
- * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
- */
- @Internal
- public final class InternalWorkbook {
- /**
- * Excel silently truncates long sheet names to 31 chars.
- * This constant is used to ensure uniqueness in the first 31 chars
- */
- private static final int MAX_SENSITIVE_SHEET_NAME_LEN = 31;
-
-
- private static final POILogger log = POILogFactory.getLogger(InternalWorkbook.class);
- private static final int DEBUG = POILogger.DEBUG;
-
- /**
- * constant used to set the "codepage" wherever "codepage" is set in records
- * (which is duplicated in more than one record)
- */
- private final static short CODEPAGE = 0x04B0;
-
- /**
- * this contains the Worksheet record objects
- */
- private final WorkbookRecordList records;
-
- /**
- * this contains a reference to the SSTRecord so that new stings can be added
- * to it.
- */
- protected SSTRecord sst;
-
-
- private LinkTable linkTable; // optionally occurs if there are references in the document. (4.10.3)
-
- /**
- * holds the "boundsheet" records (aka bundlesheet) so that they can have their
- * reference to their "BOF" marker
- */
- private final List<BoundSheetRecord> boundsheets;
- private final List<FormatRecord> formats;
- private final List<HyperlinkRecord> hyperlinks;
-
- /** the number of extended format records */
- private int numxfs;
- /** the number of font records */
- private int numfonts;
- /** holds the max format id */
- private int maxformatid;
- /** whether 1904 date windowing is being used */
- private boolean uses1904datewindowing;
- private DrawingManager2 drawingManager;
- private List<EscherBSERecord> escherBSERecords;
- private WindowOneRecord windowOne;
- private FileSharingRecord fileShare;
- private WriteAccessRecord writeAccess;
- private WriteProtectRecord writeProtect;
-
- /**
- * Hold the {@link NameCommentRecord}s indexed by the name of the {@link NameRecord} to which they apply.
- */
- private final Map<String, NameCommentRecord> commentRecords;
-
- private InternalWorkbook() {
- records = new WorkbookRecordList();
-
- boundsheets = new ArrayList<BoundSheetRecord>();
- formats = new ArrayList<FormatRecord>();
- hyperlinks = new ArrayList<HyperlinkRecord>();
- numxfs = 0;
- numfonts = 0;
- maxformatid = -1;
- uses1904datewindowing = false;
- escherBSERecords = new ArrayList<EscherBSERecord>();
- commentRecords = new LinkedHashMap<String, NameCommentRecord>();
- }
-
- /**
- * read support for low level
- * API. Pass in an array of Record objects, A Workbook
- * object is constructed and passed back with all of its initialization set
- * to the passed in records and references to those records held. Unlike Sheet
- * workbook does not use an offset (its assumed to be 0) since its first in a file.
- * If you need an offset then construct a new array with a 0 offset or write your
- * own ;-p.
- *
- * @param recs an array of Record objects
- * @return Workbook object
- */
- public static InternalWorkbook createWorkbook(List<Record> recs) {
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "Workbook (readfile) created with reclen=",
- Integer.valueOf(recs.size()));
- InternalWorkbook retval = new InternalWorkbook();
- List<Record> records = new ArrayList<Record>(recs.size() / 3);
- retval.records.setRecords(records);
-
- int k;
- for (k = 0; k < recs.size(); k++) {
- Record rec = recs.get(k);
-
- if (rec.getSid() == EOFRecord.sid) {
- records.add(rec);
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found workbook eof record at " + k);
- break;
- }
- switch (rec.getSid()) {
-
- case BoundSheetRecord.sid :
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found boundsheet record at " + k);
- retval.boundsheets.add((BoundSheetRecord) rec);
- retval.records.setBspos( k );
- break;
-
- case SSTRecord.sid :
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found sst record at " + k);
- retval.sst = ( SSTRecord ) rec;
- break;
-
- case FontRecord.sid :
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found font record at " + k);
- retval.records.setFontpos( k );
- retval.numfonts++;
- break;
-
- case ExtendedFormatRecord.sid :
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found XF record at " + k);
- retval.records.setXfpos( k );
- retval.numxfs++;
- break;
-
- case TabIdRecord.sid :
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found tabid record at " + k);
- retval.records.setTabpos( k );
- break;
-
- case ProtectRecord.sid :
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found protect record at " + k);
- retval.records.setProtpos( k );
- break;
-
- case BackupRecord.sid :
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found backup record at " + k);
- retval.records.setBackuppos( k );
- break;
- case ExternSheetRecord.sid :
- throw new RuntimeException("Extern sheet is part of LinkTable");
- case NameRecord.sid :
- case SupBookRecord.sid :
- // LinkTable can start with either of these
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found SupBook record at " + k);
- retval.linkTable = new LinkTable(recs, k, retval.records, retval.commentRecords);
- k+=retval.linkTable.getRecordCount() - 1;
- continue;
- case FormatRecord.sid :
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found format record at " + k);
- retval.formats.add((FormatRecord) rec);
- retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode();
- break;
- case DateWindow1904Record.sid :
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found datewindow1904 record at " + k);
- retval.uses1904datewindowing = ((DateWindow1904Record)rec).getWindowing() == 1;
- break;
- case PaletteRecord.sid:
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found palette record at " + k);
- retval.records.setPalettepos( k );
- break;
- case WindowOneRecord.sid:
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found WindowOneRecord at " + k);
- retval.windowOne = (WindowOneRecord) rec;
- break;
- case WriteAccessRecord.sid:
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found WriteAccess at " + k);
- retval.writeAccess = (WriteAccessRecord) rec;
- break;
- case WriteProtectRecord.sid:
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found WriteProtect at " + k);
- retval.writeProtect = (WriteProtectRecord) rec;
- break;
- case FileSharingRecord.sid:
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found FileSharing at " + k);
- retval.fileShare = (FileSharingRecord) rec;
- break;
-
- case NameCommentRecord.sid:
- final NameCommentRecord ncr = (NameCommentRecord) rec;
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "found NameComment at " + k);
- retval.commentRecords.put(ncr.getNameText(), ncr);
- default :
- }
- records.add(rec);
- }
- //What if we dont have any ranges and supbooks
- // if (retval.records.supbookpos == 0) {
- // retval.records.supbookpos = retval.records.bspos + 1;
- // retval.records.namepos = retval.records.supbookpos + 1;
- // }
-
- // Look for other interesting values that
- // follow the EOFRecord
- for ( ; k < recs.size(); k++) {
- Record rec = recs.get(k);
- switch (rec.getSid()) {
- case HyperlinkRecord.sid:
- retval.hyperlinks.add((HyperlinkRecord)rec);
- break;
- }
- }
-
- if (retval.windowOne == null) {
- retval.windowOne = createWindowOne();
- }
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "exit create workbook from existing file function");
- return retval;
- }
-
- /**
- * Creates an empty workbook object with three blank sheets and all the empty
- * fields. Use this to create a workbook from scratch.
- */
- public static InternalWorkbook createWorkbook()
- {
- if (log.check( POILogger.DEBUG ))
- log.log( DEBUG, "creating new workbook from scratch" );
- InternalWorkbook retval = new InternalWorkbook();
- List<Record> records = new ArrayList<Record>( 30 );
- retval.records.setRecords(records);
- List<FormatRecord> formats = retval.formats;
-
- records.add(createBOF());
- records.add(new InterfaceHdrRecord(CODEPAGE));
- records.add(createMMS());
- records.add(InterfaceEndRecord.instance);
- records.add(createWriteAccess());
- records.add(createCodepage());
- records.add(createDSF());
- records.add(createTabId());
- retval.records.setTabpos(records.size() - 1);
- records.add(createFnGroupCount());
- records.add(createWindowProtect());
- records.add(createProtect());
- retval.records.setProtpos(records.size() - 1);
- records.add(createPassword());
- records.add(createProtectionRev4());
- records.add(createPasswordRev4());
- retval.windowOne = createWindowOne();
- records.add(retval.windowOne);
- records.add(createBackup());
- retval.records.setBackuppos(records.size() - 1);
- records.add(createHideObj());
- records.add(createDateWindow1904());
- records.add(createPrecision());
- records.add(createRefreshAll());
- records.add(createBookBool());
- records.add(createFont());
- records.add(createFont());
- records.add(createFont());
- records.add(createFont());
- retval.records.setFontpos( records.size() - 1 ); // last font record position
- retval.numfonts = 4;
-
- // set up format records
- for (int i = 0; i <= 7; i++) {
- FormatRecord rec = createFormat(i);
- retval.maxformatid = retval.maxformatid >= rec.getIndexCode() ? retval.maxformatid : rec.getIndexCode();
- formats.add(rec);
- records.add(rec);
- }
-
- for (int k = 0; k < 21; k++) {
- records.add(retval.createExtendedFormat(k));
- retval.numxfs++;
- }
- retval.records.setXfpos( records.size() - 1 );
- for (int k = 0; k < 6; k++) {
- records.add(retval.createStyle(k));
- }
- records.add(retval.createUseSelFS());
-
- int nBoundSheets = 1; // now just do 1
- for (int k = 0; k < nBoundSheets; k++) {
- BoundSheetRecord bsr = createBoundSheet(k);
-
- records.add(bsr);
- retval.boundsheets.add(bsr);
- retval.records.setBspos(records.size() - 1);
- }
- records.add( retval.createCountry() );
- for ( int k = 0; k < nBoundSheets; k++ ) {
- retval.getOrCreateLinkTable().checkExternSheet(k);
- }
- retval.sst = new SSTRecord();
- records.add(retval.sst);
- records.add(retval.createExtendedSST());
-
- records.add(EOFRecord.instance);
- if (log.check( POILogger.DEBUG ))
- log.log( DEBUG, "exit create new workbook from scratch" );
- return retval;
- }
-
-
- /**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, 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
- */
- 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) {}?
- }
-
- public int getNumRecords() {
- return records.size();
- }
-
- /**
- * gets the font record at the given index in the font table. Remember
- * "There is No Four" (someone at M$ must have gone to Rocky Horror one too
- * many times)
- *
- * @param idx the index to look at (0 or greater but NOT 4)
- * @return FontRecord located at the given index
- */
-
- public FontRecord getFontRecordAt(int idx) {
- int index = idx;
-
- if (index > 4) {
- index -= 1; // adjust for "There is no 4"
- }
- if (index > (numfonts - 1)) {
- throw new ArrayIndexOutOfBoundsException(
- "There are only " + numfonts
- + " font records, you asked for " + idx);
- }
- FontRecord retval =
- ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + index);
-
- return retval;
- }
-
- /**
- * Retrieves the index of the given font
- */
- public int getFontIndex(FontRecord font) {
- 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;
- }
- }
- throw new IllegalArgumentException("Could not find that font!");
- }
-
- /**
- * creates a new font record and adds it to the "font table". This causes the
- * boundsheets to move down one, extended formats to move down (so this function moves
- * those pointers as well)
- *
- * @return FontRecord that was just created
- */
-
- public FontRecord createNewFont() {
- FontRecord rec = createFont();
-
- records.add(records.getFontpos()+1, rec);
- records.setFontpos( records.getFontpos() + 1 );
- numfonts++;
- return rec;
- }
-
- /**
- * Removes the given font record from the
- * file's list. This will make all
- * subsequent font indicies drop by one,
- * so you'll need to update those yourself!
- */
- public void removeFontRecord(FontRecord rec) {
- records.remove(rec); // this updates FontPos for us
- numfonts--;
- }
-
- /**
- * gets the number of font records
- *
- * @return number of font records in the "font table"
- */
-
- public int getNumberOfFontRecords() {
- return numfonts;
- }
-
- /**
- * Sets the BOF for a given sheet
- *
- * @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 sheetIndex, int pos) {
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "setting bof for sheetnum =", Integer.valueOf(sheetIndex),
- " at pos=", Integer.valueOf(pos));
- checkSheets(sheetIndex);
- getBoundSheetRec(sheetIndex)
- .setPositionOfBof(pos);
- }
-
- private BoundSheetRecord getBoundSheetRec(int sheetIndex) {
- return boundsheets.get(sheetIndex);
- }
-
- /**
- * Returns the position of the backup record.
- */
-
- public BackupRecord getBackupRecord() {
- return ( BackupRecord ) records.get(records.getBackuppos());
- }
-
-
- /**
- * sets the name for a given sheet. If the boundsheet record doesn't exist and
- * its only one more than we have, go ahead and create it. If it's > 1 more than
- * we have, except
- *
- * @param sheetnum the sheet number (0 based)
- * @param sheetname the name for the sheet
- */
- public void setSheetName(int sheetnum, String sheetname) {
- checkSheets(sheetnum);
- BoundSheetRecord sheet = boundsheets.get(sheetnum);
- sheet.setSheetname(sheetname);
- }
-
- /**
- * Determines whether a workbook contains the provided sheet name. For the purpose of
- * comparison, long names are truncated to 31 chars.
- *
- * @param name the name to test (case insensitive match)
- * @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check.
- * @return true if the sheet contains the name, false otherwise.
- */
- public boolean doesContainsSheetName(String name, int excludeSheetIdx) {
- String aName = name;
- if (aName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) {
- aName = aName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN);
- }
- for (int i = 0; i < boundsheets.size(); i++) {
- BoundSheetRecord boundSheetRecord = getBoundSheetRec(i);
- if (excludeSheetIdx == i) {
- continue;
- }
- String bName = boundSheetRecord.getSheetname();
- if (bName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) {
- bName = bName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN);
- }
- if (aName.equalsIgnoreCase(bName)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * 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));
- }
-
- /**
- * gets the name for a given sheet.
- *
- * @param sheetIndex the sheet number (0 based)
- * @return sheetname the name for the sheet
- */
- public String getSheetName(int sheetIndex) {
- return getBoundSheetRec(sheetIndex).getSheetname();
- }
-
- /**
- * Gets the hidden flag for a given sheet.
- * Note that a sheet could instead be
- * set to be very hidden, which is different
- * ({@link #isSheetVeryHidden(int)})
- *
- * @param sheetnum the sheet number (0 based)
- * @return True if sheet is hidden
- */
- public boolean isSheetHidden(int sheetnum) {
- return getBoundSheetRec(sheetnum).isHidden();
- }
-
- /**
- * Gets the very hidden flag for a given sheet.
- * This is different from the normal
- * hidden flag
- * ({@link #isSheetHidden(int)})
- *
- * @param sheetnum the sheet number (0 based)
- * @return True if sheet is very hidden
- */
- public boolean isSheetVeryHidden(int sheetnum) {
- return getBoundSheetRec(sheetnum).isVeryHidden();
- }
-
- /**
- * Hide or unhide a sheet
- *
- * @param sheetnum The sheet number
- * @param hidden True to mark the sheet as hidden, false otherwise
- */
- public void setSheetHidden(int sheetnum, boolean hidden) {
- getBoundSheetRec(sheetnum).setHidden(hidden);
- }
-
- /**
- * Hide or unhide a sheet.
- * 0 = not hidden
- * 1 = hidden
- * 2 = very hidden.
- *
- * @param sheetnum The sheet number
- * @param hidden 0 for not hidden, 1 for hidden, 2 for very hidden
- */
- public void setSheetHidden(int sheetnum, int hidden) {
- BoundSheetRecord bsr = getBoundSheetRec(sheetnum);
- boolean h = false;
- boolean vh = false;
- if(hidden == 0) {
- } else if(hidden == 1) {
- h = true;
- } else if(hidden == 2) {
- vh = true;
- } else {
- throw new IllegalArgumentException("Invalid hidden flag " + hidden + " given, must be 0, 1 or 2");
- }
- bsr.setHidden(h);
- bsr.setVeryHidden(vh);
- }
-
-
- /**
- * get the sheet's index
- * @param name sheet name
- * @return sheet index or -1 if it was not found.
- */
- public int getSheetIndex(String name) {
- int retval = -1;
-
- for (int k = 0; k < boundsheets.size(); k++) {
- String sheet = getSheetName(k);
-
- if (sheet.equalsIgnoreCase(name)) {
- retval = k;
- break;
- }
- }
- return retval;
- }
-
- /**
- * if we're trying to address one more sheet than we have, go ahead and add it! if we're
- * trying to address >1 more than we have throw an exception!
- */
- private void checkSheets(int sheetnum) {
- if ((boundsheets.size()) <= sheetnum) { // if we're short one add another..
- if ((boundsheets.size() + 1) <= sheetnum) {
- throw new RuntimeException("Sheet number out of bounds!");
- }
- BoundSheetRecord bsr = createBoundSheet(sheetnum);
-
- records.add(records.getBspos()+1, bsr);
- records.setBspos( records.getBspos() + 1 );
- boundsheets.add(bsr);
- getOrCreateLinkTable().checkExternSheet(sheetnum);
- fixTabIdRecord();
- } else {
- // Ensure we have enough tab IDs
- // Can be a few short if new sheets were added
- if(records.getTabpos() > 0) {
- TabIdRecord tir = ( TabIdRecord ) records.get(records.getTabpos());
- if(tir._tabids.length < boundsheets.size()) {
- fixTabIdRecord();
- }
- }
- }
- }
-
- /**
- * @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();
- }
-
- // Within NameRecords, it's ok to have the formula
- // part point at deleted sheets. It's also ok to
- // have the ExternSheetNumber point at deleted
- // sheets.
- // However, the sheet index must be adjusted, or
- // excel will break. (Sheet index is either 0 for
- // global, or 1 based index to sheet)
- int sheetNum1Based = sheetIndex + 1;
- for(int i=0; i<getNumNames(); i++) {
- 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);
- }
- }
- }
-
- /**
- * make the tabid record look like the current situation.
- *
- */
- private void fixTabIdRecord() {
- TabIdRecord tir = ( TabIdRecord ) records.get(records.getTabpos());
- short[] tia = new short[ boundsheets.size() ];
-
- for (short k = 0; k < tia.length; k++) {
- tia[ k ] = k;
- }
- tir.setTabIdArray(tia);
- }
-
- /**
- * returns the number of boundsheet objects contained in this workbook.
- *
- * @return number of BoundSheet records
- */
-
- public int getNumSheets() {
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "getNumSheets=", Integer.valueOf(boundsheets.size()));
- return boundsheets.size();
- }
-
- /**
- * get the number of ExtendedFormat records contained in this workbook.
- *
- * @return int count of ExtendedFormat records
- */
-
- public int getNumExFormats() {
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "getXF=", Integer.valueOf(numxfs));
- return numxfs;
- }
-
- /**
- * gets the ExtendedFormatRecord at the given 0-based index
- *
- * @param index of the Extended format record (0-based)
- * @return ExtendedFormatRecord at the given index
- */
-
- public ExtendedFormatRecord getExFormatAt(int index) {
- int xfptr = records.getXfpos() - (numxfs - 1);
-
- xfptr += index;
- ExtendedFormatRecord retval =
- ( ExtendedFormatRecord ) records.get(xfptr);
-
- return retval;
- }
-
- /**
- * Removes the given ExtendedFormatRecord record from the
- * file's list. This will make all
- * subsequent font indicies drop by one,
- * so you'll need to update those yourself!
- */
- public void removeExFormatRecord(ExtendedFormatRecord rec) {
- records.remove(rec); // this updates XfPos for us
- numxfs--;
- }
-
-
- /**
- * creates a new Cell-type Extneded Format Record and adds it to the end of
- * ExtendedFormatRecords collection
- *
- * @return ExtendedFormatRecord that was created
- */
-
- public ExtendedFormatRecord createCellXF() {
- ExtendedFormatRecord xf = createExtendedFormat();
-
- records.add(records.getXfpos()+1, xf);
- records.setXfpos( records.getXfpos() + 1 );
- numxfs++;
- return xf;
- }
-
- /**
- * Returns the StyleRecord for the given
- * xfIndex, or null if that ExtendedFormat doesn't
- * have a Style set.
- */
- public StyleRecord getStyleRecord(int xfIndex) {
- // Style records always follow after
- // the ExtendedFormat records
- for(int i=records.getXfpos(); i<records.size(); i++) {
- Record r = records.get(i);
- if(r instanceof ExtendedFormatRecord) {
- continue;
- }
- if(!(r instanceof StyleRecord)) {
- continue;
- }
- StyleRecord sr = (StyleRecord)r;
- if(sr.getXFIndex() == xfIndex) {
- return sr;
- }
- }
- return null;
- }
- /**
- * Creates a new StyleRecord, for the given Extended
- * Format index, and adds it onto the end of the
- * records collection
- */
- public StyleRecord createStyleRecord(int xfIndex) {
- // Style records always follow after
- // the ExtendedFormat records
- StyleRecord newSR = new StyleRecord();
- newSR.setXFIndex(xfIndex);
-
- // Find the spot
- int addAt = -1;
- for(int i=records.getXfpos(); i<records.size() &&
- addAt == -1; i++) {
- Record r = records.get(i);
- if(r instanceof ExtendedFormatRecord ||
- r instanceof StyleRecord) {
- // Keep going
- } else {
- addAt = i;
- }
- }
- if(addAt == -1) {
- throw new IllegalStateException("No XF Records found!");
- }
- records.add(addAt, newSR);
-
- return newSR;
- }
-
- /**
- * Adds a string to the SST table and returns its index (if its a duplicate
- * just returns its index and update the counts) ASSUMES compressed unicode
- * (meaning 8bit)
- *
- * @param string the string to be added to the SSTRecord
- *
- * @return index of the string within the SSTRecord
- */
-
- public int addSSTString(UnicodeString string) {
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "insert to sst string='", string);
- if (sst == null) {
- insertSST();
- }
- return sst.addString(string);
- }
-
- /**
- * given an index into the SST table, this function returns the corresponding String value
- * @return String containing the SST String
- */
-
- public UnicodeString getSSTString(int str) {
- if (sst == null) {
- insertSST();
- }
- UnicodeString retval = sst.getString(str);
-
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "Returning SST for index=", Integer.valueOf(str),
- " String= ", retval);
- return retval;
- }
-
- /**
- * use this function to add a Shared String Table to an existing sheet (say
- * generated by a different java api) without an sst....
- * @see #createExtendedSST()
- * @see org.apache.poi.hssf.record.SSTRecord
- */
-
- public void insertSST() {
- if (log.check( POILogger.DEBUG ))
- log.log(DEBUG, "creating new SST via insertSST!");
- sst = new SSTRecord();
- records.add(records.size() - 1, createExtendedSST());
- records.add(records.size() - 2, sst);
- }
-
- /**
- * Serializes all records int the worksheet section into a big byte array. Use
- * this to write the Workbook out.
- *
- * @return byte array containing the HSSF-only portions of the POIFS file.
- */
- // GJS: Not used so why keep it.
- // public byte [] serialize() {
- // log.log(DEBUG, "Serializing Workbook!");
- // byte[] retval = null;
- //
- //// ArrayList bytes = new ArrayList(records.size());
- // int arraysize = getSize();
- // int pos = 0;
- //
- // retval = new byte[ arraysize ];
- // for (int k = 0; k < records.size(); k++) {
- //
- // 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()) {
- // pos += record.serialize(pos, retval); // rec.length;
- // }
- // }
- // log.log(DEBUG, "Exiting serialize workbook");
- // return retval;
- // }
-
- /**
- * Serializes all records int the worksheet section into a big byte array. Use
- * this to write the Workbook out.
- * @param offset of the data to be written
- * @param data array of bytes to write this to
- */
-
- public int serialize( int offset, byte[] data )
- {
- if (log.check( POILogger.DEBUG ))
- log.log( DEBUG, "Serializing Workbook with offsets" );
-
- int pos = 0;
-
- SSTRecord sst = null;
- int sstPos = 0;
- boolean wroteBoundSheets = false;
- for ( int k = 0; k < records.size(); k++ )
- {
-
- 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() )
- {
- int len = 0;
- if (record instanceof SSTRecord)
- {
- sst = (SSTRecord)record;
- sstPos = pos;
- }
- if (record.getSid() == ExtSSTRecord.sid && sst != null)
- {
- record = sst.createExtSSTRecord(sstPos + offset);
- }
- if (record instanceof BoundSheetRecord) {
- if(!wroteBoundSheets) {
- for (int i = 0; i < boundsheets.size(); i++) {
- len+= getBoundSheetRec(i)
- .serialize(pos+offset+len, data);
- }
- wroteBoundSheets = true;
- }
- } else {
- len = record.serialize( pos + offset, data );
- }
- ///// DEBUG BEGIN /////
- // if (len != record.getRecordSize())
- // throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize());
- ///// DEBUG END /////
- pos += len; // rec.length;
- }
- }
- if (log.check( POILogger.DEBUG ))
- log.log( DEBUG, "Exiting serialize workbook" );
- return pos;
- }
-
- public int getSize()
- {
- int retval = 0;
-
- SSTRecord sst = null;
- for ( int k = 0; k < records.size(); k++ )
- {
- 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 instanceof SSTRecord)
- sst = (SSTRecord)record;
- if (record.getSid() == ExtSSTRecord.sid && sst != null)
- retval += sst.calcExtSSTRecordSize();
- else
- retval += record.getRecordSize();
- }
- }
- return retval;
- }
-
- private static BOFRecord createBOF() {
- BOFRecord retval = new BOFRecord();
-
- retval.setVersion(( short ) 0x600);
- retval.setType(BOFRecord.TYPE_WORKBOOK);
- retval.setBuild(( short ) 0x10d3);
- retval.setBuildYear(( short ) 1996);
- retval.setHistoryBitMask(0x41); // was c1 before verify
- retval.setRequiredVersion(0x6);
- return retval;
- }
-
-
- private static MMSRecord createMMS() {
- MMSRecord retval = new MMSRecord();
-
- retval.setAddMenuCount(( byte ) 0);
- retval.setDelMenuCount(( byte ) 0);
- return retval;
- }
-
- /**
- * creates the WriteAccess record containing the logged in user's name
- */
- private static WriteAccessRecord createWriteAccess() {
- WriteAccessRecord retval = new WriteAccessRecord();
-
- try {
- retval.setUsername(System.getProperty("user.name"));
- } catch (AccessControlException e) {
- // AccessControlException can occur in a restricted context
- // (client applet/jws application or restricted security server)
- retval.setUsername("POI");
- }
- return retval;
- }
-
- private static CodepageRecord createCodepage() {
- CodepageRecord retval = new CodepageRecord();
-
- retval.setCodepage(CODEPAGE);
- return retval;
- }
-
- private static DSFRecord createDSF() {
- return new DSFRecord(false); // we don't even support double stream files
- }
-
- /**
- * creates the TabId record containing an array
- */
- private static TabIdRecord createTabId() {
- return new TabIdRecord();
- }
-
- /**
- * creates the FnGroupCount record containing the Magic number constant of 14.
- */
- private static FnGroupCountRecord createFnGroupCount() {
- FnGroupCountRecord retval = new FnGroupCountRecord();
-
- retval.setCount(( short ) 14);
- return retval;
- }
-
- /**
- * @return a new WindowProtect record with protect set to false.
- */
- private static WindowProtectRecord createWindowProtect() {
- // by default even when we support it we won't
- // want it to be protected
- return new WindowProtectRecord(false);
- }
-
- /**
- * @return a new Protect record with protect set to false.
- */
- private static ProtectRecord createProtect() {
- // by default even when we support it we won't
- // want it to be protected
- return new ProtectRecord(false);
- }
-
- /**
- * @return a new Password record with password set to 0x0000 (no password).
- */
- private static PasswordRecord createPassword() {
- return new PasswordRecord(0x0000); // no password by default!
- }
-
- /**
- * @return a new ProtectionRev4 record with protect set to false.
- */
- private static ProtectionRev4Record createProtectionRev4() {
- return new ProtectionRev4Record(false);
- }
-
- /**
- * @return a new PasswordRev4 record with password set to 0.
- */
- private static PasswordRev4Record createPasswordRev4() {
- return new PasswordRev4Record(0x0000);
- }
-
- /**
- * creates the WindowOne record with the following magic values: <P>
- * horizontal hold - 0x168 <P>
- * vertical hold - 0x10e <P>
- * width - 0x3a5c <P>
- * height - 0x23be <P>
- * options - 0x38 <P>
- * selected tab - 0 <P>
- * displayed tab - 0 <P>
- * num selected tab- 0 <P>
- * tab width ratio - 0x258 <P>
- */
- private static WindowOneRecord createWindowOne() {
- WindowOneRecord retval = new WindowOneRecord();
-
- retval.setHorizontalHold(( short ) 0x168);
- retval.setVerticalHold(( short ) 0x10e);
- retval.setWidth(( short ) 0x3a5c);
- retval.setHeight(( short ) 0x23be);
- retval.setOptions(( short ) 0x38);
- retval.setActiveSheetIndex( 0x0);
- retval.setFirstVisibleTab(0x0);
- retval.setNumSelectedTabs(( short ) 1);
- retval.setTabWidthRatio(( short ) 0x258);
- return retval;
- }
-
- /**
- * creates the Backup record with backup set to 0. (loose the data, who cares)
- */
- private static BackupRecord createBackup() {
- BackupRecord retval = new BackupRecord();
-
- retval.setBackup(( short ) 0); // by default DONT save backups of files...just loose data
- return retval;
- }
-
- /**
- * creates the HideObj record with hide object set to 0. (don't hide)
- */
- private static HideObjRecord createHideObj() {
- HideObjRecord retval = new HideObjRecord();
- retval.setHideObj(( short ) 0); // by default set hide object off
- return retval;
- }
-
- /**
- * creates the DateWindow1904 record with windowing set to 0. (don't window)
- */
- private static DateWindow1904Record createDateWindow1904() {
- DateWindow1904Record retval = new DateWindow1904Record();
-
- retval.setWindowing(( short ) 0); // don't EVER use 1904 date windowing...tick tock..
- return retval;
- }
-
- /**
- * creates the Precision record with precision set to true. (full precision)
- */
- private static PrecisionRecord createPrecision() {
- PrecisionRecord retval = new PrecisionRecord();
- retval.setFullPrecision(true); // always use real numbers in calculations!
- return retval;
- }
-
- /**
- * @return a new RefreshAll record with refreshAll set to false. (do not refresh all calcs)
- */
- private static RefreshAllRecord createRefreshAll() {
- return new RefreshAllRecord(false);
- }
-
- /**
- * creates the BookBool record with saveLinkValues set to 0. (don't save link values)
- */
- private static BookBoolRecord createBookBool() {
- BookBoolRecord retval = new BookBoolRecord();
- retval.setSaveLinkValues(( short ) 0);
- return retval;
- }
-
- /**
- * creates a Font record with the following magic values: <P>
- * fontheight = 0xc8<P>
- * attributes = 0x0<P>
- * color palette index = 0x7fff<P>
- * bold weight = 0x190<P>
- * Font Name Length = 5 <P>
- * Font Name = Arial <P>
- */
- private static FontRecord createFont() {
- FontRecord retval = new FontRecord();
-
- retval.setFontHeight(( short ) 0xc8);
- retval.setAttributes(( short ) 0x0);
- retval.setColorPaletteIndex(( short ) 0x7fff);
- retval.setBoldWeight(( short ) 0x190);
- retval.setFontName("Arial");
- return retval;
- }
-
- /**
- * Creates a FormatRecord object
- * @param id the number of the format record to create (meaning its position in
- * a file as M$ Excel would create it.)
- */
- private static FormatRecord createFormat(int id) {
- // we'll need multiple editions for
- // the different formats
-
-
- switch (id) {
- case 0: return new FormatRecord(5, BuiltinFormats.getBuiltinFormat(5));
- case 1: return new FormatRecord(6, BuiltinFormats.getBuiltinFormat(6));
- case 2: return new FormatRecord(7, BuiltinFormats.getBuiltinFormat(7));
- case 3: return new FormatRecord(8, BuiltinFormats.getBuiltinFormat(8));
- case 4: return new FormatRecord(0x2a, BuiltinFormats.getBuiltinFormat(0x2a));
- case 5: return new FormatRecord(0x29, BuiltinFormats.getBuiltinFormat(0x29));
- case 6: return new FormatRecord(0x2c, BuiltinFormats.getBuiltinFormat(0x2c));
- case 7: return new FormatRecord(0x2b, BuiltinFormats.getBuiltinFormat(0x2b));
- }
- throw new IllegalArgumentException("Unexpected id " + id);
- }
-
- /**
- * Creates an ExtendedFormatRecord object
- * @param id the number of the extended format record to create (meaning its position in
- * a file as MS Excel would create it.)
- */
- private static ExtendedFormatRecord createExtendedFormat(int id) { // we'll need multiple editions
- ExtendedFormatRecord retval = new ExtendedFormatRecord();
-
- switch (id) {
-
- case 0 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 1 :
- retval.setFontIndex(( short ) 1);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 2 :
- retval.setFontIndex(( short ) 1);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 3 :
- retval.setFontIndex(( short ) 2);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 4 :
- retval.setFontIndex(( short ) 2);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 5 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 6 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 7 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 8 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 9 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 10 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 11 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 12 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 13 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 14 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff400);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- // cell records
- case 15 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0);
- retval.setCellOptions(( short ) 0x1);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0x0);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- // style
- case 16 :
- retval.setFontIndex(( short ) 1);
- retval.setFormatIndex(( short ) 0x2b);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff800);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 17 :
- retval.setFontIndex(( short ) 1);
- retval.setFormatIndex(( short ) 0x29);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff800);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 18 :
- retval.setFontIndex(( short ) 1);
- retval.setFormatIndex(( short ) 0x2c);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff800);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 19 :
- retval.setFontIndex(( short ) 1);
- retval.setFormatIndex(( short ) 0x2a);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff800);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 20 :
- retval.setFontIndex(( short ) 1);
- retval.setFormatIndex(( short ) 0x9);
- retval.setCellOptions(( short ) 0xfffffff5);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0xfffff800);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- // unused from this point down
- case 21 :
- retval.setFontIndex(( short ) 5);
- retval.setFormatIndex(( short ) 0x0);
- retval.setCellOptions(( short ) 0x1);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0x800);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 22 :
- retval.setFontIndex(( short ) 6);
- retval.setFormatIndex(( short ) 0x0);
- retval.setCellOptions(( short ) 0x1);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0x5c00);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 23 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0x31);
- retval.setCellOptions(( short ) 0x1);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0x5c00);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 24 :
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0x8);
- retval.setCellOptions(( short ) 0x1);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0x5c00);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
-
- case 25 :
- retval.setFontIndex(( short ) 6);
- retval.setFormatIndex(( short ) 0x8);
- retval.setCellOptions(( short ) 0x1);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0x5c00);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- break;
- }
- return retval;
- }
-
- /**
- * creates an default cell type ExtendedFormatRecord object.
- * @return ExtendedFormatRecord with intial defaults (cell-type)
- */
- private static ExtendedFormatRecord createExtendedFormat() {
- ExtendedFormatRecord retval = new ExtendedFormatRecord();
-
- retval.setFontIndex(( short ) 0);
- retval.setFormatIndex(( short ) 0x0);
- retval.setCellOptions(( short ) 0x1);
- retval.setAlignmentOptions(( short ) 0x20);
- retval.setIndentionOptions(( short ) 0);
- retval.setBorderOptions(( short ) 0);
- retval.setPaletteOptions(( short ) 0);
- retval.setAdtlPaletteOptions(( short ) 0);
- retval.setFillPaletteOptions(( short ) 0x20c0);
- retval.setTopBorderPaletteIdx(HSSFColor.BLACK.index);
- retval.setBottomBorderPaletteIdx(HSSFColor.BLACK.index);
- retval.setLeftBorderPaletteIdx(HSSFColor.BLACK.index);
- retval.setRightBorderPaletteIdx(HSSFColor.BLACK.index);
- return retval;
- }
-
- /**
- * Creates a StyleRecord object
- * @param id the number of the style record to create (meaning its position in
- * a file as MS Excel would create it.
- */
- private static StyleRecord createStyle(int id) { // we'll need multiple editions
- StyleRecord retval = new StyleRecord();
-
- switch (id) {
-
- case 0 :
- retval.setXFIndex(0x010);
- retval.setBuiltinStyle(3);
- retval.setOutlineStyleLevel(( byte ) 0xffffffff);
- break;
-
- case 1 :
- retval.setXFIndex(0x011);
- retval.setBuiltinStyle(6);
- retval.setOutlineStyleLevel(( byte ) 0xffffffff);
- break;
-
- case 2 :
- retval.setXFIndex(0x012);
- retval.setBuiltinStyle(4);
- retval.setOutlineStyleLevel(( byte ) 0xffffffff);
- break;
-
- case 3 :
- retval.setXFIndex(0x013);
- retval.setBuiltinStyle(7);
- retval.setOutlineStyleLevel(( byte ) 0xffffffff);
- break;
-
- case 4 :
- retval.setXFIndex(0x000);
- retval.setBuiltinStyle(0);
- retval.setOutlineStyleLevel(( byte ) 0xffffffff);
- break;
-
- case 5 :
- retval.setXFIndex(0x014);
- retval.setBuiltinStyle(5);
- retval.setOutlineStyleLevel(( byte ) 0xffffffff);
- break;
- }
- return retval;
- }
-
- /**
- * Creates a palette record initialized to the default palette
- */
- private static PaletteRecord createPalette() {
- return new PaletteRecord();
- }
-
- /**
- * @return a new UseSelFS object with the use natural language flag set to 0 (false)
- */
- private static UseSelFSRecord createUseSelFS() {
- return new UseSelFSRecord(false);
- }
-
- /**
- * create a "bound sheet" or "bundlesheet" (depending who you ask) record
- * Always sets the sheet's bof to 0. You'll need to set that yourself.
- * @param id either sheet 0,1 or 2.
- * @return record containing a BoundSheetRecord
- * @see org.apache.poi.hssf.record.BoundSheetRecord
- * @see org.apache.poi.hssf.record.Record
- */
- private static BoundSheetRecord createBoundSheet(int id) {
- return new BoundSheetRecord("Sheet" + (id+1));
- }
-
- /**
- * Creates the Country record with the default country set to 1
- * and current country set to 7 in case of russian locale ("ru_RU") and 1 otherwise
- */
- private static CountryRecord createCountry() {
- CountryRecord retval = new CountryRecord();
-
- retval.setDefaultCountry(( short ) 1);
-
- // from Russia with love ;)
- if ( Locale.getDefault().toString().equals( "ru_RU" ) ) {
- retval.setCurrentCountry(( short ) 7);
- }
- else {
- retval.setCurrentCountry(( short ) 1);
- }
-
- return retval;
- }
-
- /**
- * Creates the ExtendedSST record with numstrings per bucket set to 0x8. HSSF
- * doesn't yet know what to do with this thing, but we create it with nothing in
- * it hardly just to make Excel happy and our sheets look like Excel's
- */
- private static ExtSSTRecord createExtendedSST() {
- ExtSSTRecord retval = new ExtSSTRecord();
- retval.setNumStringsPerBucket(( short ) 0x8);
- return retval;
- }
-
- /**
- * lazy initialization
- * Note - creating the link table causes creation of 1 EXTERNALBOOK and 1 EXTERNALSHEET record
- */
- private LinkTable getOrCreateLinkTable() {
- if(linkTable == null) {
- linkTable = new LinkTable((short) getNumSheets(), records);
- }
- return linkTable;
- }
-
- /** finds the sheet name by his extern sheet index
- * @param externSheetIndex extern sheet index
- * @return sheet name.
- */
- public String findSheetNameFromExternSheet(int externSheetIndex){
-
- int indexToSheet = linkTable.getIndexToInternalSheet(externSheetIndex);
- if (indexToSheet < 0) {
- // TODO - what does '-1' mean here?
- //error check, bail out gracefully!
- return "";
- }
- if (indexToSheet >= boundsheets.size()) {
- // Not sure if this can ever happen (See bug 45798)
- return ""; // Seems to be what excel would do in this case
- }
- return getSheetName(indexToSheet);
- }
- public ExternalSheet getExternalSheet(int externSheetIndex) {
- String[] extNames = linkTable.getExternalBookAndSheetName(externSheetIndex);
- if (extNames == null) {
- return null;
- }
- return new ExternalSheet(extNames[0], extNames[1]);
- }
- public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
- String nameName = linkTable.resolveNameXText(externSheetIndex, externNameIndex);
- if(nameName == null) {
- return null;
- }
- int ix = linkTable.resolveNameXIx(externSheetIndex, externNameIndex);
- return new ExternalName(nameName, externNameIndex, ix);
- }
-
- /**
- * Finds the sheet index for a particular external sheet number.
- * @param externSheetNumber The external sheet number to convert
- * @return The index to the sheet found.
- */
- public int getSheetIndexFromExternSheetIndex(int externSheetNumber)
- {
- return linkTable.getSheetIndexFromExternSheetIndex(externSheetNumber);
- }
-
- /** returns the extern sheet number for specific sheet number ,
- * if this sheet doesn't exist in extern sheet , add it
- * @param sheetNumber sheet number
- * @return index to extern sheet
- */
- public short checkExternSheet(int sheetNumber){
- return (short)getOrCreateLinkTable().checkExternSheet(sheetNumber);
- }
-
- public int getExternalSheetIndex(String workbookName, String sheetName) {
- return getOrCreateLinkTable().getExternalSheetIndex(workbookName, sheetName);
- }
-
-
- /** gets the total number of names
- * @return number of names
- */
- public int getNumNames(){
- if(linkTable == null) {
- return 0;
- }
- return linkTable.getNumNames();
- }
-
- /** gets the name record
- * @param index name index
- * @return name record
- */
- public NameRecord getNameRecord(int index){
- return linkTable.getNameRecord(index);
- }
-
- /** gets the name comment record
- * @param nameRecord name record who's comment is required.
- * @return name comment record or <code>null</code> if there isn't one for the given name.
- */
- public NameCommentRecord getNameCommentRecord(final NameRecord nameRecord){
- return commentRecords.get(nameRecord.getNameText());
- }
-
- /** creates new name
- * @return new name record
- */
- public NameRecord createName(){
- return addName(new NameRecord());
- }
-
-
- /** creates new name
- * @return new name record
- */
- public NameRecord addName(NameRecord name)
- {
-
- LinkTable linkTable = getOrCreateLinkTable();
- linkTable.addName(name);
-
- return name;
- }
-
- /**
- * Generates a NameRecord to represent a built-in region
- * @return a new NameRecord
- */
- 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, sheetNumber);
-
- if(linkTable.nameAlreadyExists(name)) {
- throw new RuntimeException("Builtin (" + builtInName
- + ") already exists for sheet (" + sheetNumber + ")");
- }
- addName(name);
- return name;
- }
-
-
- /** removes the name
- * @param nameIndex name index
- */
- public void removeName(int nameIndex){
-
- if (linkTable.getNumNames() > nameIndex) {
- int idx = findFirstRecordLocBySid(NameRecord.sid);
- records.remove(idx + nameIndex);
- linkTable.removeName(nameIndex);
- }
- }
-
- /**
- * If a {@link NameCommentRecord} is added or the name it references
- * is renamed, then this will update the lookup cache for it.
- */
- public void updateNameCommentRecordCache(final NameCommentRecord commentRecord) {
- if(commentRecords.containsValue(commentRecord)) {
- for(Entry<String,NameCommentRecord> entry : commentRecords.entrySet()) {
- if(entry.getValue().equals(commentRecord)) {
- commentRecords.remove(entry.getKey());
- break;
- }
- }
- }
- commentRecords.put(commentRecord.getNameText(), commentRecord);
- }
-
- /**
- * Returns a format index that matches the passed in format. It does not tie into HSSFDataFormat.
- * @param format the format string
- * @param createIfNotFound creates a new format if format not found
- * @return the format id of a format that matches or -1 if none found and createIfNotFound
- */
- public short getFormat(String format, boolean createIfNotFound) {
- for (FormatRecord r : formats) {
- if (r.getFormatString().equals(format)) {
- return (short)r.getIndexCode();
- }
- }
-
- if (createIfNotFound) {
- return (short)createFormat(format);
- }
-
- return -1;
- }
-
- /**
- * Returns the list of FormatRecords in the workbook.
- * @return ArrayList of FormatRecords in the notebook
- */
- public List<FormatRecord> getFormats() {
- return formats;
- }
-
- /**
- * Creates a FormatRecord, inserts it, and returns the index code.
- * @param formatString the format string
- * @return the index code of the format record.
- * @see org.apache.poi.hssf.record.FormatRecord
- * @see org.apache.poi.hssf.record.Record
- */
- public int createFormat(String formatString) {
-
- maxformatid = maxformatid >= 0xa4 ? maxformatid + 1 : 0xa4; //Starting value from M$ empircal study.
- FormatRecord rec = new FormatRecord(maxformatid, formatString);
-
- int pos = 0;
- while ( pos < records.size() && records.get( pos ).getSid() != FormatRecord.sid )
- pos++;
- pos += formats.size();
- formats.add( rec );
- records.add( pos, rec );
- return maxformatid;
- }
-
-
-
- /**
- * Returns the first occurance of a record matching a particular sid.
- */
- public Record findFirstRecordBySid(short sid) {
- for (Record record : records) {
- if (record.getSid() == sid) {
- return record;
- }
- }
- return null;
- }
-
- /**
- * Returns the index of a record matching a particular sid.
- * @param sid The sid of the record to match
- * @return The index of -1 if no match made.
- */
- public int findFirstRecordLocBySid(short sid) {
- int index = 0;
- for (Record record : records) {
- if (record.getSid() == sid) {
- return index;
- }
- index ++;
- }
- return -1;
- }
-
- /**
- * Returns the next occurance of a record matching a particular sid.
- */
- public Record findNextRecordBySid(short sid, int pos) {
- int matches = 0;
- for (Record record : records) {
- if (record.getSid() == sid) {
- if (matches++ == pos)
- return record;
- }
- }
- return null;
- }
-
- public List<HyperlinkRecord> getHyperlinks()
- {
- return hyperlinks;
- }
-
- public List<Record> getRecords() {
- return records.getRecords();
- }
-
- /**
- * Whether date windowing is based on 1/2/1904 or 1/1/1900.
- * Some versions of Excel (Mac) can save workbooks using 1904 date windowing.
- *
- * @return true if using 1904 date windowing
- */
- public boolean isUsing1904DateWindowing() {
- return uses1904datewindowing;
- }
-
- /**
- * Returns the custom palette in use for this workbook; if a custom palette record
- * does not exist, then it is created.
- */
- public PaletteRecord getCustomPalette()
- {
- PaletteRecord palette;
- int palettePos = records.getPalettepos();
- if (palettePos != -1) {
- Record rec = records.get(palettePos);
- if (rec instanceof PaletteRecord) {
- palette = (PaletteRecord) rec;
- } else throw new RuntimeException("InternalError: Expected PaletteRecord but got a '"+rec+"'");
- }
- else
- {
- palette = createPalette();
- //Add the palette record after the bof which is always the first record
- records.add(1, palette);
- records.setPalettepos(1);
- }
- return palette;
- }
-
- /**
- * Finds the primary drawing group, if one already exists
- */
- public void findDrawingGroup() {
- if(drawingManager != null) {
- // We already have it!
- return;
- }
-
- // Need to find a DrawingGroupRecord that
- // contains a EscherDggRecord
- for(Record r : records) {
- if(r instanceof DrawingGroupRecord) {
- DrawingGroupRecord dg = (DrawingGroupRecord)r;
- dg.processChildRecords();
-
- EscherContainerRecord cr =
- dg.getEscherContainer();
- if(cr == null) {
- continue;
- }
-
- EscherDggRecord dgg = null;
- for(Iterator<EscherRecord> it = cr.getChildIterator(); 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
- int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
-
- // If there is one, does it have a EscherDggRecord?
- if(dgLoc != -1) {
- DrawingGroupRecord dg = (DrawingGroupRecord)records.get(dgLoc);
- EscherDggRecord dgg = null;
- for(EscherRecord er : dg.getEscherRecords()) {
- if(er instanceof EscherDggRecord) {
- dgg = (EscherDggRecord)er;
- }
- }
-
- if(dgg != null) {
- drawingManager = new DrawingManager2(dgg);
- }
- }
- }
-
- /**
- * Creates a primary drawing group record. If it already
- * exists then it's modified.
- */
- public void createDrawingGroup() {
- if (drawingManager == null) {
- EscherContainerRecord dggContainer = new EscherContainerRecord();
- EscherDggRecord dgg = new EscherDggRecord();
- EscherOptRecord opt = new EscherOptRecord();
- EscherSplitMenuColorsRecord splitMenuColors = new EscherSplitMenuColorsRecord();
-
- dggContainer.setRecordId((short) 0xF000);
- dggContainer.setOptions((short) 0x000F);
- dgg.setRecordId(EscherDggRecord.RECORD_ID);
- dgg.setOptions((short)0x0000);
- dgg.setShapeIdMax(1024);
- dgg.setNumShapesSaved(0);
- dgg.setDrawingsSaved(0);
- dgg.setFileIdClusters(new EscherDggRecord.FileIdCluster[] {} );
- drawingManager = new DrawingManager2(dgg);
- EscherContainerRecord bstoreContainer = null;
- if (escherBSERecords.size() > 0)
- {
- bstoreContainer = new EscherContainerRecord();
- bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER );
- bstoreContainer.setOptions( (short) ( (escherBSERecords.size() << 4) | 0xF ) );
- for (EscherRecord escherRecord : escherBSERecords) {
- bstoreContainer.addChildRecord( escherRecord );
- }
- }
- opt.setRecordId((short) 0xF00B);
- opt.setOptions((short) 0x0033);
- opt.addEscherProperty( new EscherBoolProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 524296) );
- opt.addEscherProperty( new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, 0x08000041) );
- opt.addEscherProperty( new EscherRGBProperty(EscherProperties.LINESTYLE__COLOR, 134217792) );
- splitMenuColors.setRecordId((short) 0xF11E);
- splitMenuColors.setOptions((short) 0x0040);
- splitMenuColors.setColor1(0x0800000D);
- splitMenuColors.setColor2(0x0800000C);
- splitMenuColors.setColor3(0x08000017);
- splitMenuColors.setColor4(0x100000F7);
-
- dggContainer.addChildRecord(dgg);
- if (bstoreContainer != null)
- dggContainer.addChildRecord( bstoreContainer );
- dggContainer.addChildRecord(opt);
- dggContainer.addChildRecord(splitMenuColors);
-
- int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
- if (dgLoc == -1) {
- DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
- drawingGroup.addEscherRecord(dggContainer);
- int loc = findFirstRecordLocBySid(CountryRecord.sid);
-
- getRecords().add(loc+1, drawingGroup);
- } else {
- DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
- drawingGroup.addEscherRecord(dggContainer);
- getRecords().set(dgLoc, drawingGroup);
- }
-
- }
- }
-
- public WindowOneRecord getWindowOne() {
- return windowOne;
- }
-
- public EscherBSERecord getBSERecord(int pictureIndex) {
- return escherBSERecords.get(pictureIndex-1);
- }
-
- public int addBSERecord(EscherBSERecord e) {
- createDrawingGroup();
-
- // maybe we don't need that as an instance variable anymore
- escherBSERecords.add( e );
-
- int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
- DrawingGroupRecord drawingGroup = (DrawingGroupRecord) getRecords().get( dgLoc );
-
- EscherContainerRecord dggContainer = (EscherContainerRecord) drawingGroup.getEscherRecord( 0 );
- EscherContainerRecord bstoreContainer;
- if (dggContainer.getChild( 1 ).getRecordId() == EscherContainerRecord.BSTORE_CONTAINER )
- {
- bstoreContainer = (EscherContainerRecord) dggContainer.getChild( 1 );
- }
- else
- {
- bstoreContainer = new EscherContainerRecord();
- bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER );
- List<EscherRecord> childRecords = dggContainer.getChildRecords();
- childRecords.add(1, bstoreContainer);
- dggContainer.setChildRecords(childRecords);
- }
- bstoreContainer.setOptions( (short) ( (escherBSERecords.size() << 4) | 0xF ) );
-
- bstoreContainer.addChildRecord( e );
-
- return escherBSERecords.size();
- }
-
- public DrawingManager2 getDrawingManager()
- {
- return drawingManager;
- }
-
- public WriteProtectRecord getWriteProtect() {
- if (writeProtect == null) {
- writeProtect = new WriteProtectRecord();
- int i = 0;
- for (i = 0;
- i < records.size() && !(records.get(i) instanceof BOFRecord);
- i++) {
- }
- records.add(i+1, writeProtect);
- }
- return this.writeProtect;
- }
-
- public WriteAccessRecord getWriteAccess() {
- if (writeAccess == null) {
- writeAccess = createWriteAccess();
- int i = 0;
- for (i = 0;
- i < records.size() && !(records.get(i) instanceof InterfaceEndRecord);
- i++) {
- }
- records.add(i+1, writeAccess);
- }
- return writeAccess;
- }
-
- public FileSharingRecord getFileSharing() {
- if (fileShare == null) {
- fileShare = new FileSharingRecord();
- int i = 0;
- for (i = 0;
- i < records.size() && !(records.get(i) instanceof WriteAccessRecord);
- i++) {
- }
- records.add(i+1, fileShare);
- }
- return fileShare;
- }
-
- /**
- * is the workbook protected with a password (not encrypted)?
- */
- public boolean isWriteProtected() {
- if (fileShare == null) {
- return false;
- }
- FileSharingRecord frec = getFileSharing();
- return frec.getReadOnly() == 1;
- }
-
- /**
- * protect a workbook with a password (not encypted, just sets writeprotect
- * flags and the password.
- * @param password to set
- */
- public void writeProtectWorkbook( String password, String username ) {
- int protIdx = -1;
- FileSharingRecord frec = getFileSharing();
- WriteAccessRecord waccess = getWriteAccess();
- WriteProtectRecord wprotect = getWriteProtect();
- frec.setReadOnly((short)1);
- frec.setPassword(FileSharingRecord.hashPassword(password));
- frec.setUsername(username);
- waccess.setUsername(username);
- }
-
- /**
- * removes the write protect flag
- */
- public void unwriteProtectWorkbook() {
- records.remove(fileShare);
- records.remove(writeProtect);
- fileShare = null;
- writeProtect = null;
- }
-
- /**
- * @param refIndex Index to REF entry in EXTERNSHEET record in the Link Table
- * @param definedNameIndex zero-based to DEFINEDNAME or EXTERNALNAME record
- * @return the string representation of the defined or external name
- */
- public String resolveNameXText(int refIndex, int definedNameIndex) {
- return linkTable.resolveNameXText(refIndex, definedNameIndex);
- }
-
- /**
- *
- * @param name the name of an external function, typically a name of a UDF
- * @param udf locator of user-defiend functions to resolve names of VBA and Add-In functions
- * @return the external name or null
- */
- public NameXPtg getNameXPtg(String name, UDFFinder udf) {
- LinkTable lnk = getOrCreateLinkTable();
- NameXPtg xptg = lnk.getNameXPtg(name);
-
- if(xptg == null && udf.findFunction(name) != null) {
- // the name was not found in the list of external names
- // check if the Workbook's UDFFinder is aware about it and register the name if it is
- xptg = lnk.addNameXPtg(name);
- }
- return xptg;
- }
-
- /**
- * Check if the cloned sheet has drawings. If yes, then allocate a new drawing group ID and
- * re-generate shape IDs
- *
- * @param sheet the cloned sheet
- */
- public void cloneDrawings(InternalSheet sheet){
-
- findDrawingGroup();
-
- if(drawingManager == null) {
- //this workbook does not have drawings
- return;
- }
-
- //check if the cloned sheet has drawings
- int aggLoc = sheet.aggregateDrawingRecords(drawingManager, false);
- if(aggLoc != -1) {
- EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid);
- EscherContainerRecord escherContainer = agg.getEscherContainer();
- if (escherContainer == null) {
- return;
- }
-
- EscherDggRecord dgg = drawingManager.getDgg();
-
- //register a new drawing group for the cloned sheet
- int dgId = drawingManager.findNewDrawingGroupId();
- dgg.addCluster( dgId, 0 );
- dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1);
-
- EscherDgRecord dg = null;
- for(Iterator<EscherRecord> it = escherContainer.getChildIterator(); it.hasNext();) {
- EscherRecord er = it.next();
- if(er instanceof EscherDgRecord) {
- dg = (EscherDgRecord)er;
- //update id of the drawing in the cloned sheet
- dg.setOptions( (short) ( dgId << 4 ) );
- } else if (er instanceof EscherContainerRecord){
- //recursively find shape records and re-generate shapeId
- List<EscherRecord> spRecords = new ArrayList<EscherRecord>();
- EscherContainerRecord cp = (EscherContainerRecord)er;
- cp.getRecordsById(EscherSpRecord.RECORD_ID, spRecords);
- for(Iterator<EscherRecord> spIt = spRecords.iterator(); spIt.hasNext();) {
- EscherSpRecord sp = (EscherSpRecord)spIt.next();
- int shapeId = drawingManager.allocateShapeId((short)dgId, dg);
- //allocateShapeId increments the number of shapes. roll back to the previous value
- dg.setNumShapes(dg.getNumShapes()-1);
- sp.setShapeId(shapeId);
- }
- }
- }
-
- }
- }
-
- /**
- * Updates named ranges due to moving of cells
- */
- public void updateNamesAfterCellShift(FormulaShifter shifter) {
- for (int i = 0 ; i < getNumNames() ; ++i){
- NameRecord nr = getNameRecord(i);
- Ptg[] ptgs = nr.getNameDefinition();
- if (shifter.adjustFormula(ptgs, nr.getSheetNumber())) {
- nr.setNameDefinition(ptgs);
- }
- }
- }
-
- }
|