1 /* ====================================================================
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 ==================================================================== */
19 package org
.apache
.poi
.hssf
.model
;
21 import org
.apache
.poi
.ddf
.*;
22 import org
.apache
.poi
.hssf
.record
.*;
23 import org
.apache
.poi
.hssf
.util
.HSSFColor
;
24 import org
.apache
.poi
.hssf
.util
.SheetReferences
;
25 import org
.apache
.poi
.util
.POILogFactory
;
26 import org
.apache
.poi
.util
.POILogger
;
28 import java
.util
.ArrayList
;
29 import java
.util
.Iterator
;
30 import java
.util
.List
;
31 import java
.util
.Locale
;
34 * Low level model implementation of a Workbook. Provides creational methods
35 * for settings and objects contained in the workbook object.
37 * This file contains the low level binary records starting at the workbook's BOF and
38 * ending with the workbook's EOF. Use HSSFWorkbook for a high level representation.
40 * The structures of the highlevel API use references to this to perform most of their
41 * operations. Its probably unwise to use these low level structures directly unless you
42 * really know what you're doing. I recommend you read the Microsoft Excel 97 Developer's
43 * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf
44 * before even attempting to use this.
47 * @author Luc Girardin (luc dot girardin at macrofocus dot com)
48 * @author Sergei Kozello (sergeikozello at mail.ru)
49 * @author Shawn Laubach (slaubach at apache dot org) (Data Formats)
50 * @author Andrew C. Oliver (acoliver at apache dot org)
51 * @author Brian Sanders (bsanders at risklabs dot com) - custom palette
52 * @author Dan Sherman (dsherman at isisph.com)
53 * @author Glen Stampoultzis (glens at apache.org)
54 * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
58 public class Workbook
implements Model
60 private static final int DEBUG
= POILogger
.DEBUG
;
62 // public static Workbook currentBook = null;
65 * constant used to set the "codepage" wherever "codepage" is set in records
66 * (which is duplciated in more than one record)
69 private final static short CODEPAGE
= ( short ) 0x4b0;
72 * this contains the Worksheet record objects
74 protected WorkbookRecordList records
= new WorkbookRecordList();
77 * this contains a reference to the SSTRecord so that new stings can be added
80 protected SSTRecord sst
= null;
83 private LinkTable linkTable
; // optionally occurs if there are references in the document. (4.10.3)
86 * holds the "boundsheet" records (aka bundlesheet) so that they can have their
87 * reference to their "BOF" marker
89 protected ArrayList boundsheets
= new ArrayList();
91 protected ArrayList formats
= new ArrayList();
93 protected ArrayList hyperlinks
= new ArrayList();
95 protected int numxfs
= 0; // hold the number of extended format records
96 protected int numfonts
= 0; // hold the number of font records
97 private short maxformatid
= -1; // holds the max format id
98 private boolean uses1904datewindowing
= false; // whether 1904 date windowing is being used
99 private DrawingManager2 drawingManager
;
100 private List escherBSERecords
= new ArrayList(); // EscherBSERecord
101 private WindowOneRecord windowOne
;
102 private FileSharingRecord fileShare
;
103 private WriteAccessRecord writeAccess
;
104 private WriteProtectRecord writeProtect
;
106 private static POILogger log
= POILogFactory
.getLogger(Workbook
.class);
108 protected static final String EXCEL_REPEATING_NAME_PREFIX_
= "Excel_Name_Record_Titles_";
111 * Creates new Workbook with no intitialization --useless right now
112 * @see #createWorkbook(List)
118 * read support for low level
119 * API. Pass in an array of Record objects, A Workbook
120 * object is constructed and passed back with all of its initialization set
121 * to the passed in records and references to those records held. Unlike Sheet
122 * workbook does not use an offset (its assumed to be 0) since its first in a file.
123 * If you need an offset then construct a new array with a 0 offset or write your
126 * @param recs an array of Record objects
127 * @return Workbook object
129 public static Workbook
createWorkbook(List recs
) {
130 if (log
.check( POILogger
.DEBUG
))
131 log
.log(DEBUG
, "Workbook (readfile) created with reclen=",
132 new Integer(recs
.size()));
133 Workbook retval
= new Workbook();
134 ArrayList records
= new ArrayList(recs
.size() / 3);
135 retval
.records
.setRecords(records
);
138 for (k
= 0; k
< recs
.size(); k
++) {
139 Record rec
= ( Record
) recs
.get(k
);
141 if (rec
.getSid() == EOFRecord
.sid
) {
143 if (log
.check( POILogger
.DEBUG
))
144 log
.log(DEBUG
, "found workbook eof record at " + k
);
147 switch (rec
.getSid()) {
149 case BoundSheetRecord
.sid
:
150 if (log
.check( POILogger
.DEBUG
))
151 log
.log(DEBUG
, "found boundsheet record at " + k
);
152 retval
.boundsheets
.add(rec
);
153 retval
.records
.setBspos( k
);
157 if (log
.check( POILogger
.DEBUG
))
158 log
.log(DEBUG
, "found sst record at " + k
);
159 retval
.sst
= ( SSTRecord
) rec
;
162 case FontRecord
.sid
:
163 if (log
.check( POILogger
.DEBUG
))
164 log
.log(DEBUG
, "found font record at " + k
);
165 retval
.records
.setFontpos( k
);
169 case ExtendedFormatRecord
.sid
:
170 if (log
.check( POILogger
.DEBUG
))
171 log
.log(DEBUG
, "found XF record at " + k
);
172 retval
.records
.setXfpos( k
);
176 case TabIdRecord
.sid
:
177 if (log
.check( POILogger
.DEBUG
))
178 log
.log(DEBUG
, "found tabid record at " + k
);
179 retval
.records
.setTabpos( k
);
182 case ProtectRecord
.sid
:
183 if (log
.check( POILogger
.DEBUG
))
184 log
.log(DEBUG
, "found protect record at " + k
);
185 retval
.records
.setProtpos( k
);
188 case BackupRecord
.sid
:
189 if (log
.check( POILogger
.DEBUG
))
190 log
.log(DEBUG
, "found backup record at " + k
);
191 retval
.records
.setBackuppos( k
);
193 case ExternSheetRecord
.sid
:
194 throw new RuntimeException("Extern sheet is part of LinkTable");
195 case NameRecord
.sid
:
196 case SupBookRecord
.sid
:
197 // LinkTable can start with either of these
198 if (log
.check( POILogger
.DEBUG
))
199 log
.log(DEBUG
, "found SupBook record at " + k
);
200 retval
.linkTable
= new LinkTable(recs
, k
, retval
.records
);
201 k
+=retval
.linkTable
.getRecordCount() - 1;
203 case FormatRecord
.sid
:
204 if (log
.check( POILogger
.DEBUG
))
205 log
.log(DEBUG
, "found format record at " + k
);
206 retval
.formats
.add(rec
);
207 retval
.maxformatid
= retval
.maxformatid
>= ((FormatRecord
)rec
).getIndexCode() ? retval
.maxformatid
: ((FormatRecord
)rec
).getIndexCode();
209 case DateWindow1904Record
.sid
:
210 if (log
.check( POILogger
.DEBUG
))
211 log
.log(DEBUG
, "found datewindow1904 record at " + k
);
212 retval
.uses1904datewindowing
= ((DateWindow1904Record
)rec
).getWindowing() == 1;
214 case PaletteRecord
.sid
:
215 if (log
.check( POILogger
.DEBUG
))
216 log
.log(DEBUG
, "found palette record at " + k
);
217 retval
.records
.setPalettepos( k
);
219 case WindowOneRecord
.sid
:
220 if (log
.check( POILogger
.DEBUG
))
221 log
.log(DEBUG
, "found WindowOneRecord at " + k
);
222 retval
.windowOne
= (WindowOneRecord
) rec
;
224 case WriteAccessRecord
.sid
:
225 if (log
.check( POILogger
.DEBUG
))
226 log
.log(DEBUG
, "found WriteAccess at " + k
);
227 retval
.writeAccess
= (WriteAccessRecord
) rec
;
229 case WriteProtectRecord
.sid
:
230 if (log
.check( POILogger
.DEBUG
))
231 log
.log(DEBUG
, "found WriteProtect at " + k
);
232 retval
.writeProtect
= (WriteProtectRecord
) rec
;
234 case FileSharingRecord
.sid
:
235 if (log
.check( POILogger
.DEBUG
))
236 log
.log(DEBUG
, "found FileSharing at " + k
);
237 retval
.fileShare
= (FileSharingRecord
) rec
;
242 //What if we dont have any ranges and supbooks
243 // if (retval.records.supbookpos == 0) {
244 // retval.records.supbookpos = retval.records.bspos + 1;
245 // retval.records.namepos = retval.records.supbookpos + 1;
248 // Look for other interesting values that
249 // follow the EOFRecord
250 for ( ; k
< recs
.size(); k
++) {
251 Record rec
= ( Record
) recs
.get(k
);
252 switch (rec
.getSid()) {
253 case HyperlinkRecord
.sid
:
254 retval
.hyperlinks
.add(rec
);
259 if (retval
.windowOne
== null) {
260 retval
.windowOne
= (WindowOneRecord
) retval
.createWindowOne();
262 if (log
.check( POILogger
.DEBUG
))
263 log
.log(DEBUG
, "exit create workbook from existing file function");
268 * Creates an empty workbook object with three blank sheets and all the empty
269 * fields. Use this to create a workbook from scratch.
271 public static Workbook
createWorkbook()
273 if (log
.check( POILogger
.DEBUG
))
274 log
.log( DEBUG
, "creating new workbook from scratch" );
275 Workbook retval
= new Workbook();
276 ArrayList records
= new ArrayList( 30 );
277 retval
.records
.setRecords(records
);
278 ArrayList formats
= new ArrayList( 8 );
280 records
.add( retval
.createBOF() );
281 records
.add( retval
.createInterfaceHdr() );
282 records
.add( retval
.createMMS() );
283 records
.add( retval
.createInterfaceEnd() );
284 records
.add( retval
.createWriteAccess() );
285 records
.add( retval
.createCodepage() );
286 records
.add( retval
.createDSF() );
287 records
.add( retval
.createTabId() );
288 retval
.records
.setTabpos( records
.size() - 1 );
289 records
.add( retval
.createFnGroupCount() );
290 records
.add( retval
.createWindowProtect() );
291 records
.add( retval
.createProtect() );
292 retval
.records
.setProtpos( records
.size() - 1 );
293 records
.add( retval
.createPassword() );
294 records
.add( retval
.createProtectionRev4() );
295 records
.add( retval
.createPasswordRev4() );
296 retval
.windowOne
= (WindowOneRecord
) retval
.createWindowOne();
297 records
.add( retval
.windowOne
);
298 records
.add( retval
.createBackup() );
299 retval
.records
.setBackuppos( records
.size() - 1 );
300 records
.add( retval
.createHideObj() );
301 records
.add( retval
.createDateWindow1904() );
302 records
.add( retval
.createPrecision() );
303 records
.add( retval
.createRefreshAll() );
304 records
.add( retval
.createBookBool() );
305 records
.add( retval
.createFont() );
306 records
.add( retval
.createFont() );
307 records
.add( retval
.createFont() );
308 records
.add( retval
.createFont() );
309 retval
.records
.setFontpos( records
.size() - 1 ); // last font record postion
312 // set up format records
313 for ( int i
= 0; i
<= 7; i
++ )
316 rec
= retval
.createFormat( i
);
317 retval
.maxformatid
= retval
.maxformatid
>= ( (FormatRecord
) rec
).getIndexCode() ? retval
.maxformatid
: ( (FormatRecord
) rec
).getIndexCode();
321 retval
.formats
= formats
;
323 for ( int k
= 0; k
< 21; k
++ )
325 records
.add( retval
.createExtendedFormat( k
) );
328 retval
.records
.setXfpos( records
.size() - 1 );
329 for ( int k
= 0; k
< 6; k
++ )
331 records
.add( retval
.createStyle( k
) );
333 records
.add( retval
.createUseSelFS() );
335 int nBoundSheets
= 1; // now just do 1
336 for ( int k
= 0; k
< nBoundSheets
; k
++ ) {
337 BoundSheetRecord bsr
=
338 (BoundSheetRecord
) retval
.createBoundSheet( k
);
341 retval
.boundsheets
.add( bsr
);
342 retval
.records
.setBspos( records
.size() - 1 );
344 // retval.records.supbookpos = retval.records.bspos + 1;
345 // retval.records.namepos = retval.records.supbookpos + 2;
346 records
.add( retval
.createCountry() );
347 for ( int k
= 0; k
< nBoundSheets
; k
++ ) {
348 retval
.getOrCreateLinkTable().checkExternSheet(k
);
350 retval
.sst
= (SSTRecord
) retval
.createSST();
351 records
.add( retval
.sst
);
352 records
.add( retval
.createExtendedSST() );
354 records
.add( retval
.createEOF() );
355 if (log
.check( POILogger
.DEBUG
))
356 log
.log( DEBUG
, "exit create new workbook from scratch" );
361 /**Retrieves the Builtin NameRecord that matches the name and index
362 * There shouldn't be too many names to make the sequential search too slow
363 * @param name byte representation of the builtin name to match
364 * @param sheetIndex Index to match
365 * @return null if no builtin NameRecord matches
367 public NameRecord
getSpecificBuiltinRecord(byte name
, int sheetIndex
)
369 return getOrCreateLinkTable().getSpecificBuiltinRecord(name
, sheetIndex
);
373 * Removes the specified Builtin NameRecord that matches the name and index
374 * @param name byte representation of the builtin to match
375 * @param sheetIndex zero-based sheet reference
377 public void removeBuiltinRecord(byte name
, int sheetIndex
) {
378 linkTable
.removeBuiltinRecord(name
, sheetIndex
);
379 // TODO - do we need "this.records.remove(...);" similar to that in this.removeName(int namenum) {}?
382 public int getNumRecords() {
383 return records
.size();
387 * gets the font record at the given index in the font table. Remember
388 * "There is No Four" (someone at M$ must have gone to Rocky Horror one too
391 * @param idx the index to look at (0 or greater but NOT 4)
392 * @return FontRecord located at the given index
395 public FontRecord
getFontRecordAt(int idx
) {
399 index
-= 1; // adjust for "There is no 4"
401 if (index
> (numfonts
- 1)) {
402 throw new ArrayIndexOutOfBoundsException(
403 "There are only " + numfonts
404 + " font records, you asked for " + idx
);
407 ( FontRecord
) records
.get((records
.getFontpos() - (numfonts
- 1)) + index
);
413 * creates a new font record and adds it to the "font table". This causes the
414 * boundsheets to move down one, extended formats to move down (so this function moves
415 * those pointers as well)
417 * @return FontRecord that was just created
420 public FontRecord
createNewFont() {
421 FontRecord rec
= ( FontRecord
) createFont();
423 records
.add(records
.getFontpos()+1, rec
);
424 records
.setFontpos( records
.getFontpos() + 1 );
430 * gets the number of font records
432 * @return number of font records in the "font table"
435 public int getNumberOfFontRecords() {
440 * Sets the BOF for a given sheet
442 * @param sheetnum the number of the sheet to set the positing of the bof for
443 * @param pos the actual bof position
446 public void setSheetBof(int sheetnum
, int pos
) {
447 if (log
.check( POILogger
.DEBUG
))
448 log
.log(DEBUG
, "setting bof for sheetnum =", new Integer(sheetnum
),
449 " at pos=", new Integer(pos
));
450 checkSheets(sheetnum
);
451 (( BoundSheetRecord
) boundsheets
.get(sheetnum
))
452 .setPositionOfBof(pos
);
456 * Returns the position of the backup record.
459 public BackupRecord
getBackupRecord() {
460 return ( BackupRecord
) records
.get(records
.getBackuppos());
465 * sets the name for a given sheet. If the boundsheet record doesn't exist and
466 * its only one more than we have, go ahead and create it. If its > 1 more than
469 * @param sheetnum the sheet number (0 based)
470 * @param sheetname the name for the sheet
472 public void setSheetName(int sheetnum
, String sheetname
) {
473 checkSheets(sheetnum
);
474 BoundSheetRecord sheet
= (BoundSheetRecord
)boundsheets
.get( sheetnum
);
475 sheet
.setSheetname(sheetname
);
476 sheet
.setSheetnameLength( (byte)sheetname
.length() );
480 * Determines whether a workbook contains the provided sheet name.
482 * @param name the name to test (case insensitive match)
483 * @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check.
484 * @return true if the sheet contains the name, false otherwise.
486 public boolean doesContainsSheetName( String name
, int excludeSheetIdx
)
488 for ( int i
= 0; i
< boundsheets
.size(); i
++ )
490 BoundSheetRecord boundSheetRecord
= (BoundSheetRecord
) boundsheets
.get( i
);
491 if (excludeSheetIdx
!= i
&& name
.equalsIgnoreCase(boundSheetRecord
.getSheetname()))
498 * sets the name for a given sheet forcing the encoding. This is STILL A BAD IDEA.
499 * Poi now automatically detects unicode
501 *@deprecated 3-Jan-06 Simply use setSheetNam e(int sheetnum, String sheetname)
502 * @param sheetnum the sheet number (0 based)
503 * @param sheetname the name for the sheet
505 public void setSheetName(int sheetnum
, String sheetname
, short encoding
) {
506 checkSheets(sheetnum
);
507 BoundSheetRecord sheet
= (BoundSheetRecord
)boundsheets
.get( sheetnum
);
508 sheet
.setSheetname(sheetname
);
509 sheet
.setSheetnameLength( (byte)sheetname
.length() );
510 sheet
.setCompressedUnicodeFlag( (byte)encoding
);
514 * sets the order of appearance for a given sheet.
516 * @param sheetname the name of the sheet to reorder
517 * @param pos the position that we want to insert the sheet into (0 based)
520 public void setSheetOrder(String sheetname
, int pos
) {
521 int sheetNumber
= getSheetIndex(sheetname
);
522 //remove the sheet that needs to be reordered and place it in the spot we want
523 boundsheets
.add(pos
, boundsheets
.remove(sheetNumber
));
527 * gets the name for a given sheet.
529 * @param sheetnum the sheet number (0 based)
530 * @return sheetname the name for the sheet
533 public String
getSheetName(int sheetnum
) {
534 return (( BoundSheetRecord
) boundsheets
.get(sheetnum
))
539 * gets the hidden flag for a given sheet.
541 * @param sheetnum the sheet number (0 based)
542 * @return True if sheet is hidden
545 public boolean isSheetHidden(int sheetnum
) {
546 BoundSheetRecord bsr
= ( BoundSheetRecord
) boundsheets
.get(sheetnum
);
547 return bsr
.isHidden();
551 * Hide or unhide a sheet
553 * @param sheetnum The sheet number
554 * @param hidden True to mark the sheet as hidden, false otherwise
557 public void setSheetHidden(int sheetnum
, boolean hidden
) {
558 BoundSheetRecord bsr
= ( BoundSheetRecord
) boundsheets
.get(sheetnum
);
559 bsr
.setHidden(hidden
);
562 * get the sheet's index
563 * @param name sheet name
564 * @return sheet index or -1 if it was not found.
567 public int getSheetIndex(String name
) {
570 for (int k
= 0; k
< boundsheets
.size(); k
++) {
571 String sheet
= getSheetName(k
);
573 if (sheet
.equalsIgnoreCase(name
)) {
582 * if we're trying to address one more sheet than we have, go ahead and add it! if we're
583 * trying to address >1 more than we have throw an exception!
586 private void checkSheets(int sheetnum
) {
587 if ((boundsheets
.size()) <= sheetnum
) { // if we're short one add another..
588 if ((boundsheets
.size() + 1) <= sheetnum
) {
589 throw new RuntimeException("Sheet number out of bounds!");
591 BoundSheetRecord bsr
= (BoundSheetRecord
) createBoundSheet(sheetnum
);
593 records
.add(records
.getBspos()+1, bsr
);
594 records
.setBspos( records
.getBspos() + 1 );
595 boundsheets
.add(bsr
);
596 getOrCreateLinkTable().checkExternSheet(sheetnum
);
601 public void removeSheet(int sheetnum
) {
602 if (boundsheets
.size() > sheetnum
) {
603 records
.remove(records
.getBspos() - (boundsheets
.size() - 1) + sheetnum
);
605 boundsheets
.remove(sheetnum
);
609 // Within NameRecords, it's ok to have the formula
610 // part point at deleted sheets. It's also ok to
611 // have the ExternSheetNumber point at deleted
613 // However, the sheet index must be adjusted, or
614 // excel will break. (Sheet index is either 0 for
615 // global, or 1 based index to sheet)
616 int sheetNum1Based
= sheetnum
+ 1;
617 for(int i
=0; i
<getNumNames(); i
++) {
618 NameRecord nr
= getNameRecord(i
);
620 if(nr
.getIndexToSheet() == sheetNum1Based
) {
621 // Excel re-writes these to point to no sheet
622 nr
.setEqualsToIndexToSheet((short)0);
623 } else if(nr
.getIndexToSheet() > sheetNum1Based
) {
624 // Bump down by one, so still points
626 nr
.setEqualsToIndexToSheet((short)(
627 nr
.getEqualsToIndexToSheet()-1
634 * make the tabid record look like the current situation.
637 private void fixTabIdRecord() {
638 TabIdRecord tir
= ( TabIdRecord
) records
.get(records
.getTabpos());
639 short[] tia
= new short[ boundsheets
.size() ];
641 for (short k
= 0; k
< tia
.length
; k
++) {
644 tir
.setTabIdArray(tia
);
648 * returns the number of boundsheet objects contained in this workbook.
650 * @return number of BoundSheet records
653 public int getNumSheets() {
654 if (log
.check( POILogger
.DEBUG
))
655 log
.log(DEBUG
, "getNumSheets=", new Integer(boundsheets
.size()));
656 return boundsheets
.size();
660 * get the number of ExtendedFormat records contained in this workbook.
662 * @return int count of ExtendedFormat records
665 public int getNumExFormats() {
666 if (log
.check( POILogger
.DEBUG
))
667 log
.log(DEBUG
, "getXF=", new Integer(numxfs
));
672 * gets the ExtendedFormatRecord at the given 0-based index
674 * @param index of the Extended format record (0-based)
675 * @return ExtendedFormatRecord at the given index
678 public ExtendedFormatRecord
getExFormatAt(int index
) {
679 int xfptr
= records
.getXfpos() - (numxfs
- 1);
682 ExtendedFormatRecord retval
=
683 ( ExtendedFormatRecord
) records
.get(xfptr
);
689 * creates a new Cell-type Extneded Format Record and adds it to the end of
690 * ExtendedFormatRecords collection
692 * @return ExtendedFormatRecord that was created
695 public ExtendedFormatRecord
createCellXF() {
696 ExtendedFormatRecord xf
= createExtendedFormat();
698 records
.add(records
.getXfpos()+1, xf
);
699 records
.setXfpos( records
.getXfpos() + 1 );
705 * Adds a string to the SST table and returns its index (if its a duplicate
706 * just returns its index and update the counts) ASSUMES compressed unicode
709 * @param string the string to be added to the SSTRecord
711 * @return index of the string within the SSTRecord
714 public int addSSTString(UnicodeString string
) {
715 if (log
.check( POILogger
.DEBUG
))
716 log
.log(DEBUG
, "insert to sst string='", string
);
720 return sst
.addString(string
);
724 * given an index into the SST table, this function returns the corresponding String value
725 * @return String containing the SST String
728 public UnicodeString
getSSTString(int str
) {
732 UnicodeString retval
= sst
.getString(str
);
734 if (log
.check( POILogger
.DEBUG
))
735 log
.log(DEBUG
, "Returning SST for index=", new Integer(str
),
736 " String= ", retval
);
741 * use this function to add a Shared String Table to an existing sheet (say
742 * generated by a different java api) without an sst....
744 * @see org.apache.poi.hssf.record.SSTRecord
747 public void insertSST() {
748 if (log
.check( POILogger
.DEBUG
))
749 log
.log(DEBUG
, "creating new SST via insertSST!");
750 sst
= ( SSTRecord
) createSST();
751 records
.add(records
.size() - 1, createExtendedSST());
752 records
.add(records
.size() - 2, sst
);
756 * Serializes all records int the worksheet section into a big byte array. Use
757 * this to write the Workbook out.
759 * @return byte array containing the HSSF-only portions of the POIFS file.
761 // GJS: Not used so why keep it.
762 // public byte [] serialize() {
763 // log.log(DEBUG, "Serializing Workbook!");
764 // byte[] retval = null;
766 //// ArrayList bytes = new ArrayList(records.size());
767 // int arraysize = getSize();
770 // retval = new byte[ arraysize ];
771 // for (int k = 0; k < records.size(); k++) {
773 // Record record = records.get(k);
774 //// Let's skip RECALCID records, as they are only use for optimization
775 // if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) {
776 // pos += record.serialize(pos, retval); // rec.length;
779 // log.log(DEBUG, "Exiting serialize workbook");
784 * Serializes all records int the worksheet section into a big byte array. Use
785 * this to write the Workbook out.
786 * @param offset of the data to be written
787 * @param data array of bytes to write this to
790 public int serialize( int offset
, byte[] data
)
792 if (log
.check( POILogger
.DEBUG
))
793 log
.log( DEBUG
, "Serializing Workbook with offsets" );
797 SSTRecord sst
= null;
799 boolean wroteBoundSheets
= false;
800 for ( int k
= 0; k
< records
.size(); k
++ )
803 Record record
= records
.get( k
);
804 // Let's skip RECALCID records, as they are only use for optimization
805 if ( record
.getSid() != RecalcIdRecord
.sid
|| ( (RecalcIdRecord
) record
).isNeeded() )
808 if (record
instanceof SSTRecord
)
810 sst
= (SSTRecord
)record
;
813 if (record
.getSid() == ExtSSTRecord
.sid
&& sst
!= null)
815 record
= sst
.createExtSSTRecord(sstPos
+ offset
);
817 if (record
instanceof BoundSheetRecord
) {
818 if(!wroteBoundSheets
) {
819 for (int i
= 0; i
< boundsheets
.size(); i
++) {
820 len
+= ((BoundSheetRecord
)boundsheets
.get(i
))
821 .serialize(pos
+offset
+len
, data
);
823 wroteBoundSheets
= true;
826 len
= record
.serialize( pos
+ offset
, data
);
828 ///// DEBUG BEGIN /////
829 // if (len != record.getRecordSize())
830 // throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize());
831 ///// DEBUG END /////
832 pos
+= len
; // rec.length;
835 if (log
.check( POILogger
.DEBUG
))
836 log
.log( DEBUG
, "Exiting serialize workbook" );
844 SSTRecord sst
= null;
845 for ( int k
= 0; k
< records
.size(); k
++ )
847 Record record
= records
.get( k
);
848 // Let's skip RECALCID records, as they are only use for optimization
849 if ( record
.getSid() != RecalcIdRecord
.sid
|| ( (RecalcIdRecord
) record
).isNeeded() )
851 if (record
instanceof SSTRecord
)
852 sst
= (SSTRecord
)record
;
853 if (record
.getSid() == ExtSSTRecord
.sid
&& sst
!= null)
854 retval
+= sst
.calcExtSSTRecordSize();
856 retval
+= record
.getRecordSize();
863 * creates the BOF record
864 * @see org.apache.poi.hssf.record.BOFRecord
865 * @see org.apache.poi.hssf.record.Record
866 * @return record containing a BOFRecord
869 protected Record
createBOF() {
870 BOFRecord retval
= new BOFRecord();
872 retval
.setVersion(( short ) 0x600);
873 retval
.setType(( short ) 5);
874 retval
.setBuild(( short ) 0x10d3);
876 // retval.setBuild((short)0x0dbb);
877 retval
.setBuildYear(( short ) 1996);
878 retval
.setHistoryBitMask(0x41); // was c1 before verify
879 retval
.setRequiredVersion(0x6);
884 * creates the InterfaceHdr record
885 * @see org.apache.poi.hssf.record.InterfaceHdrRecord
886 * @see org.apache.poi.hssf.record.Record
887 * @return record containing a InterfaceHdrRecord
890 protected Record
createInterfaceHdr() {
891 InterfaceHdrRecord retval
= new InterfaceHdrRecord();
893 retval
.setCodepage(CODEPAGE
);
898 * creates an MMS record
899 * @see org.apache.poi.hssf.record.MMSRecord
900 * @see org.apache.poi.hssf.record.Record
901 * @return record containing a MMSRecord
904 protected Record
createMMS() {
905 MMSRecord retval
= new MMSRecord();
907 retval
.setAddMenuCount(( byte ) 0);
908 retval
.setDelMenuCount(( byte ) 0);
913 * creates the InterfaceEnd record
914 * @see org.apache.poi.hssf.record.InterfaceEndRecord
915 * @see org.apache.poi.hssf.record.Record
916 * @return record containing a InterfaceEndRecord
919 protected Record
createInterfaceEnd() {
920 return new InterfaceEndRecord();
924 * creates the WriteAccess record containing the logged in user's name
925 * @see org.apache.poi.hssf.record.WriteAccessRecord
926 * @see org.apache.poi.hssf.record.Record
927 * @return record containing a WriteAccessRecord
930 protected Record
createWriteAccess() {
931 WriteAccessRecord retval
= new WriteAccessRecord();
935 retval
.setUsername(System
.getProperty("user.name"));
937 catch (java
.security
.AccessControlException e
)
939 // AccessControlException can occur in a restricted context
940 // (client applet/jws application or restricted security server)
941 retval
.setUsername("POI");
947 * creates the Codepage record containing the constant stored in CODEPAGE
948 * @see org.apache.poi.hssf.record.CodepageRecord
949 * @see org.apache.poi.hssf.record.Record
950 * @return record containing a CodepageRecord
953 protected Record
createCodepage() {
954 CodepageRecord retval
= new CodepageRecord();
956 retval
.setCodepage(CODEPAGE
);
961 * creates the DSF record containing a 0 since HSSF can't even create Dual Stream Files
962 * @see org.apache.poi.hssf.record.DSFRecord
963 * @see org.apache.poi.hssf.record.Record
964 * @return record containing a DSFRecord
967 protected Record
createDSF() {
968 DSFRecord retval
= new DSFRecord();
971 ( short ) 0); // we don't even support double stream files
976 * creates the TabId record containing an array of 0,1,2. This release of HSSF
977 * always has the default three sheets, no less, no more.
978 * @see org.apache.poi.hssf.record.TabIdRecord
979 * @see org.apache.poi.hssf.record.Record
980 * @return record containing a TabIdRecord
983 protected Record
createTabId() {
984 TabIdRecord retval
= new TabIdRecord();
985 short[] tabidarray
= {
989 retval
.setTabIdArray(tabidarray
);
994 * creates the FnGroupCount record containing the Magic number constant of 14.
995 * @see org.apache.poi.hssf.record.FnGroupCountRecord
996 * @see org.apache.poi.hssf.record.Record
997 * @return record containing a FnGroupCountRecord
1000 protected Record
createFnGroupCount() {
1001 FnGroupCountRecord retval
= new FnGroupCountRecord();
1003 retval
.setCount(( short ) 14);
1008 * creates the WindowProtect record with protect set to false.
1009 * @see org.apache.poi.hssf.record.WindowProtectRecord
1010 * @see org.apache.poi.hssf.record.Record
1011 * @return record containing a WindowProtectRecord
1014 protected Record
createWindowProtect() {
1015 WindowProtectRecord retval
= new WindowProtectRecord();
1018 false); // by default even when we support it we won't
1019 return retval
; // want it to be protected
1023 * creates the Protect record with protect set to false.
1024 * @see org.apache.poi.hssf.record.ProtectRecord
1025 * @see org.apache.poi.hssf.record.Record
1026 * @return record containing a ProtectRecord
1029 protected Record
createProtect() {
1030 ProtectRecord retval
= new ProtectRecord();
1033 false); // by default even when we support it we won't
1034 return retval
; // want it to be protected
1038 * creates the Password record with password set to 0.
1039 * @see org.apache.poi.hssf.record.PasswordRecord
1040 * @see org.apache.poi.hssf.record.Record
1041 * @return record containing a PasswordRecord
1044 protected Record
createPassword() {
1045 PasswordRecord retval
= new PasswordRecord();
1047 retval
.setPassword(( short ) 0); // no password by default!
1052 * creates the ProtectionRev4 record with protect set to false.
1053 * @see org.apache.poi.hssf.record.ProtectionRev4Record
1054 * @see org.apache.poi.hssf.record.Record
1055 * @return record containing a ProtectionRev4Record
1058 protected Record
createProtectionRev4() {
1059 ProtectionRev4Record retval
= new ProtectionRev4Record();
1061 retval
.setProtect(false);
1066 * creates the PasswordRev4 record with password set to 0.
1067 * @see org.apache.poi.hssf.record.PasswordRev4Record
1068 * @see org.apache.poi.hssf.record.Record
1069 * @return record containing a PasswordRev4Record
1072 protected Record
createPasswordRev4() {
1073 PasswordRev4Record retval
= new PasswordRev4Record();
1075 retval
.setPassword(( short ) 0); // no password by default!
1080 * creates the WindowOne record with the following magic values: <P>
1081 * horizontal hold - 0x168 <P>
1082 * vertical hold - 0x10e <P>
1083 * width - 0x3a5c <P>
1084 * height - 0x23be <P>
1085 * options - 0x38 <P>
1086 * selected tab - 0 <P>
1087 * displayed tab - 0 <P>
1088 * num selected tab- 0 <P>
1089 * tab width ratio - 0x258 <P>
1090 * @see org.apache.poi.hssf.record.WindowOneRecord
1091 * @see org.apache.poi.hssf.record.Record
1092 * @return record containing a WindowOneRecord
1095 protected Record
createWindowOne() {
1096 WindowOneRecord retval
= new WindowOneRecord();
1098 retval
.setHorizontalHold(( short ) 0x168);
1099 retval
.setVerticalHold(( short ) 0x10e);
1100 retval
.setWidth(( short ) 0x3a5c);
1101 retval
.setHeight(( short ) 0x23be);
1102 retval
.setOptions(( short ) 0x38);
1103 retval
.setSelectedTab(( short ) 0x0);
1104 retval
.setDisplayedTab(( short ) 0x0);
1105 retval
.setNumSelectedTabs(( short ) 1);
1106 retval
.setTabWidthRatio(( short ) 0x258);
1111 * creates the Backup record with backup set to 0. (loose the data, who cares)
1112 * @see org.apache.poi.hssf.record.BackupRecord
1113 * @see org.apache.poi.hssf.record.Record
1114 * @return record containing a BackupRecord
1117 protected Record
createBackup() {
1118 BackupRecord retval
= new BackupRecord();
1121 ( short ) 0); // by default DONT save backups of files...just loose data
1126 * creates the HideObj record with hide object set to 0. (don't hide)
1127 * @see org.apache.poi.hssf.record.HideObjRecord
1128 * @see org.apache.poi.hssf.record.Record
1129 * @return record containing a HideObjRecord
1132 protected Record
createHideObj() {
1133 HideObjRecord retval
= new HideObjRecord();
1135 retval
.setHideObj(( short ) 0); // by default set hide object off
1140 * creates the DateWindow1904 record with windowing set to 0. (don't window)
1141 * @see org.apache.poi.hssf.record.DateWindow1904Record
1142 * @see org.apache.poi.hssf.record.Record
1143 * @return record containing a DateWindow1904Record
1146 protected Record
createDateWindow1904() {
1147 DateWindow1904Record retval
= new DateWindow1904Record();
1149 retval
.setWindowing(
1150 ( short ) 0); // don't EVER use 1904 date windowing...tick tock..
1155 * creates the Precision record with precision set to true. (full precision)
1156 * @see org.apache.poi.hssf.record.PrecisionRecord
1157 * @see org.apache.poi.hssf.record.Record
1158 * @return record containing a PrecisionRecord
1161 protected Record
createPrecision() {
1162 PrecisionRecord retval
= new PrecisionRecord();
1164 retval
.setFullPrecision(
1165 true); // always use real numbers in calculations!
1170 * creates the RefreshAll record with refreshAll set to true. (refresh all calcs)
1171 * @see org.apache.poi.hssf.record.RefreshAllRecord
1172 * @see org.apache.poi.hssf.record.Record
1173 * @return record containing a RefreshAllRecord
1176 protected Record
createRefreshAll() {
1177 RefreshAllRecord retval
= new RefreshAllRecord();
1179 retval
.setRefreshAll(false);
1184 * creates the BookBool record with saveLinkValues set to 0. (don't save link values)
1185 * @see org.apache.poi.hssf.record.BookBoolRecord
1186 * @see org.apache.poi.hssf.record.Record
1187 * @return record containing a BookBoolRecord
1190 protected Record
createBookBool() {
1191 BookBoolRecord retval
= new BookBoolRecord();
1193 retval
.setSaveLinkValues(( short ) 0);
1198 * creates a Font record with the following magic values: <P>
1199 * fontheight = 0xc8<P>
1200 * attributes = 0x0<P>
1201 * color palette index = 0x7fff<P>
1202 * bold weight = 0x190<P>
1203 * Font Name Length = 5 <P>
1204 * Font Name = Arial <P>
1206 * @see org.apache.poi.hssf.record.FontRecord
1207 * @see org.apache.poi.hssf.record.Record
1208 * @return record containing a FontRecord
1211 protected Record
createFont() {
1212 FontRecord retval
= new FontRecord();
1214 retval
.setFontHeight(( short ) 0xc8);
1215 retval
.setAttributes(( short ) 0x0);
1216 retval
.setColorPaletteIndex(( short ) 0x7fff);
1217 retval
.setBoldWeight(( short ) 0x190);
1218 retval
.setFontNameLength(( byte ) 5);
1219 retval
.setFontName("Arial");
1224 * Creates a FormatRecord object
1225 * @param id the number of the format record to create (meaning its position in
1226 * a file as M$ Excel would create it.)
1227 * @return record containing a FormatRecord
1228 * @see org.apache.poi.hssf.record.FormatRecord
1229 * @see org.apache.poi.hssf.record.Record
1232 protected Record
createFormat(int id
) { // we'll need multiple editions for
1233 FormatRecord retval
= new FormatRecord(); // the differnt formats
1238 retval
.setIndexCode(( short ) 5);
1239 retval
.setFormatStringLength(( byte ) 0x17);
1240 retval
.setFormatString("\"$\"#,##0_);\\(\"$\"#,##0\\)");
1244 retval
.setIndexCode(( short ) 6);
1245 retval
.setFormatStringLength(( byte ) 0x1c);
1246 retval
.setFormatString("\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)");
1250 retval
.setIndexCode(( short ) 7);
1251 retval
.setFormatStringLength(( byte ) 0x1d);
1252 retval
.setFormatString("\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)");
1256 retval
.setIndexCode(( short ) 8);
1257 retval
.setFormatStringLength(( byte ) 0x22);
1258 retval
.setFormatString(
1259 "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)");
1263 retval
.setIndexCode(( short ) 0x2a);
1264 retval
.setFormatStringLength(( byte ) 0x32);
1265 retval
.setFormatString(
1266 "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)");
1270 retval
.setIndexCode(( short ) 0x29);
1271 retval
.setFormatStringLength(( byte ) 0x29);
1272 retval
.setFormatString(
1273 "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)");
1277 retval
.setIndexCode(( short ) 0x2c);
1278 retval
.setFormatStringLength(( byte ) 0x3a);
1279 retval
.setFormatString(
1280 "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)");
1284 retval
.setIndexCode(( short ) 0x2b);
1285 retval
.setFormatStringLength(( byte ) 0x31);
1286 retval
.setFormatString(
1287 "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)");
1294 * Creates an ExtendedFormatRecord object
1295 * @param id the number of the extended format record to create (meaning its position in
1296 * a file as MS Excel would create it.)
1298 * @return record containing an ExtendedFormatRecord
1299 * @see org.apache.poi.hssf.record.ExtendedFormatRecord
1300 * @see org.apache.poi.hssf.record.Record
1303 protected Record
createExtendedFormat(int id
) { // we'll need multiple editions
1304 ExtendedFormatRecord retval
= new ExtendedFormatRecord();
1309 retval
.setFontIndex(( short ) 0);
1310 retval
.setFormatIndex(( short ) 0);
1311 retval
.setCellOptions(( short ) 0xfffffff5);
1312 retval
.setAlignmentOptions(( short ) 0x20);
1313 retval
.setIndentionOptions(( short ) 0);
1314 retval
.setBorderOptions(( short ) 0);
1315 retval
.setPaletteOptions(( short ) 0);
1316 retval
.setAdtlPaletteOptions(( short ) 0);
1317 retval
.setFillPaletteOptions(( short ) 0x20c0);
1321 retval
.setFontIndex(( short ) 1);
1322 retval
.setFormatIndex(( short ) 0);
1323 retval
.setCellOptions(( short ) 0xfffffff5);
1324 retval
.setAlignmentOptions(( short ) 0x20);
1325 retval
.setIndentionOptions(( short ) 0xfffff400);
1326 retval
.setBorderOptions(( short ) 0);
1327 retval
.setPaletteOptions(( short ) 0);
1328 retval
.setAdtlPaletteOptions(( short ) 0);
1329 retval
.setFillPaletteOptions(( short ) 0x20c0);
1333 retval
.setFontIndex(( short ) 1);
1334 retval
.setFormatIndex(( short ) 0);
1335 retval
.setCellOptions(( short ) 0xfffffff5);
1336 retval
.setAlignmentOptions(( short ) 0x20);
1337 retval
.setIndentionOptions(( short ) 0xfffff400);
1338 retval
.setBorderOptions(( short ) 0);
1339 retval
.setPaletteOptions(( short ) 0);
1340 retval
.setAdtlPaletteOptions(( short ) 0);
1341 retval
.setFillPaletteOptions(( short ) 0x20c0);
1345 retval
.setFontIndex(( short ) 2);
1346 retval
.setFormatIndex(( short ) 0);
1347 retval
.setCellOptions(( short ) 0xfffffff5);
1348 retval
.setAlignmentOptions(( short ) 0x20);
1349 retval
.setIndentionOptions(( short ) 0xfffff400);
1350 retval
.setBorderOptions(( short ) 0);
1351 retval
.setPaletteOptions(( short ) 0);
1352 retval
.setAdtlPaletteOptions(( short ) 0);
1353 retval
.setFillPaletteOptions(( short ) 0x20c0);
1357 retval
.setFontIndex(( short ) 2);
1358 retval
.setFormatIndex(( short ) 0);
1359 retval
.setCellOptions(( short ) 0xfffffff5);
1360 retval
.setAlignmentOptions(( short ) 0x20);
1361 retval
.setIndentionOptions(( short ) 0xfffff400);
1362 retval
.setBorderOptions(( short ) 0);
1363 retval
.setPaletteOptions(( short ) 0);
1364 retval
.setAdtlPaletteOptions(( short ) 0);
1365 retval
.setFillPaletteOptions(( short ) 0x20c0);
1369 retval
.setFontIndex(( short ) 0);
1370 retval
.setFormatIndex(( short ) 0);
1371 retval
.setCellOptions(( short ) 0xfffffff5);
1372 retval
.setAlignmentOptions(( short ) 0x20);
1373 retval
.setIndentionOptions(( short ) 0xfffff400);
1374 retval
.setBorderOptions(( short ) 0);
1375 retval
.setPaletteOptions(( short ) 0);
1376 retval
.setAdtlPaletteOptions(( short ) 0);
1377 retval
.setFillPaletteOptions(( short ) 0x20c0);
1381 retval
.setFontIndex(( short ) 0);
1382 retval
.setFormatIndex(( short ) 0);
1383 retval
.setCellOptions(( short ) 0xfffffff5);
1384 retval
.setAlignmentOptions(( short ) 0x20);
1385 retval
.setIndentionOptions(( short ) 0xfffff400);
1386 retval
.setBorderOptions(( short ) 0);
1387 retval
.setPaletteOptions(( short ) 0);
1388 retval
.setAdtlPaletteOptions(( short ) 0);
1389 retval
.setFillPaletteOptions(( short ) 0x20c0);
1393 retval
.setFontIndex(( short ) 0);
1394 retval
.setFormatIndex(( short ) 0);
1395 retval
.setCellOptions(( short ) 0xfffffff5);
1396 retval
.setAlignmentOptions(( short ) 0x20);
1397 retval
.setIndentionOptions(( short ) 0xfffff400);
1398 retval
.setBorderOptions(( short ) 0);
1399 retval
.setPaletteOptions(( short ) 0);
1400 retval
.setAdtlPaletteOptions(( short ) 0);
1401 retval
.setFillPaletteOptions(( short ) 0x20c0);
1405 retval
.setFontIndex(( short ) 0);
1406 retval
.setFormatIndex(( short ) 0);
1407 retval
.setCellOptions(( short ) 0xfffffff5);
1408 retval
.setAlignmentOptions(( short ) 0x20);
1409 retval
.setIndentionOptions(( short ) 0xfffff400);
1410 retval
.setBorderOptions(( short ) 0);
1411 retval
.setPaletteOptions(( short ) 0);
1412 retval
.setAdtlPaletteOptions(( short ) 0);
1413 retval
.setFillPaletteOptions(( short ) 0x20c0);
1417 retval
.setFontIndex(( short ) 0);
1418 retval
.setFormatIndex(( short ) 0);
1419 retval
.setCellOptions(( short ) 0xfffffff5);
1420 retval
.setAlignmentOptions(( short ) 0x20);
1421 retval
.setIndentionOptions(( short ) 0xfffff400);
1422 retval
.setBorderOptions(( short ) 0);
1423 retval
.setPaletteOptions(( short ) 0);
1424 retval
.setAdtlPaletteOptions(( short ) 0);
1425 retval
.setFillPaletteOptions(( short ) 0x20c0);
1429 retval
.setFontIndex(( short ) 0);
1430 retval
.setFormatIndex(( short ) 0);
1431 retval
.setCellOptions(( short ) 0xfffffff5);
1432 retval
.setAlignmentOptions(( short ) 0x20);
1433 retval
.setIndentionOptions(( short ) 0xfffff400);
1434 retval
.setBorderOptions(( short ) 0);
1435 retval
.setPaletteOptions(( short ) 0);
1436 retval
.setAdtlPaletteOptions(( short ) 0);
1437 retval
.setFillPaletteOptions(( short ) 0x20c0);
1441 retval
.setFontIndex(( short ) 0);
1442 retval
.setFormatIndex(( short ) 0);
1443 retval
.setCellOptions(( short ) 0xfffffff5);
1444 retval
.setAlignmentOptions(( short ) 0x20);
1445 retval
.setIndentionOptions(( short ) 0xfffff400);
1446 retval
.setBorderOptions(( short ) 0);
1447 retval
.setPaletteOptions(( short ) 0);
1448 retval
.setAdtlPaletteOptions(( short ) 0);
1449 retval
.setFillPaletteOptions(( short ) 0x20c0);
1453 retval
.setFontIndex(( short ) 0);
1454 retval
.setFormatIndex(( short ) 0);
1455 retval
.setCellOptions(( short ) 0xfffffff5);
1456 retval
.setAlignmentOptions(( short ) 0x20);
1457 retval
.setIndentionOptions(( short ) 0xfffff400);
1458 retval
.setBorderOptions(( short ) 0);
1459 retval
.setPaletteOptions(( short ) 0);
1460 retval
.setAdtlPaletteOptions(( short ) 0);
1461 retval
.setFillPaletteOptions(( short ) 0x20c0);
1465 retval
.setFontIndex(( short ) 0);
1466 retval
.setFormatIndex(( short ) 0);
1467 retval
.setCellOptions(( short ) 0xfffffff5);
1468 retval
.setAlignmentOptions(( short ) 0x20);
1469 retval
.setIndentionOptions(( short ) 0xfffff400);
1470 retval
.setBorderOptions(( short ) 0);
1471 retval
.setPaletteOptions(( short ) 0);
1472 retval
.setAdtlPaletteOptions(( short ) 0);
1473 retval
.setFillPaletteOptions(( short ) 0x20c0);
1477 retval
.setFontIndex(( short ) 0);
1478 retval
.setFormatIndex(( short ) 0);
1479 retval
.setCellOptions(( short ) 0xfffffff5);
1480 retval
.setAlignmentOptions(( short ) 0x20);
1481 retval
.setIndentionOptions(( short ) 0xfffff400);
1482 retval
.setBorderOptions(( short ) 0);
1483 retval
.setPaletteOptions(( short ) 0);
1484 retval
.setAdtlPaletteOptions(( short ) 0);
1485 retval
.setFillPaletteOptions(( short ) 0x20c0);
1490 retval
.setFontIndex(( short ) 0);
1491 retval
.setFormatIndex(( short ) 0);
1492 retval
.setCellOptions(( short ) 0x1);
1493 retval
.setAlignmentOptions(( short ) 0x20);
1494 retval
.setIndentionOptions(( short ) 0x0);
1495 retval
.setBorderOptions(( short ) 0);
1496 retval
.setPaletteOptions(( short ) 0);
1497 retval
.setAdtlPaletteOptions(( short ) 0);
1498 retval
.setFillPaletteOptions(( short ) 0x20c0);
1503 retval
.setFontIndex(( short ) 1);
1504 retval
.setFormatIndex(( short ) 0x2b);
1505 retval
.setCellOptions(( short ) 0xfffffff5);
1506 retval
.setAlignmentOptions(( short ) 0x20);
1507 retval
.setIndentionOptions(( short ) 0xfffff800);
1508 retval
.setBorderOptions(( short ) 0);
1509 retval
.setPaletteOptions(( short ) 0);
1510 retval
.setAdtlPaletteOptions(( short ) 0);
1511 retval
.setFillPaletteOptions(( short ) 0x20c0);
1515 retval
.setFontIndex(( short ) 1);
1516 retval
.setFormatIndex(( short ) 0x29);
1517 retval
.setCellOptions(( short ) 0xfffffff5);
1518 retval
.setAlignmentOptions(( short ) 0x20);
1519 retval
.setIndentionOptions(( short ) 0xfffff800);
1520 retval
.setBorderOptions(( short ) 0);
1521 retval
.setPaletteOptions(( short ) 0);
1522 retval
.setAdtlPaletteOptions(( short ) 0);
1523 retval
.setFillPaletteOptions(( short ) 0x20c0);
1527 retval
.setFontIndex(( short ) 1);
1528 retval
.setFormatIndex(( short ) 0x2c);
1529 retval
.setCellOptions(( short ) 0xfffffff5);
1530 retval
.setAlignmentOptions(( short ) 0x20);
1531 retval
.setIndentionOptions(( short ) 0xfffff800);
1532 retval
.setBorderOptions(( short ) 0);
1533 retval
.setPaletteOptions(( short ) 0);
1534 retval
.setAdtlPaletteOptions(( short ) 0);
1535 retval
.setFillPaletteOptions(( short ) 0x20c0);
1539 retval
.setFontIndex(( short ) 1);
1540 retval
.setFormatIndex(( short ) 0x2a);
1541 retval
.setCellOptions(( short ) 0xfffffff5);
1542 retval
.setAlignmentOptions(( short ) 0x20);
1543 retval
.setIndentionOptions(( short ) 0xfffff800);
1544 retval
.setBorderOptions(( short ) 0);
1545 retval
.setPaletteOptions(( short ) 0);
1546 retval
.setAdtlPaletteOptions(( short ) 0);
1547 retval
.setFillPaletteOptions(( short ) 0x20c0);
1551 retval
.setFontIndex(( short ) 1);
1552 retval
.setFormatIndex(( short ) 0x9);
1553 retval
.setCellOptions(( short ) 0xfffffff5);
1554 retval
.setAlignmentOptions(( short ) 0x20);
1555 retval
.setIndentionOptions(( short ) 0xfffff800);
1556 retval
.setBorderOptions(( short ) 0);
1557 retval
.setPaletteOptions(( short ) 0);
1558 retval
.setAdtlPaletteOptions(( short ) 0);
1559 retval
.setFillPaletteOptions(( short ) 0x20c0);
1562 // unused from this point down
1564 retval
.setFontIndex(( short ) 5);
1565 retval
.setFormatIndex(( short ) 0x0);
1566 retval
.setCellOptions(( short ) 0x1);
1567 retval
.setAlignmentOptions(( short ) 0x20);
1568 retval
.setIndentionOptions(( short ) 0x800);
1569 retval
.setBorderOptions(( short ) 0);
1570 retval
.setPaletteOptions(( short ) 0);
1571 retval
.setAdtlPaletteOptions(( short ) 0);
1572 retval
.setFillPaletteOptions(( short ) 0x20c0);
1576 retval
.setFontIndex(( short ) 6);
1577 retval
.setFormatIndex(( short ) 0x0);
1578 retval
.setCellOptions(( short ) 0x1);
1579 retval
.setAlignmentOptions(( short ) 0x20);
1580 retval
.setIndentionOptions(( short ) 0x5c00);
1581 retval
.setBorderOptions(( short ) 0);
1582 retval
.setPaletteOptions(( short ) 0);
1583 retval
.setAdtlPaletteOptions(( short ) 0);
1584 retval
.setFillPaletteOptions(( short ) 0x20c0);
1588 retval
.setFontIndex(( short ) 0);
1589 retval
.setFormatIndex(( short ) 0x31);
1590 retval
.setCellOptions(( short ) 0x1);
1591 retval
.setAlignmentOptions(( short ) 0x20);
1592 retval
.setIndentionOptions(( short ) 0x5c00);
1593 retval
.setBorderOptions(( short ) 0);
1594 retval
.setPaletteOptions(( short ) 0);
1595 retval
.setAdtlPaletteOptions(( short ) 0);
1596 retval
.setFillPaletteOptions(( short ) 0x20c0);
1600 retval
.setFontIndex(( short ) 0);
1601 retval
.setFormatIndex(( short ) 0x8);
1602 retval
.setCellOptions(( short ) 0x1);
1603 retval
.setAlignmentOptions(( short ) 0x20);
1604 retval
.setIndentionOptions(( short ) 0x5c00);
1605 retval
.setBorderOptions(( short ) 0);
1606 retval
.setPaletteOptions(( short ) 0);
1607 retval
.setAdtlPaletteOptions(( short ) 0);
1608 retval
.setFillPaletteOptions(( short ) 0x20c0);
1612 retval
.setFontIndex(( short ) 6);
1613 retval
.setFormatIndex(( short ) 0x8);
1614 retval
.setCellOptions(( short ) 0x1);
1615 retval
.setAlignmentOptions(( short ) 0x20);
1616 retval
.setIndentionOptions(( short ) 0x5c00);
1617 retval
.setBorderOptions(( short ) 0);
1618 retval
.setPaletteOptions(( short ) 0);
1619 retval
.setAdtlPaletteOptions(( short ) 0);
1620 retval
.setFillPaletteOptions(( short ) 0x20c0);
1627 * creates an default cell type ExtendedFormatRecord object.
1628 * @return ExtendedFormatRecord with intial defaults (cell-type)
1631 protected ExtendedFormatRecord
createExtendedFormat() {
1632 ExtendedFormatRecord retval
= new ExtendedFormatRecord();
1634 retval
.setFontIndex(( short ) 0);
1635 retval
.setFormatIndex(( short ) 0x0);
1636 retval
.setCellOptions(( short ) 0x1);
1637 retval
.setAlignmentOptions(( short ) 0x20);
1638 retval
.setIndentionOptions(( short ) 0);
1639 retval
.setBorderOptions(( short ) 0);
1640 retval
.setPaletteOptions(( short ) 0);
1641 retval
.setAdtlPaletteOptions(( short ) 0);
1642 retval
.setFillPaletteOptions(( short ) 0x20c0);
1643 retval
.setTopBorderPaletteIdx(HSSFColor
.BLACK
.index
);
1644 retval
.setBottomBorderPaletteIdx(HSSFColor
.BLACK
.index
);
1645 retval
.setLeftBorderPaletteIdx(HSSFColor
.BLACK
.index
);
1646 retval
.setRightBorderPaletteIdx(HSSFColor
.BLACK
.index
);
1651 * Creates a StyleRecord object
1652 * @param id the number of the style record to create (meaning its position in
1653 * a file as MS Excel would create it.
1654 * @return record containing a StyleRecord
1655 * @see org.apache.poi.hssf.record.StyleRecord
1656 * @see org.apache.poi.hssf.record.Record
1659 protected Record
createStyle(int id
) { // we'll need multiple editions
1660 StyleRecord retval
= new StyleRecord();
1665 retval
.setIndex(( short ) 0xffff8010);
1666 retval
.setBuiltin(( byte ) 3);
1667 retval
.setOutlineStyleLevel(( byte ) 0xffffffff);
1671 retval
.setIndex(( short ) 0xffff8011);
1672 retval
.setBuiltin(( byte ) 6);
1673 retval
.setOutlineStyleLevel(( byte ) 0xffffffff);
1677 retval
.setIndex(( short ) 0xffff8012);
1678 retval
.setBuiltin(( byte ) 4);
1679 retval
.setOutlineStyleLevel(( byte ) 0xffffffff);
1683 retval
.setIndex(( short ) 0xffff8013);
1684 retval
.setBuiltin(( byte ) 7);
1685 retval
.setOutlineStyleLevel(( byte ) 0xffffffff);
1689 retval
.setIndex(( short ) 0xffff8000);
1690 retval
.setBuiltin(( byte ) 0);
1691 retval
.setOutlineStyleLevel(( byte ) 0xffffffff);
1695 retval
.setIndex(( short ) 0xffff8014);
1696 retval
.setBuiltin(( byte ) 5);
1697 retval
.setOutlineStyleLevel(( byte ) 0xffffffff);
1704 * Creates a palette record initialized to the default palette
1705 * @return a PaletteRecord instance populated with the default colors
1706 * @see org.apache.poi.hssf.record.PaletteRecord
1708 protected PaletteRecord
createPalette()
1710 return new PaletteRecord();
1714 * Creates the UseSelFS object with the use natural language flag set to 0 (false)
1715 * @return record containing a UseSelFSRecord
1716 * @see org.apache.poi.hssf.record.UseSelFSRecord
1717 * @see org.apache.poi.hssf.record.Record
1720 protected Record
createUseSelFS() {
1721 UseSelFSRecord retval
= new UseSelFSRecord();
1723 retval
.setFlag(( short ) 0);
1728 * create a "bound sheet" or "bundlesheet" (depending who you ask) record
1729 * Always sets the sheet's bof to 0. You'll need to set that yourself.
1730 * @param id either sheet 0,1 or 2.
1731 * @return record containing a BoundSheetRecord
1732 * @see org.apache.poi.hssf.record.BoundSheetRecord
1733 * @see org.apache.poi.hssf.record.Record
1736 protected Record
createBoundSheet(int id
) { // 1,2,3 sheets
1737 BoundSheetRecord retval
= new BoundSheetRecord();
1742 retval
.setPositionOfBof(0x0); // should be set later
1743 retval
.setOptionFlags(( short ) 0);
1744 retval
.setSheetnameLength(( byte ) 0x6);
1745 retval
.setCompressedUnicodeFlag(( byte ) 0);
1746 retval
.setSheetname("Sheet1");
1750 retval
.setPositionOfBof(0x0); // should be set later
1751 retval
.setOptionFlags(( short ) 0);
1752 retval
.setSheetnameLength(( byte ) 0x6);
1753 retval
.setCompressedUnicodeFlag(( byte ) 0);
1754 retval
.setSheetname("Sheet2");
1758 retval
.setPositionOfBof(0x0); // should be set later
1759 retval
.setOptionFlags(( short ) 0);
1760 retval
.setSheetnameLength(( byte ) 0x6);
1761 retval
.setCompressedUnicodeFlag(( byte ) 0);
1762 retval
.setSheetname("Sheet3");
1769 * Creates the Country record with the default country set to 1
1770 * and current country set to 7 in case of russian locale ("ru_RU") and 1 otherwise
1771 * @return record containing a CountryRecord
1772 * @see org.apache.poi.hssf.record.CountryRecord
1773 * @see org.apache.poi.hssf.record.Record
1776 protected Record
createCountry() { // what a novel idea, create your own!
1777 CountryRecord retval
= new CountryRecord();
1779 retval
.setDefaultCountry(( short ) 1);
1781 // from Russia with love ;)
1782 if ( Locale
.getDefault().toString().equals( "ru_RU" ) ) {
1783 retval
.setCurrentCountry(( short ) 7);
1786 retval
.setCurrentCountry(( short ) 1);
1793 * Creates the SST record with no strings and the unique/num string set to 0
1794 * @return record containing a SSTRecord
1795 * @see org.apache.poi.hssf.record.SSTRecord
1796 * @see org.apache.poi.hssf.record.Record
1799 protected Record
createSST() {
1800 return new SSTRecord();
1804 * Creates the ExtendedSST record with numstrings per bucket set to 0x8. HSSF
1805 * doesn't yet know what to do with this thing, but we create it with nothing in
1806 * it hardly just to make Excel happy and our sheets look like Excel's
1808 * @return record containing an ExtSSTRecord
1809 * @see org.apache.poi.hssf.record.ExtSSTRecord
1810 * @see org.apache.poi.hssf.record.Record
1813 protected Record
createExtendedSST() {
1814 ExtSSTRecord retval
= new ExtSSTRecord();
1816 retval
.setNumStringsPerBucket(( short ) 0x8);
1821 * creates the EOF record
1822 * @see org.apache.poi.hssf.record.EOFRecord
1823 * @see org.apache.poi.hssf.record.Record
1824 * @return record containing a EOFRecord
1827 protected Record
createEOF() {
1828 return new EOFRecord();
1832 * lazy initialization
1833 * Note - creating the link table causes creation of 1 EXTERNALBOOK and 1 EXTERNALSHEET record
1835 private LinkTable
getOrCreateLinkTable() {
1836 if(linkTable
== null) {
1837 linkTable
= new LinkTable((short) getNumSheets(), records
);
1842 public SheetReferences
getSheetReferences() {
1843 SheetReferences refs
= new SheetReferences();
1845 if (linkTable
!= null) {
1846 int numRefStructures
= linkTable
.getNumberOfREFStructures();
1847 for (short k
= 0; k
< numRefStructures
; k
++) {
1849 String sheetName
= findSheetNameFromExternSheet(k
);
1850 refs
.addSheetReference(sheetName
, k
);
1857 /** finds the sheet name by his extern sheet index
1858 * @param num extern sheet index
1859 * @return sheet name
1861 public String
findSheetNameFromExternSheet(short num
){
1864 short indexToSheet
= linkTable
.getIndexToSheet(num
);
1866 if (indexToSheet
>-1) { //error check, bail out gracefully!
1867 result
= getSheetName(indexToSheet
);
1874 * Finds the sheet index for a particular external sheet number.
1875 * @param externSheetNumber The external sheet number to convert
1876 * @return The index to the sheet found.
1878 public int getSheetIndexFromExternSheetIndex(int externSheetNumber
)
1880 return linkTable
.getSheetIndexFromExternSheetIndex(externSheetNumber
);
1883 /** returns the extern sheet number for specific sheet number ,
1884 * if this sheet doesn't exist in extern sheet , add it
1885 * @param sheetNumber sheet number
1886 * @return index to extern sheet
1888 public short checkExternSheet(int sheetNumber
){
1889 return getOrCreateLinkTable().checkExternSheet(sheetNumber
);
1892 /** gets the total number of names
1893 * @return number of names
1895 public int getNumNames(){
1896 if(linkTable
== null) {
1899 return linkTable
.getNumNames();
1902 /** gets the name record
1903 * @param index name index
1904 * @return name record
1906 public NameRecord
getNameRecord(int index
){
1907 return linkTable
.getNameRecord(index
);
1910 /** creates new name
1911 * @return new name record
1913 public NameRecord
createName(){
1914 return addName(new NameRecord());
1918 /** creates new name
1919 * @return new name record
1921 public NameRecord
addName(NameRecord name
)
1924 LinkTable linkTable
= getOrCreateLinkTable();
1925 if(linkTable
.nameAlreadyExists(name
)) {
1926 throw new IllegalArgumentException(
1927 "You are trying to assign a duplicated name record: "
1928 + name
.getNameText());
1930 linkTable
.addName(name
);
1936 * Generates a NameRecord to represent a built-in region
1937 * @return a new NameRecord unless the index is invalid
1939 public NameRecord
createBuiltInName(byte builtInName
, int index
)
1941 if (index
== -1 || index
+1 > Short
.MAX_VALUE
)
1942 throw new IllegalArgumentException("Index is not valid ["+index
+"]");
1944 NameRecord name
= new NameRecord(builtInName
, (short)(index
));
1946 String prefix
= EXCEL_REPEATING_NAME_PREFIX_
+ index
+ "_";
1948 while(linkTable
.nameAlreadyExists(name
)) {
1950 String altNameName
= prefix
+ cont
;
1952 // It would be better to set a different builtInName here.
1953 // It does not seem possible, so we create it as a
1954 // non built-in name from this point on
1955 name
= new NameRecord();
1956 name
.setNameText(altNameName
);
1957 name
.setNameTextLength((byte)altNameName
.length());
1964 /** removes the name
1965 * @param namenum name index
1967 public void removeName(int namenum
){
1969 if (linkTable
.getNumNames() > namenum
) {
1970 int idx
= findFirstRecordLocBySid(NameRecord
.sid
);
1971 records
.remove(idx
+ namenum
);
1972 linkTable
.removeName(namenum
);
1978 * Returns a format index that matches the passed in format. It does not tie into HSSFDataFormat.
1979 * @param format the format string
1980 * @param createIfNotFound creates a new format if format not found
1981 * @return the format id of a format that matches or -1 if none found and createIfNotFound
1983 public short getFormat(String format
, boolean createIfNotFound
) {
1985 for (iterator
= formats
.iterator(); iterator
.hasNext();) {
1986 FormatRecord r
= (FormatRecord
)iterator
.next();
1987 if (r
.getFormatString().equals(format
)) {
1988 return r
.getIndexCode();
1992 if (createIfNotFound
) {
1993 return createFormat(format
);
2000 * Returns the list of FormatRecords in the workbook.
2001 * @return ArrayList of FormatRecords in the notebook
2003 public ArrayList
getFormats() {
2008 * Creates a FormatRecord, inserts it, and returns the index code.
2009 * @param format the format string
2010 * @return the index code of the format record.
2011 * @see org.apache.poi.hssf.record.FormatRecord
2012 * @see org.apache.poi.hssf.record.Record
2014 public short createFormat( String format
)
2016 // ++xfpos; //These are to ensure that positions are updated properly
2019 FormatRecord rec
= new FormatRecord();
2020 maxformatid
= maxformatid
>= (short) 0xa4 ?
(short) ( maxformatid
+ 1 ) : (short) 0xa4; //Starting value from M$ empiracle study.
2021 rec
.setIndexCode( maxformatid
);
2022 rec
.setFormatStringLength( (byte) format
.length() );
2023 rec
.setFormatString( format
);
2026 while ( pos
< records
.size() && records
.get( pos
).getSid() != FormatRecord
.sid
)
2028 pos
+= formats
.size();
2030 records
.add( pos
, rec
);
2037 * Returns the first occurance of a record matching a particular sid.
2039 public Record
findFirstRecordBySid(short sid
) {
2040 for (Iterator iterator
= records
.iterator(); iterator
.hasNext(); ) {
2041 Record record
= ( Record
) iterator
.next();
2043 if (record
.getSid() == sid
) {
2051 * Returns the index of a record matching a particular sid.
2052 * @param sid The sid of the record to match
2053 * @return The index of -1 if no match made.
2055 public int findFirstRecordLocBySid(short sid
) {
2057 for (Iterator iterator
= records
.iterator(); iterator
.hasNext(); ) {
2058 Record record
= ( Record
) iterator
.next();
2060 if (record
.getSid() == sid
) {
2069 * Returns the next occurance of a record matching a particular sid.
2071 public Record
findNextRecordBySid(short sid
, int pos
) {
2073 for (Iterator iterator
= records
.iterator(); iterator
.hasNext(); ) {
2074 Record record
= ( Record
) iterator
.next();
2076 if (record
.getSid() == sid
) {
2077 if (matches
++ == pos
)
2084 public List
getHyperlinks()
2089 public List
getRecords()
2091 return records
.getRecords();
2094 // public void insertChartRecords( List chartRecords )
2096 // backuppos += chartRecords.size();
2097 // fontpos += chartRecords.size();
2098 // palettepos += chartRecords.size();
2099 // bspos += chartRecords.size();
2100 // xfpos += chartRecords.size();
2102 // records.addAll(protpos, chartRecords);
2106 * Whether date windowing is based on 1/2/1904 or 1/1/1900.
2107 * Some versions of Excel (Mac) can save workbooks using 1904 date windowing.
2109 * @return true if using 1904 date windowing
2111 public boolean isUsing1904DateWindowing() {
2112 return uses1904datewindowing
;
2116 * Returns the custom palette in use for this workbook; if a custom palette record
2117 * does not exist, then it is created.
2119 public PaletteRecord
getCustomPalette()
2121 PaletteRecord palette
;
2122 int palettePos
= records
.getPalettepos();
2123 if (palettePos
!= -1) {
2124 Record rec
= records
.get(palettePos
);
2125 if (rec
instanceof PaletteRecord
) {
2126 palette
= (PaletteRecord
) rec
;
2127 } else throw new RuntimeException("InternalError: Expected PaletteRecord but got a '"+rec
+"'");
2131 palette
= createPalette();
2132 //Add the palette record after the bof which is always the first record
2133 records
.add(1, palette
);
2134 records
.setPalettepos(1);
2140 * Finds the primary drawing group, if one already exists
2142 public void findDrawingGroup() {
2143 // Need to find a DrawingGroupRecord that
2144 // contains a EscherDggRecord
2145 for(Iterator rit
= records
.iterator(); rit
.hasNext();) {
2146 Record r
= (Record
)rit
.next();
2148 if(r
instanceof DrawingGroupRecord
) {
2149 DrawingGroupRecord dg
= (DrawingGroupRecord
)r
;
2150 dg
.processChildRecords();
2152 EscherContainerRecord cr
=
2153 dg
.getEscherContainer();
2158 EscherDggRecord dgg
= null;
2159 for(Iterator it
= cr
.getChildRecords().iterator(); it
.hasNext();) {
2160 Object er
= it
.next();
2161 if(er
instanceof EscherDggRecord
) {
2162 dgg
= (EscherDggRecord
)er
;
2167 drawingManager
= new DrawingManager2(dgg
);
2173 // Look for the DrawingGroup record
2174 int dgLoc
= findFirstRecordLocBySid(DrawingGroupRecord
.sid
);
2176 // If there is one, does it have a EscherDggRecord?
2178 DrawingGroupRecord dg
=
2179 (DrawingGroupRecord
)records
.get(dgLoc
);
2180 EscherDggRecord dgg
= null;
2181 for(Iterator it
= dg
.getEscherRecords().iterator(); it
.hasNext();) {
2182 Object er
= it
.next();
2183 if(er
instanceof EscherDggRecord
) {
2184 dgg
= (EscherDggRecord
)er
;
2189 drawingManager
= new DrawingManager2(dgg
);
2195 * Creates a primary drawing group record. If it already
2196 * exists then it's modified.
2198 public void createDrawingGroup()
2200 if (drawingManager
== null)
2202 EscherContainerRecord dggContainer
= new EscherContainerRecord();
2203 EscherDggRecord dgg
= new EscherDggRecord();
2204 EscherOptRecord opt
= new EscherOptRecord();
2205 EscherSplitMenuColorsRecord splitMenuColors
= new EscherSplitMenuColorsRecord();
2207 dggContainer
.setRecordId((short) 0xF000);
2208 dggContainer
.setOptions((short) 0x000F);
2209 dgg
.setRecordId(EscherDggRecord
.RECORD_ID
);
2210 dgg
.setOptions((short)0x0000);
2211 dgg
.setShapeIdMax(1024);
2212 dgg
.setNumShapesSaved(0);
2213 dgg
.setDrawingsSaved(0);
2214 dgg
.setFileIdClusters(new EscherDggRecord
.FileIdCluster
[] {} );
2215 drawingManager
= new DrawingManager2(dgg
);
2216 EscherContainerRecord bstoreContainer
= null;
2217 if (escherBSERecords
.size() > 0)
2219 bstoreContainer
= new EscherContainerRecord();
2220 bstoreContainer
.setRecordId( EscherContainerRecord
.BSTORE_CONTAINER
);
2221 bstoreContainer
.setOptions( (short) ( (escherBSERecords
.size() << 4) | 0xF ) );
2222 for ( Iterator iterator
= escherBSERecords
.iterator(); iterator
.hasNext(); )
2224 EscherRecord escherRecord
= (EscherRecord
) iterator
.next();
2225 bstoreContainer
.addChildRecord( escherRecord
);
2228 opt
.setRecordId((short) 0xF00B);
2229 opt
.setOptions((short) 0x0033);
2230 opt
.addEscherProperty( new EscherBoolProperty(EscherProperties
.TEXT__SIZE_TEXT_TO_FIT_SHAPE
, 524296) );
2231 opt
.addEscherProperty( new EscherRGBProperty(EscherProperties
.FILL__FILLCOLOR
, 0x08000041) );
2232 opt
.addEscherProperty( new EscherRGBProperty(EscherProperties
.LINESTYLE__COLOR
, 134217792) );
2233 splitMenuColors
.setRecordId((short) 0xF11E);
2234 splitMenuColors
.setOptions((short) 0x0040);
2235 splitMenuColors
.setColor1(0x0800000D);
2236 splitMenuColors
.setColor2(0x0800000C);
2237 splitMenuColors
.setColor3(0x08000017);
2238 splitMenuColors
.setColor4(0x100000F7);
2240 dggContainer
.addChildRecord(dgg
);
2241 if (bstoreContainer
!= null)
2242 dggContainer
.addChildRecord( bstoreContainer
);
2243 dggContainer
.addChildRecord(opt
);
2244 dggContainer
.addChildRecord(splitMenuColors
);
2246 int dgLoc
= findFirstRecordLocBySid(DrawingGroupRecord
.sid
);
2249 DrawingGroupRecord drawingGroup
= new DrawingGroupRecord();
2250 drawingGroup
.addEscherRecord(dggContainer
);
2251 int loc
= findFirstRecordLocBySid(CountryRecord
.sid
);
2253 getRecords().add(loc
+1, drawingGroup
);
2257 DrawingGroupRecord drawingGroup
= new DrawingGroupRecord();
2258 drawingGroup
.addEscherRecord(dggContainer
);
2259 getRecords().set(dgLoc
, drawingGroup
);
2265 public WindowOneRecord
getWindowOne() {
2269 public EscherBSERecord
getBSERecord(int pictureIndex
)
2271 return (EscherBSERecord
)escherBSERecords
.get(pictureIndex
-1);
2274 public int addBSERecord(EscherBSERecord e
)
2276 createDrawingGroup();
2278 // maybe we don't need that as an instance variable anymore
2279 escherBSERecords
.add( e
);
2281 int dgLoc
= findFirstRecordLocBySid(DrawingGroupRecord
.sid
);
2282 DrawingGroupRecord drawingGroup
= (DrawingGroupRecord
) getRecords().get( dgLoc
);
2284 EscherContainerRecord dggContainer
= (EscherContainerRecord
) drawingGroup
.getEscherRecord( 0 );
2285 EscherContainerRecord bstoreContainer
;
2286 if (dggContainer
.getChild( 1 ).getRecordId() == EscherContainerRecord
.BSTORE_CONTAINER
)
2288 bstoreContainer
= (EscherContainerRecord
) dggContainer
.getChild( 1 );
2292 bstoreContainer
= new EscherContainerRecord();
2293 bstoreContainer
.setRecordId( EscherContainerRecord
.BSTORE_CONTAINER
);
2294 dggContainer
.getChildRecords().add( 1, bstoreContainer
);
2296 bstoreContainer
.setOptions( (short) ( (escherBSERecords
.size() << 4) | 0xF ) );
2298 bstoreContainer
.addChildRecord( e
);
2300 return escherBSERecords
.size();
2303 public DrawingManager2
getDrawingManager()
2305 return drawingManager
;
2308 public WriteProtectRecord
getWriteProtect() {
2309 if (this.writeProtect
== null) {
2310 this.writeProtect
= new WriteProtectRecord();
2313 i
< records
.size() && !(records
.get(i
) instanceof BOFRecord
);
2316 records
.add(i
+1,this.writeProtect
);
2318 return this.writeProtect
;
2321 public WriteAccessRecord
getWriteAccess() {
2322 if (this.writeAccess
== null) {
2323 this.writeAccess
= (WriteAccessRecord
)createWriteAccess();
2326 i
< records
.size() && !(records
.get(i
) instanceof InterfaceEndRecord
);
2329 records
.add(i
+1,this.writeAccess
);
2331 return this.writeAccess
;
2334 public FileSharingRecord
getFileSharing() {
2335 if (this.fileShare
== null) {
2336 this.fileShare
= new FileSharingRecord();
2339 i
< records
.size() && !(records
.get(i
) instanceof WriteAccessRecord
);
2342 records
.add(i
+1,this.fileShare
);
2344 return this.fileShare
;
2348 * is the workbook protected with a password (not encrypted)?
2350 public boolean isWriteProtected() {
2351 if (this.fileShare
== null) {
2354 FileSharingRecord frec
= getFileSharing();
2355 return (frec
.getReadOnly() == 1);
2359 * protect a workbook with a password (not encypted, just sets writeprotect
2360 * flags and the password.
2361 * @param password to set
2363 public void writeProtectWorkbook( String password
, String username
) {
2365 FileSharingRecord frec
= getFileSharing();
2366 WriteAccessRecord waccess
= getWriteAccess();
2367 WriteProtectRecord wprotect
= getWriteProtect();
2368 frec
.setReadOnly((short)1);
2369 frec
.setPassword(FileSharingRecord
.hashPassword(password
));
2370 frec
.setUsername(username
);
2371 waccess
.setUsername(username
);
2375 * removes the write protect flag
2377 public void unwriteProtectWorkbook() {
2378 records
.remove(fileShare
);
2379 records
.remove(writeProtect
);
2381 writeProtect
= null;
2385 * @param refIndex Index to REF entry in EXTERNSHEET record in the Link Table
2386 * @param definedNameIndex zero-based to DEFINEDNAME or EXTERNALNAME record
2387 * @return the string representation of the defined or external name
2389 public String
resolveNameXText(int refIndex
, int definedNameIndex
) {
2390 return linkTable
.resolveNameXText(refIndex
, definedNameIndex
);