1    
2    /* ====================================================================
3     * The Apache Software License, Version 1.1
4     *
5     * Copyright (c) 2002 The Apache Software Foundation.  All rights
6     * reserved.
7     *
8     * Redistribution and use in source and binary forms, with or without
9     * modification, are permitted provided that the following conditions
10    * are met:
11    *
12    * 1. Redistributions of source code must retain the above copyright
13    *    notice, this list of conditions and the following disclaimer.
14    *
15    * 2. Redistributions in binary form must reproduce the above copyright
16    *    notice, this list of conditions and the following disclaimer in
17    *    the documentation and/or other materials provided with the
18    *    distribution.
19    *
20    * 3. The end-user documentation included with the redistribution,
21    *    if any, must include the following acknowledgment:
22    *       "This product includes software developed by the
23    *        Apache Software Foundation (http://www.apache.org/)."
24    *    Alternately, this acknowledgment may appear in the software itself,
25    *    if and wherever such third-party acknowledgments normally appear.
26    *
27    * 4. The names "Apache" and "Apache Software Foundation" and
28    *    "Apache POI" must not be used to endorse or promote products
29    *    derived from this software without prior written permission. For
30    *    written permission, please contact apache@apache.org.
31    *
32    * 5. Products derived from this software may not be called "Apache",
33    *    "Apache POI", nor may "Apache" appear in their name, without
34    *    prior written permission of the Apache Software Foundation.
35    *
36    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47    * SUCH DAMAGE.
48    * ====================================================================
49    *
50    * This software consists of voluntary contributions made by many
51    * individuals on behalf of the Apache Software Foundation.  For more
52    * information on the Apache Software Foundation, please see
53    * <http://www.apache.org/>.
54    */
55   
56   package org.apache.poi.hssf.model;
57   
58   import java.io.*;
59   
60   import java.util.ArrayList;
61   import java.util.List;
62   import java.util.Iterator;
63   import java.util.Locale;
64   
65   
66   import org.apache.poi.util.POILogger;
67   import org.apache.poi.util.POILogFactory;
68   
69   import org.apache.poi.hssf.record.*;
70   import org.apache.poi.hssf.util.SheetReferences;
71   import org.apache.poi.hssf.util.HSSFColor;
72   
73   /**
74    * Workbook
75    * Low level model implementation of a Workbook.  Provides creational methods
76    * for settings and objects contained in the workbook object.
77    * <P>
78    * This file contains the low level binary records starting at the workbook's BOF and
79    * ending with the workbook's EOF.  Use HSSFWorkbook for a high level representation.
80    * <P>
81    * The structures of the highlevel API use references to this to perform most of their
82    * operations.  Its probably unwise to use these low level structures directly unless you
83    * really know what you're doing.  I recommend you read the Microsoft Excel 97 Developer's
84    * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf
85    * before even attempting to use this.
86    *
87    * @author  Shawn Laubach (shawnlaubach at cox.net) (Data Formats)
88    * @author  Andrew C. Oliver (acoliver at apache dot org)
89    * @author  Glen Stampoultzis (glens at apache.org)
90    * @author  Sergei Kozello (sergeikozello at mail.ru)
91    * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
92    * @version 1.0-pre
93    */
94   
95   public class Workbook {
96       private static final int   DEBUG       = POILogger.DEBUG;
97   
98   //    public static Workbook currentBook = null;
99   
100      /**
101       * constant used to set the "codepage" wherever "codepage" is set in records
102       * (which is duplciated in more than one record)
103       */
104  
105      private final static short CODEPAGE    = ( short ) 0x4b0;
106  
107      /**
108       * this contains the Worksheet record objects
109       */
110  
111      protected ArrayList        records     = null;
112  
113      /**
114       * this contains a reference to the SSTRecord so that new stings can be added
115       * to it.
116       */
117  
118      protected SSTRecord        sst         = null;
119  
120      /**
121       * Holds the Extern Sheet with references to bound sheets
122       */
123  
124      protected ExternSheetRecord externSheet= null;
125  
126      /**
127       * holds the "boundsheet" records (aka bundlesheet) so that they can have their
128       * reference to their "BOF" marker
129       */
130  
131  
132      protected ArrayList        boundsheets = new ArrayList();
133  
134      protected ArrayList        formats = new ArrayList();
135  
136      protected ArrayList        names = new ArrayList();
137  
138      protected int              bspos       =
139      0;   // holds the position of the last bound sheet.
140      protected int              tabpos      =
141      0;   // holds the position of the tabid record
142      protected int              fontpos     =
143      0;   // hold the position of the last font record
144      protected int              numfonts    =
145      0;   // hold the number of font records
146      protected int              xfpos       =
147      0;   // hold the position of the last extended font record
148      protected int              numxfs      =
149      0;   // hold the number of extended format records
150      private int                backuppos   =
151      0;   // holds the position of the backup record.
152      private int                namepos   =
153      0;   // holds the position of last name record
154      private int                supbookpos   =
155      0;   // holds the position of sup book
156      private short              maxformatid  =
157      -1;  // holds the max format id
158  
159      private static POILogger   log         =
160      POILogFactory.getLogger(Workbook.class);
161  
162      /**
163       * Creates new Workbook with no intitialization --useless right now
164       * @see #createWorkbook(List)
165       */
166  
167      public Workbook() {
168      }
169  
170      /**
171       * read support  for low level
172       * API.  Pass in an array of Record objects, A Workbook
173       * object is constructed and passed back with all of its initialization set
174       * to the passed in records and references to those records held. Unlike Sheet
175       * workbook does not use an offset (its assumed to be 0) since its first in a file.
176       * If you need an offset then construct a new array with a 0 offset or write your
177       * own ;-p.
178       *
179       * @param recs an array of Record objects
180       * @return Workbook object
181       */
182  
183      public static Workbook createWorkbook(List recs) {
184          log.log(DEBUG, "Workbook (readfile) created with reclen=",
185          new Integer(recs.size()));
186          Workbook  retval  = new Workbook();
187          ArrayList records = new ArrayList(recs.size() / 3);
188  
189          for (int k = 0; k < recs.size(); k++) {
190              Record rec = ( Record ) recs.get(k);
191  
192              if (rec.getSid() == EOFRecord.sid) {
193                  records.add(rec);
194                  log.log(DEBUG, "found workbook eof record at " + k);
195                  break;
196              }
197              switch (rec.getSid()) {
198  
199                  case BoundSheetRecord.sid :
200                      log.log(DEBUG, "found boundsheet record at " + k);
201                      retval.boundsheets.add(rec);
202                      retval.bspos = k;
203                      break;
204  
205                  case SSTRecord.sid :
206                      log.log(DEBUG, "found sst record at " + k);
207                      retval.sst = ( SSTRecord ) rec;
208                      break;
209  
210                  case FontRecord.sid :
211                      log.log(DEBUG, "found font record at " + k);
212                      retval.fontpos = k;
213                      retval.numfonts++;
214                      break;
215  
216                  case ExtendedFormatRecord.sid :
217                      log.log(DEBUG, "found XF record at " + k);
218                      retval.xfpos = k;
219                      retval.numxfs++;
220                      break;
221  
222                  case TabIdRecord.sid :
223                      log.log(DEBUG, "found tabid record at " + k);
224                      retval.tabpos = k;
225                      break;
226  
227                  case BackupRecord.sid :
228                      log.log(DEBUG, "found backup record at " + k);
229                      retval.backuppos = k;
230                      break;
231                  case ExternSheetRecord.sid :
232                      log.log(DEBUG, "found extern sheet record at " + k);
233                      retval.externSheet = ( ExternSheetRecord ) rec;
234                      break;
235                  case NameRecord.sid :
236                      log.log(DEBUG, "found name record at " + k);
237                      retval.names.add(rec);
238                      retval.namepos = k;
239                      break;
240                  case 0x1AE :
241                      //Havent Implement the sup book , because we dont need extern ranges
242                      //for now
243                      log.log(DEBUG, "found SupBook record at " + k);
244                      retval.supbookpos = k;
245                      break;
246  	        case FormatRecord.sid :
247  		    log.log(DEBUG, "found format record at " + k);
248  		    retval.formats.add(rec);
249  		    retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode();
250  		    break;
251  
252                  default :
253              }
254              records.add(rec);
255          }
256          //What if we dont have any ranges and supbooks
257          if (retval.supbookpos == 0) {
258              retval.supbookpos = retval.bspos + 1;
259              retval.namepos    = retval.supbookpos + 1;
260          }
261  
262          retval.records = records;
263          log.log(DEBUG, "exit create workbook from existing file function");
264          return retval;
265      }
266  
267      /**
268       * Creates an empty workbook object with three blank sheets and all the empty
269       * fields.  Use this to create a workbook from scratch.
270       */
271  
272      public static Workbook createWorkbook() {
273          log.log(DEBUG, "creating new workbook from scratch");
274          Workbook  retval  = new Workbook();
275          ArrayList records = new ArrayList(30);
276          ArrayList formats = new ArrayList(8);
277  
278          records.add(retval.createBOF());
279          records.add(retval.createInterfaceHdr());
280          records.add(retval.createMMS());
281          records.add(retval.createInterfaceEnd());
282          records.add(retval.createWriteAccess());
283          records.add(retval.createCodepage());
284          records.add(retval.createDSF());
285          records.add(retval.createTabId());
286          retval.tabpos = records.size() - 1;
287          records.add(retval.createFnGroupCount());
288          records.add(retval.createWindowProtect());
289          records.add(retval.createProtect());
290          records.add(retval.createPassword());
291          records.add(retval.createProtectionRev4());
292          records.add(retval.createPasswordRev4());
293          records.add(retval.createWindowOne());
294          records.add(retval.createBackup());
295          retval.backuppos = records.size() - 1;
296          records.add(retval.createHideObj());
297          records.add(retval.createDateWindow1904());
298          records.add(retval.createPrecision());
299          records.add(retval.createRefreshAll());
300          records.add(retval.createBookBool());
301          records.add(retval.createFont());
302          records.add(retval.createFont());
303          records.add(retval.createFont());
304          records.add(retval.createFont());
305          retval.fontpos  = records.size() - 1;   // last font record postion
306          retval.numfonts = 4;
307  
308          // set up format records
309  	for (int i = 0; i <= 7; i++) {
310              Record    rec;         
311  	    rec = retval.createFormat(i);
312  	    retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode();
313  	    formats.add(rec);
314  	    records.add(rec);
315  	}
316  	retval.formats = formats;
317  
318          for (int k = 0; k < 21; k++) {
319              records.add(retval.createExtendedFormat(k));
320              retval.numxfs++;
321          }
322          retval.xfpos = records.size() - 1;
323          for (int k = 0; k < 6; k++) {
324              records.add(retval.createStyle(k));
325          }
326          records.add(retval.createUseSelFS());
327          for (int k = 0; k < 1; k++) {   // now just do 1
328              BoundSheetRecord bsr =
329              ( BoundSheetRecord ) retval.createBoundSheet(k);
330  
331              records.add(bsr);
332              retval.boundsheets.add(bsr);
333              retval.bspos = records.size() - 1;
334          }
335          records.add(retval.createCountry());
336          retval.sst = ( SSTRecord ) retval.createSST();
337          records.add(retval.sst);
338          records.add(retval.createExtendedSST());
339  
340          // TODO
341          records.add(retval.createEOF());
342          retval.records = records;
343          log.log(DEBUG, "exit create new workbook from scratch");
344          return retval;
345      }
346  
347      public int getNumRecords() {
348          return records.size();
349      }
350  
351      /**
352       * gets the font record at the given index in the font table.  Remember
353       * "There is No Four" (someone at M$ must have gone to Rocky Horror one too
354       * many times)
355       *
356       * @param idx the index to look at (0 or greater but NOT 4)
357       * @return FontRecord located at the given index
358       */
359  
360      public FontRecord getFontRecordAt(int idx) {
361          int index = idx;
362  
363          if (index > 4) {
364              index -= 1;   // adjust for "There is no 4"
365          }
366          if (index > (numfonts - 1)) {
367              throw new ArrayIndexOutOfBoundsException(
368              "There are only " + numfonts
369              + " font records, you asked for " + idx);
370          }
371          FontRecord retval =
372          ( FontRecord ) records.get((fontpos - (numfonts - 1)) + index);
373  
374          return retval;
375      }
376  
377      /**
378       * creates a new font record and adds it to the "font table".  This causes the
379       * boundsheets to move down one, extended formats to move down (so this function moves
380       * those pointers as well)
381       *
382       * @return FontRecord that was just created
383       */
384  
385      public FontRecord createNewFont() {
386          FontRecord rec = ( FontRecord ) createFont();
387  
388          ++fontpos;
389          ++bspos;
390          ++xfpos;
391          records.add(fontpos, rec);
392          numfonts++;
393          return rec;
394      }
395  
396      /**
397       * gets the number of font records
398       *
399       * @return   number of font records in the "font table"
400       */
401  
402      public int getNumberOfFontRecords() {
403          return numfonts;
404      }
405  
406      /**
407       * Sets the BOF for a given sheet
408       *
409       * @param sheetnum the number of the sheet to set the positing of the bof for
410       * @param pos the actual bof position
411       */
412  
413      public void setSheetBof(int sheetnum, int pos) {
414          log.log(DEBUG, "setting bof for sheetnum =", new Integer(sheetnum),
415          " at pos=", new Integer(pos));
416          checkSheets(sheetnum);
417          (( BoundSheetRecord ) boundsheets.get(sheetnum))
418          .setPositionOfBof(pos);
419      }
420  
421      /**
422       * Returns the position of the backup record.
423       */
424  
425      public BackupRecord getBackupRecord() {
426          return ( BackupRecord ) records.get(backuppos);
427      }
428  
429  
430      /**
431       * sets the name for a given sheet.  If the boundsheet record doesn't exist and
432       * its only one more than we have, go ahead and create it.  If its > 1 more than
433       * we have, except
434       *
435       * @param sheetnum the sheet number (0 based)
436       * @param sheetname the name for the sheet
437       */
438  
439      // for compartibility
440      public void setSheetName(int sheetnum, String sheetname ) {
441          setSheetName( sheetnum, sheetname, (byte)0 );
442      }
443  
444      public void setSheetName(int sheetnum, String sheetname, short encoding ) {
445          checkSheets(sheetnum);
446          BoundSheetRecord sheet = (BoundSheetRecord)boundsheets.get( sheetnum );
447          sheet.setSheetname(sheetname);
448          sheet.setSheetnameLength( (byte)sheetname.length() );
449  		sheet.setCompressedUnicodeFlag( (byte)encoding );
450      }
451  
452      /**
453       * gets the name for a given sheet.
454       *
455       * @param sheetnum the sheet number (0 based)
456       * @return sheetname the name for the sheet
457       */
458  
459      public String getSheetName(int sheetnum) {
460          return (( BoundSheetRecord ) boundsheets.get(sheetnum))
461          .getSheetname();
462      }
463  
464      /**
465       * get the sheet's index
466       * @param name  sheet name
467       * @return sheet index or -1 if it was not found.
468       */
469  
470      public int getSheetIndex(String name) {
471          int retval = -1;
472  
473          for (int k = 0; k < boundsheets.size(); k++) {
474              String sheet = getSheetName(k);
475  
476              if (sheet.equals(name)) {
477                  retval = k;
478                  break;
479              }
480          }
481          return retval;
482      }
483  
484      /**
485       * if we're trying to address one more sheet than we have, go ahead and add it!  if we're
486       * trying to address >1 more than we have throw an exception!
487       */
488  
489      private void checkSheets(int sheetnum) {
490          if ((boundsheets.size()) <= sheetnum) {   // if we're short one add another..
491              if ((boundsheets.size() + 1) <= sheetnum) {
492                  throw new RuntimeException("Sheet number out of bounds!");
493              }
494              BoundSheetRecord bsr =
495              ( BoundSheetRecord ) createBoundSheet(sheetnum);
496  
497              records.add(++bspos, bsr);
498              boundsheets.add(bsr);
499              fixTabIdRecord();
500          }
501      }
502  
503      public void removeSheet(int sheetnum) {
504          if (boundsheets.size() > sheetnum) {
505              records.remove(bspos - (boundsheets.size() - 1) + sheetnum);
506              bspos--;
507              boundsheets.remove(sheetnum);
508              fixTabIdRecord();
509          }
510      }
511  
512      /**
513       * make the tabid record look like the current situation.
514       *
515       */
516  
517      private void fixTabIdRecord() {
518          TabIdRecord tir = ( TabIdRecord ) records.get(tabpos);
519          short[]     tia = new short[ boundsheets.size() ];
520  
521          for (short k = 0; k < tia.length; k++) {
522              tia[ k ] = k;
523          }
524          tir.setTabIdArray(tia);
525      }
526  
527      /**
528       * returns the number of boundsheet objects contained in this workbook.
529       *
530       * @return number of BoundSheet records
531       */
532  
533      public int getNumSheets() {
534          log.log(DEBUG, "getNumSheets=", new Integer(boundsheets.size()));
535          return boundsheets.size();
536      }
537  
538      /**
539       * get the number of ExtendedFormat records contained in this workbook.
540       *
541       * @return int count of ExtendedFormat records
542       */
543  
544      public int getNumExFormats() {
545          log.log(DEBUG, "getXF=", new Integer(boundsheets.size()));
546          return numxfs;
547      }
548  
549      /**
550       * gets the ExtendedFormatRecord at the given 0-based index
551       *
552       * @param index of the Extended format record (0-based)
553       * @return ExtendedFormatRecord at the given index
554       */
555  
556      public ExtendedFormatRecord getExFormatAt(int index) {
557          int xfptr = xfpos - (numxfs - 1);
558  
559          xfptr += index;
560          ExtendedFormatRecord retval =
561          ( ExtendedFormatRecord ) records.get(xfptr);
562  
563          return retval;
564      }
565  
566      /**
567       * creates a new Cell-type Extneded Format Record and adds it to the end of
568       *  ExtendedFormatRecords collection
569       *
570       * @return ExtendedFormatRecord that was created
571       */
572  
573      public ExtendedFormatRecord createCellXF() {
574          ExtendedFormatRecord xf = createExtendedFormat();
575  
576          ++xfpos;
577          ++bspos;
578          records.add(xfpos, xf);
579          numxfs++;
580          return xf;
581      }
582  
583      /**
584       * Adds a string to the SST table and returns its index (if its a duplicate
585       * just returns its index and update the counts)
586       *
587       * @param string the string to be added to the SSTRecord
588       * @param use16bits whether to use utf 16 or false for compressed unicode
589       * @return index of the string within the SSTRecord
590       */
591  
592      public int addSSTString(String string, boolean use16bits) {
593          log.log(DEBUG, "insert to sst string='", string, "' and use16bits= ",
594          new Boolean(use16bits));
595          if (sst == null) {
596              insertSST();
597          }
598          return sst.addString(string, use16bits);
599      }
600  
601      /**
602       * Adds a string to the SST table and returns its index (if its a duplicate
603       * just returns its index and update the counts) ASSUMES compressed unicode
604       * (meaning 8bit)
605       *
606       * @param string the string to be added to the SSTRecord
607       *
608       * @return index of the string within the SSTRecord
609       */
610  
611      public int addSSTString(String string) {
612          return addSSTString(string, false);
613      }
614  
615      /**
616       * given an index into the SST table, this function returns the corresponding String value
617       * @return String containing the SST String
618       */
619  
620      public String getSSTString(int str) {
621          if (sst == null) {
622              insertSST();
623          }
624          String retval = sst.getString(str);
625  
626          log.log(DEBUG, "Returning SST for index=", new Integer(str),
627          " String= ", retval);
628          return retval;
629      }
630  
631      /**
632       * use this function to add a Shared String Table to an existing sheet (say
633       * generated by a different java api) without an sst....
634       * @see #createSST()
635       * @see org.apache.poi.hssf.record.SSTRecord
636       */
637  
638      public void insertSST() {
639          log.log(DEBUG, "creating new SST via insertSST!");
640          sst = ( SSTRecord ) createSST();
641          records.add(records.size() - 1, createExtendedSST());
642          records.add(records.size() - 2, sst);
643      }
644  
645      /**
646       * Serializes all records int the worksheet section into a big byte array. Use
647       * this to write the Workbook out.
648       *
649       * @return byte array containing the HSSF-only portions of the POIFS file.
650       */
651  
652      public byte [] serialize() {
653          log.log(DEBUG, "Serializing Workbook!");
654          byte[] retval    = null;
655  
656          // ArrayList bytes     = new ArrayList(records.size());
657          int    arraysize = getSize();
658          int    pos       = 0;
659  
660          // for (int k = 0; k < records.size(); k++)
661          // {
662          // bytes.add((( Record ) records.get(k)).serialize());
663          //        }
664          // for (int k = 0; k < bytes.size(); k++)
665          // {
666          // arraysize += (( byte [] ) bytes.get(k)).length;
667          // }
668          retval = new byte[ arraysize ];
669          for (int k = 0; k < records.size(); k++) {
670  
671              // byte[] rec = (( byte [] ) bytes.get(k));
672              // System.arraycopy(rec, 0, retval, pos, rec.length);
673              pos += (( Record ) records.get(k)).serialize(pos,
674              retval);   // rec.length;
675          }
676          log.log(DEBUG, "Exiting serialize workbook");
677          return retval;
678      }
679  
680      /**
681       * Serializes all records int the worksheet section into a big byte array. Use
682       * this to write the Workbook out.
683       * @param offset of the data to be written
684       * @param data array of bytes to write this to
685       */
686  
687      public int serialize(int offset, byte [] data) {
688          log.log(DEBUG, "Serializing Workbook with offsets");
689  
690          // ArrayList bytes     = new ArrayList(records.size());
691          //        int arraysize = getSize();   // 0;
692          int pos       = 0;
693  
694          //        for (int k = 0; k < records.size(); k++)
695          //        {
696          //            bytes.add((( Record ) records.get(k)).serialize());
697          //
698          //        }
699          //        for (int k = 0; k < bytes.size(); k++)
700          //       {
701          //            arraysize += (( byte [] ) bytes.get(k)).length;
702          //        }
703          for (int k = 0; k < records.size(); k++) {
704  
705              // byte[] rec = (( byte [] ) bytes.get(k));
706              // System.arraycopy(rec, 0, data, offset + pos, rec.length);
707              pos += (( Record ) records.get(k)).serialize(pos + offset,
708              data);   // rec.length;
709          }
710          log.log(DEBUG, "Exiting serialize workbook");
711          return pos;
712      }
713  
714      public int getSize() {
715          int retval = 0;
716  
717          for (int k = 0; k < records.size(); k++) {
718              retval += (( Record ) records.get(k)).getRecordSize();
719          }
720          return retval;
721      }
722  
723      /**
724       * creates the BOF record
725       * @see org.apache.poi.hssf.record.BOFRecord
726       * @see org.apache.poi.hssf.record.Record
727       * @return record containing a BOFRecord
728       */
729  
730      protected Record createBOF() {
731          BOFRecord retval = new BOFRecord();
732  
733          retval.setVersion(( short ) 0x600);
734          retval.setType(( short ) 5);
735          retval.setBuild(( short ) 0x10d3);
736  
737          //        retval.setBuild((short)0x0dbb);
738          retval.setBuildYear(( short ) 1996);
739          retval.setHistoryBitMask(0x41);   // was c1 before verify
740          retval.setRequiredVersion(0x6);
741          return retval;
742      }
743  
744      /**
745       * creates the InterfaceHdr record
746       * @see org.apache.poi.hssf.record.InterfaceHdrRecord
747       * @see org.apache.poi.hssf.record.Record
748       * @return record containing a InterfaceHdrRecord
749       */
750  
751      protected Record createInterfaceHdr() {
752          InterfaceHdrRecord retval = new InterfaceHdrRecord();
753  
754          retval.setCodepage(CODEPAGE);
755          return retval;
756      }
757  
758      /**
759       * creates an MMS record
760       * @see org.apache.poi.hssf.record.MMSRecord
761       * @see org.apache.poi.hssf.record.Record
762       * @return record containing a MMSRecord
763       */
764  
765      protected Record createMMS() {
766          MMSRecord retval = new MMSRecord();
767  
768          retval.setAddMenuCount(( byte ) 0);
769          retval.setDelMenuCount(( byte ) 0);
770          return retval;
771      }
772  
773      /**
774       * creates the InterfaceEnd record
775       * @see org.apache.poi.hssf.record.InterfaceEndRecord
776       * @see org.apache.poi.hssf.record.Record
777       * @return record containing a InterfaceEndRecord
778       */
779  
780      protected Record createInterfaceEnd() {
781          return new InterfaceEndRecord();
782      }
783  
784      /**
785       * creates the WriteAccess record containing the logged in user's name
786       * @see org.apache.poi.hssf.record.WriteAccessRecord
787       * @see org.apache.poi.hssf.record.Record
788       * @return record containing a WriteAccessRecord
789       */
790  
791      protected Record createWriteAccess() {
792          WriteAccessRecord retval = new WriteAccessRecord();
793  
794          retval.setUsername(System.getProperty("user.name"));
795          return retval;
796      }
797  
798      /**
799       * creates the Codepage record containing the constant stored in CODEPAGE
800       * @see org.apache.poi.hssf.record.CodepageRecord
801       * @see org.apache.poi.hssf.record.Record
802       * @return record containing a CodepageRecord
803       */
804  
805      protected Record createCodepage() {
806          CodepageRecord retval = new CodepageRecord();
807  
808          retval.setCodepage(CODEPAGE);
809          return retval;
810      }
811  
812      /**
813       * creates the DSF record containing a 0 since HSSF can't even create Dual Stream Files
814       * @see org.apache.poi.hssf.record.DSFRecord
815       * @see org.apache.poi.hssf.record.Record
816       * @return record containing a DSFRecord
817       */
818  
819      protected Record createDSF() {
820          DSFRecord retval = new DSFRecord();
821  
822          retval.setDsf(
823          ( short ) 0);   // we don't even support double stream files
824          return retval;
825      }
826  
827      /**
828       * creates the TabId record containing an array of 0,1,2.  This release of HSSF
829       * always has the default three sheets, no less, no more.
830       * @see org.apache.poi.hssf.record.TabIdRecord
831       * @see org.apache.poi.hssf.record.Record
832       * @return record containing a TabIdRecord
833       */
834  
835      protected Record createTabId() {
836          TabIdRecord retval     = new TabIdRecord();
837          short[]     tabidarray = {
838              0
839          };
840  
841          retval.setTabIdArray(tabidarray);
842          return retval;
843      }
844  
845      /**
846       * creates the FnGroupCount record containing the Magic number constant of 14.
847       * @see org.apache.poi.hssf.record.FnGroupCountRecord
848       * @see org.apache.poi.hssf.record.Record
849       * @return record containing a FnGroupCountRecord
850       */
851  
852      protected Record createFnGroupCount() {
853          FnGroupCountRecord retval = new FnGroupCountRecord();
854  
855          retval.setCount(( short ) 14);
856          return retval;
857      }
858  
859      /**
860       * creates the WindowProtect record with protect set to false.
861       * @see org.apache.poi.hssf.record.WindowProtectRecord
862       * @see org.apache.poi.hssf.record.Record
863       * @return record containing a WindowProtectRecord
864       */
865  
866      protected Record createWindowProtect() {
867          WindowProtectRecord retval = new WindowProtectRecord();
868  
869          retval.setProtect(
870          false);   // by default even when we support it we won't
871          return retval;   // want it to be protected
872      }
873  
874      /**
875       * creates the Protect record with protect set to false.
876       * @see org.apache.poi.hssf.record.ProtectRecord
877       * @see org.apache.poi.hssf.record.Record
878       * @return record containing a ProtectRecord
879       */
880  
881      protected Record createProtect() {
882          ProtectRecord retval = new ProtectRecord();
883  
884          retval.setProtect(
885          false);   // by default even when we support it we won't
886          return retval;   // want it to be protected
887      }
888  
889      /**
890       * creates the Password record with password set to 0.
891       * @see org.apache.poi.hssf.record.PasswordRecord
892       * @see org.apache.poi.hssf.record.Record
893       * @return record containing a PasswordRecord
894       */
895  
896      protected Record createPassword() {
897          PasswordRecord retval = new PasswordRecord();
898  
899          retval.setPassword(( short ) 0);   // no password by default!
900          return retval;
901      }
902  
903      /**
904       * creates the ProtectionRev4 record with protect set to false.
905       * @see org.apache.poi.hssf.record.ProtectionRev4Record
906       * @see org.apache.poi.hssf.record.Record
907       * @return record containing a ProtectionRev4Record
908       */
909  
910      protected Record createProtectionRev4() {
911          ProtectionRev4Record retval = new ProtectionRev4Record();
912  
913          retval.setProtect(false);
914          return retval;
915      }
916  
917      /**
918       * creates the PasswordRev4 record with password set to 0.
919       * @see org.apache.poi.hssf.record.PasswordRev4Record
920       * @see org.apache.poi.hssf.record.Record
921       * @return record containing a PasswordRev4Record
922       */
923  
924      protected Record createPasswordRev4() {
925          PasswordRev4Record retval = new PasswordRev4Record();
926  
927          retval.setPassword(( short ) 0);   // no password by default!
928          return retval;
929      }
930  
931      /**
932       * creates the WindowOne record with the following magic values: <P>
933       * horizontal hold - 0x168 <P>
934       * vertical hold   - 0x10e <P>
935       * width           - 0x3a5c <P>
936       * height          - 0x23be <P>
937       * options         - 0x38 <P>
938       * selected tab    - 0 <P>
939       * displayed tab   - 0 <P>
940       * num selected tab- 0 <P>
941       * tab width ratio - 0x258 <P>
942       * @see org.apache.poi.hssf.record.WindowOneRecord
943       * @see org.apache.poi.hssf.record.Record
944       * @return record containing a WindowOneRecord
945       */
946  
947      protected Record createWindowOne() {
948          WindowOneRecord retval = new WindowOneRecord();
949  
950          retval.setHorizontalHold(( short ) 0x168);
951          retval.setVerticalHold(( short ) 0x10e);
952          retval.setWidth(( short ) 0x3a5c);
953          retval.setHeight(( short ) 0x23be);
954          retval.setOptions(( short ) 0x38);
955          retval.setSelectedTab(( short ) 0x0);
956          retval.setDisplayedTab(( short ) 0x0);
957          retval.setNumSelectedTabs(( short ) 1);
958          retval.setTabWidthRatio(( short ) 0x258);
959          return retval;
960      }
961  
962      /**
963       * creates the Backup record with backup set to 0. (loose the data, who cares)
964       * @see org.apache.poi.hssf.record.BackupRecord
965       * @see org.apache.poi.hssf.record.Record
966       * @return record containing a BackupRecord
967       */
968  
969      protected Record createBackup() {
970          BackupRecord retval = new BackupRecord();
971  
972          retval.setBackup(
973          ( short ) 0);   // by default DONT save backups of files...just loose data
974          return retval;
975      }
976  
977      /**
978       * creates the HideObj record with hide object set to 0. (don't hide)
979       * @see org.apache.poi.hssf.record.HideObjRecord
980       * @see org.apache.poi.hssf.record.Record
981       * @return record containing a HideObjRecord
982       */
983  
984      protected Record createHideObj() {
985          HideObjRecord retval = new HideObjRecord();
986  
987          retval.setHideObj(( short ) 0);   // by default set hide object off
988          return retval;
989      }
990  
991      /**
992       * creates the DateWindow1904 record with windowing set to 0. (don't window)
993       * @see org.apache.poi.hssf.record.DateWindow1904Record
994       * @see org.apache.poi.hssf.record.Record
995       * @return record containing a DateWindow1904Record
996       */
997  
998      protected Record createDateWindow1904() {
999          DateWindow1904Record retval = new DateWindow1904Record();
1000 
1001         retval.setWindowing(
1002         ( short ) 0);   // don't EVER use 1904 date windowing...tick tock..
1003         return retval;
1004     }
1005 
1006     /**
1007      * creates the Precision record with precision set to true. (full precision)
1008      * @see org.apache.poi.hssf.record.PrecisionRecord
1009      * @see org.apache.poi.hssf.record.Record
1010      * @return record containing a PrecisionRecord
1011      */
1012 
1013     protected Record createPrecision() {
1014         PrecisionRecord retval = new PrecisionRecord();
1015 
1016         retval.setFullPrecision(
1017         true);   // always use real numbers in calculations!
1018         return retval;
1019     }
1020 
1021     /**
1022      * creates the RefreshAll record with refreshAll set to true. (refresh all calcs)
1023      * @see org.apache.poi.hssf.record.RefreshAllRecord
1024      * @see org.apache.poi.hssf.record.Record
1025      * @return record containing a RefreshAllRecord
1026      */
1027 
1028     protected Record createRefreshAll() {
1029         RefreshAllRecord retval = new RefreshAllRecord();
1030 
1031         retval.setRefreshAll(false);
1032         return retval;
1033     }
1034 
1035     /**
1036      * creates the BookBool record with saveLinkValues set to 0. (don't save link values)
1037      * @see org.apache.poi.hssf.record.BookBoolRecord
1038      * @see org.apache.poi.hssf.record.Record
1039      * @return record containing a BookBoolRecord
1040      */
1041 
1042     protected Record createBookBool() {
1043         BookBoolRecord retval = new BookBoolRecord();
1044 
1045         retval.setSaveLinkValues(( short ) 0);
1046         return retval;
1047     }
1048 
1049     /**
1050      * creates a Font record with the following magic values: <P>
1051      * fontheight           = 0xc8<P>
1052      * attributes           = 0x0<P>
1053      * color palette index  = 0x7fff<P>
1054      * bold weight          = 0x190<P>
1055      * Font Name Length     = 5 <P>
1056      * Font Name            = Arial <P>
1057      *
1058      * @see org.apache.poi.hssf.record.FontRecord
1059      * @see org.apache.poi.hssf.record.Record
1060      * @return record containing a FontRecord
1061      */
1062 
1063     protected Record createFont() {
1064         FontRecord retval = new FontRecord();
1065 
1066         retval.setFontHeight(( short ) 0xc8);
1067         retval.setAttributes(( short ) 0x0);
1068         retval.setColorPaletteIndex(( short ) 0x7fff);
1069         retval.setBoldWeight(( short ) 0x190);
1070         retval.setFontNameLength(( byte ) 5);
1071         retval.setFontName("Arial");
1072         return retval;
1073     }
1074 
1075     /**
1076      * Creates a FormatRecord object
1077      * @param id    the number of the format record to create (meaning its position in
1078      *        a file as M$ Excel would create it.)
1079      * @return record containing a FormatRecord
1080      * @see org.apache.poi.hssf.record.FormatRecord
1081      * @see org.apache.poi.hssf.record.Record
1082      */
1083 
1084     protected Record createFormat(int id) {   // we'll need multiple editions for
1085         FormatRecord retval = new FormatRecord();   // the differnt formats
1086 
1087         switch (id) {
1088 
1089             case 0 :
1090                 retval.setIndexCode(( short ) 5);
1091                 retval.setFormatStringLength(( byte ) 0x17);
1092                 retval.setFormatString("\"$\"#,##0_);\\(\"$\"#,##0\\)");
1093                 break;
1094 
1095             case 1 :
1096                 retval.setIndexCode(( short ) 6);
1097                 retval.setFormatStringLength(( byte ) 0x1c);
1098                 retval.setFormatString("\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)");
1099                 break;
1100 
1101             case 2 :
1102                 retval.setIndexCode(( short ) 7);
1103                 retval.setFormatStringLength(( byte ) 0x1d);
1104                 retval.setFormatString("\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)");
1105                 break;
1106 
1107             case 3 :
1108                 retval.setIndexCode(( short ) 8);
1109                 retval.setFormatStringLength(( byte ) 0x22);
1110                 retval.setFormatString(
1111                 "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)");
1112                 break;
1113 
1114             case 4 :
1115                 retval.setIndexCode(( short ) 0x2a);
1116                 retval.setFormatStringLength(( byte ) 0x32);
1117                 retval.setFormatString(
1118                 "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)");
1119                 break;
1120 
1121             case 5 :
1122                 retval.setIndexCode(( short ) 0x29);
1123                 retval.setFormatStringLength(( byte ) 0x29);
1124                 retval.setFormatString(
1125                 "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)");
1126                 break;
1127 
1128             case 6 :
1129                 retval.setIndexCode(( short ) 0x2c);
1130                 retval.setFormatStringLength(( byte ) 0x3a);
1131                 retval.setFormatString(
1132                 "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)");
1133                 break;
1134 
1135             case 7 :
1136                 retval.setIndexCode(( short ) 0x2b);
1137                 retval.setFormatStringLength(( byte ) 0x31);
1138                 retval.setFormatString(
1139                 "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)");
1140                 break;
1141         }
1142         return retval;
1143     }
1144 
1145     /**
1146      * Creates an ExtendedFormatRecord object
1147      * @param id    the number of the extended format record to create (meaning its position in
1148      *        a file as MS Excel would create it.)
1149      *
1150      * @return record containing an ExtendedFormatRecord
1151      * @see org.apache.poi.hssf.record.ExtendedFormatRecord
1152      * @see org.apache.poi.hssf.record.Record
1153      */
1154 
1155     protected Record createExtendedFormat(int id) {   // we'll need multiple editions
1156         ExtendedFormatRecord retval = new ExtendedFormatRecord();
1157 
1158         switch (id) {
1159 
1160             case 0 :
1161                 retval.setFontIndex(( short ) 0);
1162                 retval.setFormatIndex(( short ) 0);
1163                 retval.setCellOptions(( short ) 0xfffffff5);
1164                 retval.setAlignmentOptions(( short ) 0x20);
1165                 retval.setIndentionOptions(( short ) 0);
1166                 retval.setBorderOptions(( short ) 0);
1167                 retval.setPaletteOptions(( short ) 0);
1168                 retval.setAdtlPaletteOptions(( short ) 0);
1169                 retval.setFillPaletteOptions(( short ) 0x20c0);
1170                 break;
1171 
1172             case 1 :
1173                 retval.setFontIndex(( short ) 1);
1174                 retval.setFormatIndex(( short ) 0);
1175                 retval.setCellOptions(( short ) 0xfffffff5);
1176                 retval.setAlignmentOptions(( short ) 0x20);
1177                 retval.setIndentionOptions(( short ) 0xfffff400);
1178                 retval.setBorderOptions(( short ) 0);
1179                 retval.setPaletteOptions(( short ) 0);
1180                 retval.setAdtlPaletteOptions(( short ) 0);
1181                 retval.setFillPaletteOptions(( short ) 0x20c0);
1182                 break;
1183 
1184             case 2 :
1185                 retval.setFontIndex(( short ) 1);
1186                 retval.setFormatIndex(( short ) 0);
1187                 retval.setCellOptions(( short ) 0xfffffff5);
1188                 retval.setAlignmentOptions(( short ) 0x20);
1189                 retval.setIndentionOptions(( short ) 0xfffff400);
1190                 retval.setBorderOptions(( short ) 0);
1191                 retval.setPaletteOptions(( short ) 0);
1192                 retval.setAdtlPaletteOptions(( short ) 0);
1193                 retval.setFillPaletteOptions(( short ) 0x20c0);
1194                 break;
1195 
1196             case 3 :
1197                 retval.setFontIndex(( short ) 2);
1198                 retval.setFormatIndex(( short ) 0);
1199                 retval.setCellOptions(( short ) 0xfffffff5);
1200                 retval.setAlignmentOptions(( short ) 0x20);
1201                 retval.setIndentionOptions(( short ) 0xfffff400);
1202                 retval.setBorderOptions(( short ) 0);
1203                 retval.setPaletteOptions(( short ) 0);
1204                 retval.setAdtlPaletteOptions(( short ) 0);
1205                 retval.setFillPaletteOptions(( short ) 0x20c0);
1206                 break;
1207 
1208             case 4 :
1209                 retval.setFontIndex(( short ) 2);
1210                 retval.setFormatIndex(( short ) 0);
1211                 retval.setCellOptions(( short ) 0xfffffff5);
1212                 retval.setAlignmentOptions(( short ) 0x20);
1213                 retval.setIndentionOptions(( short ) 0xfffff400);
1214                 retval.setBorderOptions(( short ) 0);
1215                 retval.setPaletteOptions(( short ) 0);
1216                 retval.setAdtlPaletteOptions(( short ) 0);
1217                 retval.setFillPaletteOptions(( short ) 0x20c0);
1218                 break;
1219 
1220             case 5 :
1221                 retval.setFontIndex(( short ) 0);
1222                 retval.setFormatIndex(( short ) 0);
1223                 retval.setCellOptions(( short ) 0xfffffff5);
1224                 retval.setAlignmentOptions(( short ) 0x20);
1225                 retval.setIndentionOptions(( short ) 0xfffff400);
1226                 retval.setBorderOptions(( short ) 0);
1227                 retval.setPaletteOptions(( short ) 0);
1228                 retval.setAdtlPaletteOptions(( short ) 0);
1229                 retval.setFillPaletteOptions(( short ) 0x20c0);
1230                 break;
1231 
1232             case 6 :
1233                 retval.setFontIndex(( short ) 0);
1234                 retval.setFormatIndex(( short ) 0);
1235                 retval.setCellOptions(( short ) 0xfffffff5);
1236                 retval.setAlignmentOptions(( short ) 0x20);
1237                 retval.setIndentionOptions(( short ) 0xfffff400);
1238                 retval.setBorderOptions(( short ) 0);
1239                 retval.setPaletteOptions(( short ) 0);
1240                 retval.setAdtlPaletteOptions(( short ) 0);
1241                 retval.setFillPaletteOptions(( short ) 0x20c0);
1242                 break;
1243 
1244             case 7 :
1245                 retval.setFontIndex(( short ) 0);
1246                 retval.setFormatIndex(( short ) 0);
1247                 retval.setCellOptions(( short ) 0xfffffff5);
1248                 retval.setAlignmentOptions(( short ) 0x20);
1249                 retval.setIndentionOptions(( short ) 0xfffff400);
1250                 retval.setBorderOptions(( short ) 0);
1251                 retval.setPaletteOptions(( short ) 0);
1252                 retval.setAdtlPaletteOptions(( short ) 0);
1253                 retval.setFillPaletteOptions(( short ) 0x20c0);
1254                 break;
1255 
1256             case 8 :
1257                 retval.setFontIndex(( short ) 0);
1258                 retval.setFormatIndex(( short ) 0);
1259                 retval.setCellOptions(( short ) 0xfffffff5);
1260                 retval.setAlignmentOptions(( short ) 0x20);
1261                 retval.setIndentionOptions(( short ) 0xfffff400);
1262                 retval.setBorderOptions(( short ) 0);
1263                 retval.setPaletteOptions(( short ) 0);
1264                 retval.setAdtlPaletteOptions(( short ) 0);
1265                 retval.setFillPaletteOptions(( short ) 0x20c0);
1266                 break;
1267 
1268             case 9 :
1269                 retval.setFontIndex(( short ) 0);
1270                 retval.setFormatIndex(( short ) 0);
1271                 retval.setCellOptions(( short ) 0xfffffff5);
1272                 retval.setAlignmentOptions(( short ) 0x20);
1273                 retval.setIndentionOptions(( short ) 0xfffff400);
1274                 retval.setBorderOptions(( short ) 0);
1275                 retval.setPaletteOptions(( short ) 0);
1276                 retval.setAdtlPaletteOptions(( short ) 0);
1277                 retval.setFillPaletteOptions(( short ) 0x20c0);
1278                 break;
1279 
1280             case 10 :
1281                 retval.setFontIndex(( short ) 0);
1282                 retval.setFormatIndex(( short ) 0);
1283                 retval.setCellOptions(( short ) 0xfffffff5);
1284                 retval.setAlignmentOptions(( short ) 0x20);
1285                 retval.setIndentionOptions(( short ) 0xfffff400);
1286                 retval.setBorderOptions(( short ) 0);
1287                 retval.setPaletteOptions(( short ) 0);
1288                 retval.setAdtlPaletteOptions(( short ) 0);
1289                 retval.setFillPaletteOptions(( short ) 0x20c0);
1290                 break;
1291 
1292             case 11 :
1293                 retval.setFontIndex(( short ) 0);
1294                 retval.setFormatIndex(( short ) 0);
1295                 retval.setCellOptions(( short ) 0xfffffff5);
1296                 retval.setAlignmentOptions(( short ) 0x20);
1297                 retval.setIndentionOptions(( short ) 0xfffff400);
1298                 retval.setBorderOptions(( short ) 0);
1299                 retval.setPaletteOptions(( short ) 0);
1300                 retval.setAdtlPaletteOptions(( short ) 0);
1301                 retval.setFillPaletteOptions(( short ) 0x20c0);
1302                 break;
1303 
1304             case 12 :
1305                 retval.setFontIndex(( short ) 0);
1306                 retval.setFormatIndex(( short ) 0);
1307                 retval.setCellOptions(( short ) 0xfffffff5);
1308                 retval.setAlignmentOptions(( short ) 0x20);
1309                 retval.setIndentionOptions(( short ) 0xfffff400);
1310                 retval.setBorderOptions(( short ) 0);
1311                 retval.setPaletteOptions(( short ) 0);
1312                 retval.setAdtlPaletteOptions(( short ) 0);
1313                 retval.setFillPaletteOptions(( short ) 0x20c0);
1314                 break;
1315 
1316             case 13 :
1317                 retval.setFontIndex(( short ) 0);
1318                 retval.setFormatIndex(( short ) 0);
1319                 retval.setCellOptions(( short ) 0xfffffff5);
1320                 retval.setAlignmentOptions(( short ) 0x20);
1321                 retval.setIndentionOptions(( short ) 0xfffff400);
1322                 retval.setBorderOptions(( short ) 0);
1323                 retval.setPaletteOptions(( short ) 0);
1324                 retval.setAdtlPaletteOptions(( short ) 0);
1325                 retval.setFillPaletteOptions(( short ) 0x20c0);
1326                 break;
1327 
1328             case 14 :
1329                 retval.setFontIndex(( short ) 0);
1330                 retval.setFormatIndex(( short ) 0);
1331                 retval.setCellOptions(( short ) 0xfffffff5);
1332                 retval.setAlignmentOptions(( short ) 0x20);
1333                 retval.setIndentionOptions(( short ) 0xfffff400);
1334                 retval.setBorderOptions(( short ) 0);
1335                 retval.setPaletteOptions(( short ) 0);
1336                 retval.setAdtlPaletteOptions(( short ) 0);
1337                 retval.setFillPaletteOptions(( short ) 0x20c0);
1338                 break;
1339 
1340                 // cell records
1341             case 15 :
1342                 retval.setFontIndex(( short ) 0);
1343                 retval.setFormatIndex(( short ) 0);
1344                 retval.setCellOptions(( short ) 0x1);
1345                 retval.setAlignmentOptions(( short ) 0x20);
1346                 retval.setIndentionOptions(( short ) 0x0);
1347                 retval.setBorderOptions(( short ) 0);
1348                 retval.setPaletteOptions(( short ) 0);
1349                 retval.setAdtlPaletteOptions(( short ) 0);
1350                 retval.setFillPaletteOptions(( short ) 0x20c0);
1351                 break;
1352 
1353                 // style
1354             case 16 :
1355                 retval.setFontIndex(( short ) 1);
1356                 retval.setFormatIndex(( short ) 0x2b);
1357                 retval.setCellOptions(( short ) 0xfffffff5);
1358                 retval.setAlignmentOptions(( short ) 0x20);
1359                 retval.setIndentionOptions(( short ) 0xfffff800);
1360                 retval.setBorderOptions(( short ) 0);
1361                 retval.setPaletteOptions(( short ) 0);
1362                 retval.setAdtlPaletteOptions(( short ) 0);
1363                 retval.setFillPaletteOptions(( short ) 0x20c0);
1364                 break;
1365 
1366             case 17 :
1367                 retval.setFontIndex(( short ) 1);
1368                 retval.setFormatIndex(( short ) 0x29);
1369                 retval.setCellOptions(( short ) 0xfffffff5);
1370                 retval.setAlignmentOptions(( short ) 0x20);
1371                 retval.setIndentionOptions(( short ) 0xfffff800);
1372                 retval.setBorderOptions(( short ) 0);
1373                 retval.setPaletteOptions(( short ) 0);
1374                 retval.setAdtlPaletteOptions(( short ) 0);
1375                 retval.setFillPaletteOptions(( short ) 0x20c0);
1376                 break;
1377 
1378             case 18 :
1379                 retval.setFontIndex(( short ) 1);
1380                 retval.setFormatIndex(( short ) 0x2c);
1381                 retval.setCellOptions(( short ) 0xfffffff5);
1382                 retval.setAlignmentOptions(( short ) 0x20);
1383                 retval.setIndentionOptions(( short ) 0xfffff800);
1384                 retval.setBorderOptions(( short ) 0);
1385                 retval.setPaletteOptions(( short ) 0);
1386                 retval.setAdtlPaletteOptions(( short ) 0);
1387                 retval.setFillPaletteOptions(( short ) 0x20c0);
1388                 break;
1389 
1390             case 19 :
1391                 retval.setFontIndex(( short ) 1);
1392                 retval.setFormatIndex(( short ) 0x2a);
1393                 retval.setCellOptions(( short ) 0xfffffff5);
1394                 retval.setAlignmentOptions(( short ) 0x20);
1395                 retval.setIndentionOptions(( short ) 0xfffff800);
1396                 retval.setBorderOptions(( short ) 0);
1397                 retval.setPaletteOptions(( short ) 0);
1398                 retval.setAdtlPaletteOptions(( short ) 0);
1399                 retval.setFillPaletteOptions(( short ) 0x20c0);
1400                 break;
1401 
1402             case 20 :
1403                 retval.setFontIndex(( short ) 1);
1404                 retval.setFormatIndex(( short ) 0x9);
1405                 retval.setCellOptions(( short ) 0xfffffff5);
1406                 retval.setAlignmentOptions(( short ) 0x20);
1407                 retval.setIndentionOptions(( short ) 0xfffff800);
1408                 retval.setBorderOptions(( short ) 0);
1409                 retval.setPaletteOptions(( short ) 0);
1410                 retval.setAdtlPaletteOptions(( short ) 0);
1411                 retval.setFillPaletteOptions(( short ) 0x20c0);
1412                 break;
1413 
1414                 // unused from this point down
1415             case 21 :
1416                 retval.setFontIndex(( short ) 5);
1417                 retval.setFormatIndex(( short ) 0x0);
1418                 retval.setCellOptions(( short ) 0x1);
1419                 retval.setAlignmentOptions(( short ) 0x20);
1420                 retval.setIndentionOptions(( short ) 0x800);
1421                 retval.setBorderOptions(( short ) 0);
1422                 retval.setPaletteOptions(( short ) 0);
1423                 retval.setAdtlPaletteOptions(( short ) 0);
1424                 retval.setFillPaletteOptions(( short ) 0x20c0);
1425                 break;
1426 
1427             case 22 :
1428                 retval.setFontIndex(( short ) 6);
1429                 retval.setFormatIndex(( short ) 0x0);
1430                 retval.setCellOptions(( short ) 0x1);
1431                 retval.setAlignmentOptions(( short ) 0x20);
1432                 retval.setIndentionOptions(( short ) 0x5c00);
1433                 retval.setBorderOptions(( short ) 0);
1434                 retval.setPaletteOptions(( short ) 0);
1435                 retval.setAdtlPaletteOptions(( short ) 0);
1436                 retval.setFillPaletteOptions(( short ) 0x20c0);
1437                 break;
1438 
1439             case 23 :
1440                 retval.setFontIndex(( short ) 0);
1441                 retval.setFormatIndex(( short ) 0x31);
1442                 retval.setCellOptions(( short ) 0x1);
1443                 retval.setAlignmentOptions(( short ) 0x20);
1444                 retval.setIndentionOptions(( short ) 0x5c00);
1445                 retval.setBorderOptions(( short ) 0);
1446                 retval.setPaletteOptions(( short ) 0);
1447                 retval.setAdtlPaletteOptions(( short ) 0);
1448                 retval.setFillPaletteOptions(( short ) 0x20c0);
1449                 break;
1450 
1451             case 24 :
1452                 retval.setFontIndex(( short ) 0);
1453                 retval.setFormatIndex(( short ) 0x8);
1454                 retval.setCellOptions(( short ) 0x1);
1455                 retval.setAlignmentOptions(( short ) 0x20);
1456                 retval.setIndentionOptions(( short ) 0x5c00);
1457                 retval.setBorderOptions(( short ) 0);
1458                 retval.setPaletteOptions(( short ) 0);
1459                 retval.setAdtlPaletteOptions(( short ) 0);
1460                 retval.setFillPaletteOptions(( short ) 0x20c0);
1461                 break;
1462 
1463             case 25 :
1464                 retval.setFontIndex(( short ) 6);
1465                 retval.setFormatIndex(( short ) 0x8);
1466                 retval.setCellOptions(( short ) 0x1);
1467                 retval.setAlignmentOptions(( short ) 0x20);
1468                 retval.setIndentionOptions(( short ) 0x5c00);
1469                 retval.setBorderOptions(( short ) 0);
1470                 retval.setPaletteOptions(( short ) 0);
1471                 retval.setAdtlPaletteOptions(( short ) 0);
1472                 retval.setFillPaletteOptions(( short ) 0x20c0);
1473                 break;
1474         }
1475         return retval;
1476     }
1477 
1478     /**
1479      * creates an default cell type ExtendedFormatRecord object.
1480      * @return ExtendedFormatRecord with intial defaults (cell-type)
1481      */
1482 
1483     protected ExtendedFormatRecord createExtendedFormat() {
1484         ExtendedFormatRecord retval = new ExtendedFormatRecord();
1485 
1486         retval.setFontIndex(( short ) 0);
1487         retval.setFormatIndex(( short ) 0x0);
1488         retval.setCellOptions(( short ) 0x1);
1489         retval.setAlignmentOptions(( short ) 0x20);
1490         retval.setIndentionOptions(( short ) 0);
1491         retval.setBorderOptions(( short ) 0);
1492         retval.setPaletteOptions(( short ) 0);
1493         retval.setAdtlPaletteOptions(( short ) 0);
1494         retval.setFillPaletteOptions(( short ) 0x20c0);
1495         retval.setTopBorderPaletteIdx(HSSFColor.BLACK.index);
1496         retval.setBottomBorderPaletteIdx(HSSFColor.BLACK.index);
1497         retval.setLeftBorderPaletteIdx(HSSFColor.BLACK.index);
1498         retval.setRightBorderPaletteIdx(HSSFColor.BLACK.index);
1499         return retval;
1500     }
1501 
1502     /**
1503      * Creates a StyleRecord object
1504      * @param id        the number of the style record to create (meaning its position in
1505      *                  a file as MS Excel would create it.
1506      * @return record containing a StyleRecord
1507      * @see org.apache.poi.hssf.record.StyleRecord
1508      * @see org.apache.poi.hssf.record.Record
1509      */
1510 
1511     protected Record createStyle(int id) {   // we'll need multiple editions
1512         StyleRecord retval = new StyleRecord();
1513 
1514         switch (id) {
1515 
1516             case 0 :
1517                 retval.setIndex(( short ) 0xffff8010);
1518                 retval.setBuiltin(( byte ) 3);
1519                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
1520                 break;
1521 
1522             case 1 :
1523                 retval.setIndex(( short ) 0xffff8011);
1524                 retval.setBuiltin(( byte ) 6);
1525                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
1526                 break;
1527 
1528             case 2 :
1529                 retval.setIndex(( short ) 0xffff8012);
1530                 retval.setBuiltin(( byte ) 4);
1531                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
1532                 break;
1533 
1534             case 3 :
1535                 retval.setIndex(( short ) 0xffff8013);
1536                 retval.setBuiltin(( byte ) 7);
1537                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
1538                 break;
1539 
1540             case 4 :
1541                 retval.setIndex(( short ) 0xffff8000);
1542                 retval.setBuiltin(( byte ) 0);
1543                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
1544                 break;
1545 
1546             case 5 :
1547                 retval.setIndex(( short ) 0xffff8014);
1548                 retval.setBuiltin(( byte ) 5);
1549                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
1550                 break;
1551         }
1552         return retval;
1553     }
1554 
1555     /**
1556      * Creates the UseSelFS object with the use natural language flag set to 0 (false)
1557      * @return record containing a UseSelFSRecord
1558      * @see org.apache.poi.hssf.record.UseSelFSRecord
1559      * @see org.apache.poi.hssf.record.Record
1560      */
1561 
1562     protected Record createUseSelFS() {
1563         UseSelFSRecord retval = new UseSelFSRecord();
1564 
1565         retval.setFlag(( short ) 0);
1566         return retval;
1567     }
1568 
1569     /**
1570      * create a "bound sheet" or "bundlesheet" (depending who you ask) record
1571      * Always sets the sheet's bof to 0.  You'll need to set that yourself.
1572      * @param id either sheet 0,1 or 2.
1573      * @return record containing a BoundSheetRecord
1574      * @see org.apache.poi.hssf.record.BoundSheetRecord
1575      * @see org.apache.poi.hssf.record.Record
1576      */
1577 
1578     protected Record createBoundSheet(int id) {   // 1,2,3 sheets
1579         BoundSheetRecord retval = new BoundSheetRecord();
1580 
1581         switch (id) {
1582 
1583             case 0 :
1584                 retval.setPositionOfBof(0x0);   // should be set later
1585                 retval.setOptionFlags(( short ) 0);
1586                 retval.setSheetnameLength(( byte ) 0x6);
1587                 retval.setCompressedUnicodeFlag(( byte ) 0);
1588                 retval.setSheetname("Sheet1");
1589                 break;
1590 
1591             case 1 :
1592                 retval.setPositionOfBof(0x0);   // should be set later
1593                 retval.setOptionFlags(( short ) 0);
1594                 retval.setSheetnameLength(( byte ) 0x6);
1595                 retval.setCompressedUnicodeFlag(( byte ) 0);
1596                 retval.setSheetname("Sheet2");
1597                 break;
1598 
1599             case 2 :
1600                 retval.setPositionOfBof(0x0);   // should be set later
1601                 retval.setOptionFlags(( short ) 0);
1602                 retval.setSheetnameLength(( byte ) 0x6);
1603                 retval.setCompressedUnicodeFlag(( byte ) 0);
1604                 retval.setSheetname("Sheet3");
1605                 break;
1606         }
1607         return retval;
1608     }
1609 
1610     /**
1611      * Creates the Country record with the default country set to 1
1612      * and current country set to 7 in case of russian locale ("ru_RU") and 1 otherwise
1613      * @return record containing a CountryRecord
1614      * @see org.apache.poi.hssf.record.CountryRecord
1615      * @see org.apache.poi.hssf.record.Record
1616      */
1617 
1618     protected Record createCountry() {   // what a novel idea, create your own!
1619         CountryRecord retval = new CountryRecord();
1620 
1621         retval.setDefaultCountry(( short ) 1);
1622 
1623         // from Russia with love ;)
1624         if ( Locale.getDefault().toString().equals( "ru_RU" ) ) {
1625 	        retval.setCurrentCountry(( short ) 7);
1626         }
1627         else {
1628 	        retval.setCurrentCountry(( short ) 1);
1629         }
1630 
1631         return retval;
1632     }
1633 
1634     /**
1635      * Creates the SST record with no strings and the unique/num string set to 0
1636      * @return record containing a SSTRecord
1637      * @see org.apache.poi.hssf.record.SSTRecord
1638      * @see org.apache.poi.hssf.record.Record
1639      */
1640 
1641     protected Record createSST() {
1642         return new SSTRecord();
1643     }
1644 
1645     /**
1646      * Creates the ExtendedSST record with numstrings per bucket set to 0x8.  HSSF
1647      * doesn't yet know what to do with this thing, but we create it with nothing in
1648      * it hardly just to make Excel happy and our sheets look like Excel's
1649      *
1650      * @return record containing an ExtSSTRecord
1651      * @see org.apache.poi.hssf.record.ExtSSTRecord
1652      * @see org.apache.poi.hssf.record.Record
1653      */
1654 
1655     protected Record createExtendedSST() {
1656         ExtSSTRecord retval = new ExtSSTRecord();
1657 
1658         retval.setNumStringsPerBucket(( short ) 0x8);
1659         return retval;
1660     }
1661 
1662     /**
1663      * creates the EOF record
1664      * @see org.apache.poi.hssf.record.EOFRecord
1665      * @see org.apache.poi.hssf.record.Record
1666      * @return record containing a EOFRecord
1667      */
1668 
1669     protected Record createEOF() {
1670         return new EOFRecord();
1671     }
1672 
1673     public SheetReferences getSheetReferences() {
1674        SheetReferences refs = new SheetReferences();
1675 
1676        if (externSheet != null) {
1677           for (int k = 0; k < externSheet.getNumOfREFStructures(); k++) {
1678               String sheetName = findSheetNameFromExternSheet((short)k);
1679               refs.addSheetReference(sheetName, k);
1680           }
1681        }
1682        return refs;
1683     }
1684 
1685     /** fins the sheet name by his extern sheet index
1686      * @param num extern sheet index
1687      * @return sheet name
1688      */
1689     public String findSheetNameFromExternSheet(short num){
1690         String result;
1691 
1692         short indexToSheet = externSheet.getREFRecordAt(num).getIndexToFirstSupBook();
1693         result = getSheetName(indexToSheet);
1694 
1695         return result;
1696     }
1697 
1698     /** returns the extern sheet number for specific sheet number ,
1699      *  if this sheet doesn't exist in extern sheet , add it
1700      * @param sheetNumber sheet number
1701      * @return index to extern sheet
1702      */
1703     public short checkExternSheet(int sheetNumber){
1704 
1705         int i = 0;
1706         boolean flag = false;
1707         short result = 0;
1708 
1709         if (externSheet == null) {
1710             externSheet = createExternSheet();
1711         }
1712 
1713         //Trying to find reference to this sheet
1714         while (i < externSheet.getNumOfREFStructures() && !flag){
1715             ExternSheetSubRecord record = externSheet.getREFRecordAt(i);
1716 
1717             if (record.getIndexToFirstSupBook() ==  sheetNumber &&
1718             record.getIndexToLastSupBook() == sheetNumber){
1719                 flag = true;
1720                 result = (short) i;
1721             }
1722 
1723             ++i;
1724         }
1725 
1726         //We Havent found reference to this sheet
1727         if (!flag) {
1728             result = addSheetIndexToExternSheet((short) sheetNumber);
1729         }
1730 
1731         return result;
1732     }
1733 
1734     private short addSheetIndexToExternSheet(short sheetNumber){
1735         short result;
1736 
1737         ExternSheetSubRecord record = new ExternSheetSubRecord();
1738         record.setIndexToFirstSupBook(sheetNumber);
1739         record.setIndexToLastSupBook(sheetNumber);
1740         externSheet.addREFRecord(record);
1741         externSheet.setNumOfREFStructures((short)(externSheet.getNumOfREFStructures() + 1));
1742         result = (short)(externSheet.getNumOfREFStructures() - 1);
1743 
1744         return result;
1745     }
1746 
1747 
1748 
1749     /** gets the total number of names
1750      * @return number of names
1751      */
1752     public int getNumNames(){
1753         int result = names.size();
1754 
1755         return result;
1756     }
1757 
1758     /** gets the name record
1759      * @param index name index
1760      * @return name record
1761      */
1762     public NameRecord getNameRecord(int index){
1763         NameRecord result = (NameRecord) names.get(index);
1764 
1765         return result;
1766 
1767     }
1768 
1769     /** creates new name
1770      * @return new name record
1771      */
1772     public NameRecord createName(){
1773 
1774         NameRecord name = new NameRecord();
1775 
1776         records.add(++namepos, name);
1777         names.add(name);
1778 
1779         return name;
1780     }
1781 
1782     /** removes the name
1783      * @param namenum name index
1784      */
1785     public void removeName(int namenum){
1786         if (names.size() > namenum) {
1787             records.remove(namepos - (names.size() - 1) + namenum);
1788             namepos--;
1789             names.remove(namenum);
1790         }
1791 
1792     }
1793 
1794     /** creates a new extern sheet record
1795      * @return the new extern sheet record
1796      */
1797     protected ExternSheetRecord createExternSheet(){
1798         ExternSheetRecord rec = new ExternSheetRecord();
1799 
1800         records.add(supbookpos + 1 , rec);
1801 
1802         //We also adds the supBook for internal reference
1803         SupBookRecord supbook = new SupBookRecord();
1804 
1805         supbook.setNumberOfSheets((short)getNumSheets());
1806         //supbook.setFlag();
1807 
1808         records.add(supbookpos + 1 , supbook);
1809 
1810         return rec;
1811     }
1812 
1813     /**
1814      * Returns a format index that matches the passed in format.  It does not tie into HSSFDataFormat.
1815      * @param format the format string
1816      * @param createIfNotFound creates a new format if format not found
1817      * @return the format id of a format that matches or -1 if none found and createIfNotFound
1818      */
1819     public short getFormat(String format, boolean createIfNotFound) {
1820 	Iterator iterator;
1821 	for (iterator = formats.iterator(); iterator.hasNext();) {
1822 	    FormatRecord r = (FormatRecord)iterator.next();
1823 	    if (r.getFormatString().equals(format)) {
1824 		return r.getIndexCode();
1825 	    }
1826 	}
1827 
1828 	if (createIfNotFound) {
1829 	    return createFormat(format);
1830 	}
1831 
1832 	return -1;
1833     }
1834 
1835     /**
1836      * Returns the list of FormatRecords in the workbook.
1837      * @return ArrayList of FormatRecords in the notebook
1838      */
1839     public ArrayList getFormats() {
1840 	return formats;
1841     }
1842 
1843     /**
1844      * Creates a FormatRecord, inserts it, and returns the index code.
1845      * @param format the format string
1846      * @return the index code of the format record.
1847      * @see org.apache.poi.hssf.record.FormatRecord
1848      * @see org.apache.poi.hssf.record.Record
1849      */
1850     public short createFormat(String format) {
1851 	FormatRecord rec = new FormatRecord();
1852 	maxformatid = maxformatid >= (short)0xa4 ? (short)(maxformatid + 1) : (short)0xa4; //Starting value from M$ empiracle study.
1853 	rec.setIndexCode(maxformatid);
1854 	rec.setFormatStringLength((byte)format.length());
1855 	rec.setFormatString(format);
1856 
1857 	int pos = 0;
1858 	while (pos < records.size() && ((Record)records.get(pos)).getSid() != FormatRecord.sid) 
1859 	    pos++;
1860 	pos += formats.size();
1861 	formats.add(rec);
1862 	records.add(pos, rec);
1863 	return maxformatid;
1864      }
1865 
1866 
1867     /**
1868      * Returns the first occurance of a record matching a particular sid.
1869      */
1870 
1871     public Record findFirstRecordBySid(short sid) {
1872         for (Iterator iterator = records.iterator(); iterator.hasNext(); ) {
1873             Record record = ( Record ) iterator.next();
1874             
1875             if (record.getSid() == sid) {
1876                 return record;
1877             }
1878         }
1879         return null;
1880     }
1881 
1882     /**
1883      * Returns the next occurance of a record matching a particular sid.
1884      */
1885     public Record findNextRecordBySid(short sid, int pos) {
1886         Iterator iterator = records.iterator();
1887 	for (;pos > 0 && iterator.hasNext(); iterator.next(),pos--);
1888 	while (iterator.hasNext()) {
1889             Record record = ( Record ) iterator.next();
1890 
1891             if (record.getSid() == sid) {
1892                 return record;
1893             }
1894         }
1895         return null;
1896     }
1897 
1898     public List getRecords()
1899     {
1900         return records;
1901     }
1902 }
1903