Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache » poi » hssf » model » [javadoc | source]
    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
    8   
    9          http://www.apache.org/licenses/LICENSE-2.0
   10   
   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   ==================================================================== */
   17   
   18   
   19   package org.apache.poi.hssf.model;
   20   
   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;
   27   
   28   import java.util.ArrayList;
   29   import java.util.Iterator;
   30   import java.util.List;
   31   import java.util.Locale;
   32   
   33   /**
   34    * Low level model implementation of a Workbook.  Provides creational methods
   35    * for settings and objects contained in the workbook object.
   36    * <P>
   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.
   39    * <P>
   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.
   45    *
   46    *
   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
   55    * @version 1.0-pre
   56    */
   57   
   58   public class Workbook implements Model
   59   {
   60       private static final int   DEBUG       = POILogger.DEBUG;
   61   
   62   //    public static Workbook currentBook = null;
   63   
   64       /**
   65        * constant used to set the "codepage" wherever "codepage" is set in records
   66        * (which is duplciated in more than one record)
   67        */
   68   
   69       private final static short CODEPAGE    = ( short ) 0x4b0;
   70   
   71       /**
   72        * this contains the Worksheet record objects
   73        */
   74       protected WorkbookRecordList        records     = new WorkbookRecordList();
   75   
   76       /**
   77        * this contains a reference to the SSTRecord so that new stings can be added
   78        * to it.
   79        */
   80       protected SSTRecord        sst         = null;
   81   
   82   
   83       private LinkTable linkTable; // optionally occurs if there are  references in the document. (4.10.3)
   84   
   85       /**
   86        * holds the "boundsheet" records (aka bundlesheet) so that they can have their
   87        * reference to their "BOF" marker
   88        */
   89       protected ArrayList        boundsheets = new ArrayList();
   90   
   91       protected ArrayList        formats = new ArrayList();
   92   
   93       protected ArrayList        hyperlinks = new ArrayList();
   94   
   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;
  105   
  106       private static POILogger   log = POILogFactory.getLogger(Workbook.class);
  107   
  108       /**
  109        * Creates new Workbook with no intitialization --useless right now
  110        * @see #createWorkbook(List)
  111        */
  112       public Workbook() {
  113       }
  114   
  115       /**
  116        * read support  for low level
  117        * API.  Pass in an array of Record objects, A Workbook
  118        * object is constructed and passed back with all of its initialization set
  119        * to the passed in records and references to those records held. Unlike Sheet
  120        * workbook does not use an offset (its assumed to be 0) since its first in a file.
  121        * If you need an offset then construct a new array with a 0 offset or write your
  122        * own ;-p.
  123        *
  124        * @param recs an array of Record objects
  125        * @return Workbook object
  126        */
  127       public static Workbook createWorkbook(List recs) {
  128           if (log.check( POILogger.DEBUG ))
  129               log.log(DEBUG, "Workbook (readfile) created with reclen=",
  130                       new Integer(recs.size()));
  131           Workbook  retval  = new Workbook();
  132           ArrayList records = new ArrayList(recs.size() / 3);
  133           retval.records.setRecords(records);
  134   
  135           int k;
  136           for (k = 0; k < recs.size(); k++) {
  137               Record rec = ( Record ) recs.get(k);
  138   
  139               if (rec.getSid() == EOFRecord.sid) {
  140                   records.add(rec);
  141                   if (log.check( POILogger.DEBUG ))
  142                       log.log(DEBUG, "found workbook eof record at " + k);
  143                   break;
  144               }
  145               switch (rec.getSid()) {
  146   
  147                   case BoundSheetRecord.sid :
  148                       if (log.check( POILogger.DEBUG ))
  149                           log.log(DEBUG, "found boundsheet record at " + k);
  150                       retval.boundsheets.add(rec);
  151                       retval.records.setBspos( k );
  152                       break;
  153   
  154                   case SSTRecord.sid :
  155                       if (log.check( POILogger.DEBUG ))
  156                           log.log(DEBUG, "found sst record at " + k);
  157                       retval.sst = ( SSTRecord ) rec;
  158                       break;
  159   
  160                   case FontRecord.sid :
  161                       if (log.check( POILogger.DEBUG ))
  162                           log.log(DEBUG, "found font record at " + k);
  163                       retval.records.setFontpos( k );
  164                       retval.numfonts++;
  165                       break;
  166   
  167                   case ExtendedFormatRecord.sid :
  168                       if (log.check( POILogger.DEBUG ))
  169                           log.log(DEBUG, "found XF record at " + k);
  170                       retval.records.setXfpos( k );
  171                       retval.numxfs++;
  172                       break;
  173   
  174                   case TabIdRecord.sid :
  175                       if (log.check( POILogger.DEBUG ))
  176                           log.log(DEBUG, "found tabid record at " + k);
  177                       retval.records.setTabpos( k );
  178                       break;
  179   
  180                   case ProtectRecord.sid :
  181                       if (log.check( POILogger.DEBUG ))
  182                           log.log(DEBUG, "found protect record at " + k);
  183                       retval.records.setProtpos( k );
  184                       break;
  185   
  186                   case BackupRecord.sid :
  187                       if (log.check( POILogger.DEBUG ))
  188                           log.log(DEBUG, "found backup record at " + k);
  189                       retval.records.setBackuppos( k );
  190                       break;
  191                   case ExternSheetRecord.sid :
  192                       throw new RuntimeException("Extern sheet is part of LinkTable");
  193                   case NameRecord.sid :
  194                   case SupBookRecord.sid :
  195                       // LinkTable can start with either of these
  196                       if (log.check( POILogger.DEBUG ))
  197                           log.log(DEBUG, "found SupBook record at " + k);
  198                       retval.linkTable = new LinkTable(recs, k, retval.records);
  199                       k+=retval.linkTable.getRecordCount() - 1;
  200                       continue;
  201                   case FormatRecord.sid :
  202                       if (log.check( POILogger.DEBUG ))
  203                           log.log(DEBUG, "found format record at " + k);
  204                       retval.formats.add(rec);
  205                       retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode();
  206                       break;
  207                   case DateWindow1904Record.sid :
  208                       if (log.check( POILogger.DEBUG ))
  209                           log.log(DEBUG, "found datewindow1904 record at " + k);
  210                       retval.uses1904datewindowing = ((DateWindow1904Record)rec).getWindowing() == 1;
  211                       break;
  212                   case PaletteRecord.sid:
  213                       if (log.check( POILogger.DEBUG ))
  214                           log.log(DEBUG, "found palette record at " + k);
  215                       retval.records.setPalettepos( k );
  216                       break;
  217                   case WindowOneRecord.sid:
  218                       if (log.check( POILogger.DEBUG ))
  219                           log.log(DEBUG, "found WindowOneRecord at " + k);
  220                       retval.windowOne = (WindowOneRecord) rec; 
  221                       break;
  222                   case WriteAccessRecord.sid: 
  223                       if (log.check( POILogger.DEBUG ))
  224                           log.log(DEBUG, "found WriteAccess at " + k);
  225                       retval.writeAccess = (WriteAccessRecord) rec;
  226                       break;
  227                   case WriteProtectRecord.sid: 
  228                       if (log.check( POILogger.DEBUG ))
  229                           log.log(DEBUG, "found WriteProtect at " + k);
  230                       retval.writeProtect = (WriteProtectRecord) rec;
  231                       break;
  232                   case FileSharingRecord.sid: 
  233                       if (log.check( POILogger.DEBUG ))
  234                           log.log(DEBUG, "found FileSharing at " + k);
  235                       retval.fileShare = (FileSharingRecord) rec;
  236                   default :
  237               }
  238               records.add(rec);
  239           }
  240           //What if we dont have any ranges and supbooks
  241           //        if (retval.records.supbookpos == 0) {
  242           //            retval.records.supbookpos = retval.records.bspos + 1;
  243           //            retval.records.namepos    = retval.records.supbookpos + 1;
  244           //        }
  245           
  246           // Look for other interesting values that
  247           //  follow the EOFRecord
  248           for ( ; k < recs.size(); k++) {
  249               Record rec = ( Record ) recs.get(k);
  250               switch (rec.getSid()) {
  251               	case HyperlinkRecord.sid:
  252               		retval.hyperlinks.add(rec);
  253               		break;
  254               }
  255           }
  256           
  257           if (retval.windowOne == null) {
  258               retval.windowOne = (WindowOneRecord) retval.createWindowOne();
  259           }
  260           if (log.check( POILogger.DEBUG ))
  261               log.log(DEBUG, "exit create workbook from existing file function");
  262           return retval;
  263       }
  264   
  265       /**
  266        * Creates an empty workbook object with three blank sheets and all the empty
  267        * fields.  Use this to create a workbook from scratch.
  268        */
  269       public static Workbook createWorkbook()
  270       {
  271           if (log.check( POILogger.DEBUG ))
  272               log.log( DEBUG, "creating new workbook from scratch" );
  273           Workbook retval = new Workbook();
  274           ArrayList records = new ArrayList( 30 );
  275           retval.records.setRecords(records);
  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.records.setTabpos( records.size() - 1 );
  287           records.add( retval.createFnGroupCount() );
  288           records.add( retval.createWindowProtect() );
  289           records.add( retval.createProtect() );
  290           retval.records.setProtpos( records.size() - 1 );
  291           records.add( retval.createPassword() );
  292           records.add( retval.createProtectionRev4() );
  293           records.add( retval.createPasswordRev4() );
  294           retval.windowOne = (WindowOneRecord) retval.createWindowOne();
  295           records.add( retval.windowOne );
  296           records.add( retval.createBackup() );
  297           retval.records.setBackuppos( records.size() - 1 );
  298           records.add( retval.createHideObj() );
  299           records.add( retval.createDateWindow1904() );
  300           records.add( retval.createPrecision() );
  301           records.add( retval.createRefreshAll() );
  302           records.add( retval.createBookBool() );
  303           records.add( retval.createFont() );
  304           records.add( retval.createFont() );
  305           records.add( retval.createFont() );
  306           records.add( retval.createFont() );
  307           retval.records.setFontpos( records.size() - 1 );   // last font record postion
  308           retval.numfonts = 4;
  309   
  310           // set up format records
  311           for ( int i = 0; i <= 7; i++ )
  312           {
  313               Record rec;
  314               rec = retval.createFormat( i );
  315               retval.maxformatid = retval.maxformatid >= ( (FormatRecord) rec ).getIndexCode() ? retval.maxformatid : ( (FormatRecord) rec ).getIndexCode();
  316               formats.add( rec );
  317               records.add( rec );
  318           }
  319           retval.formats = formats;
  320   
  321           for ( int k = 0; k < 21; k++ )
  322           {
  323               records.add( retval.createExtendedFormat( k ) );
  324               retval.numxfs++;
  325           }
  326           retval.records.setXfpos( records.size() - 1 );
  327           for ( int k = 0; k < 6; k++ )
  328           {
  329               records.add( retval.createStyle( k ) );
  330           }
  331           records.add( retval.createUseSelFS() );
  332   
  333           int nBoundSheets = 1; // now just do 1
  334           for ( int k = 0; k < nBoundSheets; k++ ) {   
  335               BoundSheetRecord bsr =
  336                       (BoundSheetRecord) retval.createBoundSheet( k );
  337   
  338               records.add( bsr );
  339               retval.boundsheets.add( bsr );
  340               retval.records.setBspos( records.size() - 1 );
  341           }
  342   //        retval.records.supbookpos = retval.records.bspos + 1;
  343   //        retval.records.namepos = retval.records.supbookpos + 2;
  344           records.add( retval.createCountry() );
  345           for ( int k = 0; k < nBoundSheets; k++ ) {   
  346               retval.getOrCreateLinkTable().checkExternSheet(k);
  347           }
  348           retval.sst = (SSTRecord) retval.createSST();
  349           records.add( retval.sst );
  350           records.add( retval.createExtendedSST() );
  351   
  352           records.add( retval.createEOF() );
  353           if (log.check( POILogger.DEBUG ))
  354               log.log( DEBUG, "exit create new workbook from scratch" );
  355           return retval;
  356       }
  357   
  358   
  359   	/**Retrieves the Builtin NameRecord that matches the name and index
  360   	 * There shouldn't be too many names to make the sequential search too slow
  361   	 * @param name byte representation of the builtin name to match
  362   	 * @param sheetIndex Index to match
  363   	 * @return null if no builtin NameRecord matches
  364   	 */
  365       public NameRecord getSpecificBuiltinRecord(byte name, int sheetIndex)
  366       {
  367           return getOrCreateLinkTable().getSpecificBuiltinRecord(name, sheetIndex);
  368       }
  369   
  370   	/**
  371   	 * Removes the specified Builtin NameRecord that matches the name and index
  372   	 * @param name byte representation of the builtin to match
  373   	 * @param sheetIndex zero-based sheet reference
  374   	 */
  375       public void removeBuiltinRecord(byte name, int sheetIndex) {
  376           linkTable.removeBuiltinRecord(name, sheetIndex);
  377           // TODO - do we need "this.records.remove(...);" similar to that in this.removeName(int namenum) {}?
  378       }
  379   
  380       public int getNumRecords() {
  381           return records.size();
  382       }
  383   
  384       /**
  385        * gets the font record at the given index in the font table.  Remember
  386        * "There is No Four" (someone at M$ must have gone to Rocky Horror one too
  387        * many times)
  388        *
  389        * @param idx the index to look at (0 or greater but NOT 4)
  390        * @return FontRecord located at the given index
  391        */
  392   
  393       public FontRecord getFontRecordAt(int idx) {
  394           int index = idx;
  395   
  396           if (index > 4) {
  397               index -= 1;   // adjust for "There is no 4"
  398           }
  399           if (index > (numfonts - 1)) {
  400               throw new ArrayIndexOutOfBoundsException(
  401               "There are only " + numfonts
  402               + " font records, you asked for " + idx);
  403           }
  404           FontRecord retval =
  405           ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + index);
  406   
  407           return retval;
  408       }
  409   
  410       /**
  411        * creates a new font record and adds it to the "font table".  This causes the
  412        * boundsheets to move down one, extended formats to move down (so this function moves
  413        * those pointers as well)
  414        *
  415        * @return FontRecord that was just created
  416        */
  417   
  418       public FontRecord createNewFont() {
  419           FontRecord rec = ( FontRecord ) createFont();
  420   
  421           records.add(records.getFontpos()+1, rec);
  422           records.setFontpos( records.getFontpos() + 1 );
  423           numfonts++;
  424           return rec;
  425       }
  426   
  427       /**
  428        * gets the number of font records
  429        *
  430        * @return   number of font records in the "font table"
  431        */
  432   
  433       public int getNumberOfFontRecords() {
  434           return numfonts;
  435       }
  436   
  437       /**
  438        * Sets the BOF for a given sheet
  439        *
  440        * @param sheetnum the number of the sheet to set the positing of the bof for
  441        * @param pos the actual bof position
  442        */
  443   
  444       public void setSheetBof(int sheetnum, int pos) {
  445           if (log.check( POILogger.DEBUG ))
  446               log.log(DEBUG, "setting bof for sheetnum =", new Integer(sheetnum),
  447                   " at pos=", new Integer(pos));
  448           checkSheets(sheetnum);
  449           (( BoundSheetRecord ) boundsheets.get(sheetnum))
  450           .setPositionOfBof(pos);
  451       }
  452   
  453       /**
  454        * Returns the position of the backup record.
  455        */
  456   
  457       public BackupRecord getBackupRecord() {
  458           return ( BackupRecord ) records.get(records.getBackuppos());
  459       }
  460   
  461   
  462       /**
  463        * sets the name for a given sheet.  If the boundsheet record doesn't exist and
  464        * its only one more than we have, go ahead and create it.  If its > 1 more than
  465        * we have, except
  466        *
  467        * @param sheetnum the sheet number (0 based)
  468        * @param sheetname the name for the sheet
  469        */
  470       public void setSheetName(int sheetnum, String sheetname ) {
  471           checkSheets(sheetnum);
  472           BoundSheetRecord sheet = (BoundSheetRecord)boundsheets.get( sheetnum );
  473           sheet.setSheetname(sheetname);
  474           sheet.setSheetnameLength( (byte)sheetname.length() );
  475       }
  476   
  477       /**
  478        * Determines whether a workbook contains the provided sheet name.
  479        *
  480        * @param name the name to test (case insensitive match)
  481        * @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check.
  482        * @return true if the sheet contains the name, false otherwise.
  483        */
  484       public boolean doesContainsSheetName( String name, int excludeSheetIdx )
  485       {
  486           for ( int i = 0; i < boundsheets.size(); i++ )
  487           {
  488               BoundSheetRecord boundSheetRecord = (BoundSheetRecord) boundsheets.get( i );
  489               if (excludeSheetIdx != i && name.equalsIgnoreCase(boundSheetRecord.getSheetname()))
  490                   return true;
  491           }
  492           return false;
  493       }
  494   
  495       /**
  496        * sets the name for a given sheet forcing the encoding. This is STILL A BAD IDEA.
  497        * Poi now automatically detects unicode
  498        *
  499        *@deprecated 3-Jan-06 Simply use setSheetNam e(int sheetnum, String sheetname)
  500        * @param sheetnum the sheet number (0 based)
  501        * @param sheetname the name for the sheet
  502        */    
  503       public void setSheetName(int sheetnum, String sheetname, short encoding ) {
  504           checkSheets(sheetnum);
  505           BoundSheetRecord sheet = (BoundSheetRecord)boundsheets.get( sheetnum );
  506           sheet.setSheetname(sheetname);
  507           sheet.setSheetnameLength( (byte)sheetname.length() );
  508   		sheet.setCompressedUnicodeFlag( (byte)encoding );
  509       }
  510       
  511       /**
  512   	 * sets the order of appearance for a given sheet.
  513   	 *
  514   	 * @param sheetname the name of the sheet to reorder
  515   	 * @param pos the position that we want to insert the sheet into (0 based)
  516   	 */
  517       
  518       public void setSheetOrder(String sheetname, int pos ) {
  519   	int sheetNumber = getSheetIndex(sheetname);
  520   	//remove the sheet that needs to be reordered and place it in the spot we want
  521   	boundsheets.add(pos, boundsheets.remove(sheetNumber));	
  522       }
  523   
  524       /**
  525        * gets the name for a given sheet.
  526        *
  527        * @param sheetnum the sheet number (0 based)
  528        * @return sheetname the name for the sheet
  529        */
  530   
  531       public String getSheetName(int sheetnum) {
  532           return (( BoundSheetRecord ) boundsheets.get(sheetnum))
  533           .getSheetname();
  534       }
  535   
  536       /**
  537        * gets the hidden flag for a given sheet.
  538        *
  539        * @param sheetnum the sheet number (0 based)
  540        * @return True if sheet is hidden
  541        */
  542   
  543       public boolean isSheetHidden(int sheetnum) {
  544           BoundSheetRecord bsr = ( BoundSheetRecord ) boundsheets.get(sheetnum);
  545           return bsr.isHidden();
  546       }
  547   
  548       /**
  549        * Hide or unhide a sheet
  550        * 
  551        * @param sheetnum The sheet number
  552        * @param hidden True to mark the sheet as hidden, false otherwise
  553        */
  554       
  555       public void setSheetHidden(int sheetnum, boolean hidden) {
  556           BoundSheetRecord bsr = ( BoundSheetRecord ) boundsheets.get(sheetnum);
  557           bsr.setHidden(hidden);
  558       }
  559       /**
  560        * get the sheet's index
  561        * @param name  sheet name
  562        * @return sheet index or -1 if it was not found.
  563        */
  564   
  565       public int getSheetIndex(String name) {
  566           int retval = -1;
  567   
  568           for (int k = 0; k < boundsheets.size(); k++) {
  569               String sheet = getSheetName(k);
  570   
  571               if (sheet.equalsIgnoreCase(name)) {
  572                   retval = k;
  573                   break;
  574               }
  575           }
  576           return retval;
  577       }
  578   
  579       /**
  580        * if we're trying to address one more sheet than we have, go ahead and add it!  if we're
  581        * trying to address >1 more than we have throw an exception!
  582        */
  583   
  584       private void checkSheets(int sheetnum) {
  585           if ((boundsheets.size()) <= sheetnum) {   // if we're short one add another..
  586               if ((boundsheets.size() + 1) <= sheetnum) {
  587                   throw new RuntimeException("Sheet number out of bounds!");
  588               }
  589               BoundSheetRecord bsr = (BoundSheetRecord ) createBoundSheet(sheetnum);
  590   
  591               records.add(records.getBspos()+1, bsr);
  592               records.setBspos( records.getBspos() + 1 );
  593               boundsheets.add(bsr);
  594               getOrCreateLinkTable().checkExternSheet(sheetnum);
  595               fixTabIdRecord();
  596           }
  597       }
  598   
  599       public void removeSheet(int sheetnum) {
  600           if (boundsheets.size() > sheetnum) {
  601               records.remove(records.getBspos() - (boundsheets.size() - 1) + sheetnum);
  602   //            records.bspos--;
  603               boundsheets.remove(sheetnum);
  604               fixTabIdRecord();
  605           }
  606           
  607           // Within NameRecords, it's ok to have the formula
  608           //  part point at deleted sheets. It's also ok to
  609           //  have the ExternSheetNumber point at deleted
  610           //  sheets. 
  611           // However, the sheet index must be adjusted, or
  612           //  excel will break. (Sheet index is either 0 for
  613           //  global, or 1 based index to sheet)
  614           int sheetNum1Based = sheetnum + 1;
  615           for(int i=0; i<getNumNames(); i++) {
  616           	NameRecord nr = getNameRecord(i);
  617           	
  618           	if(nr.getIndexToSheet() == sheetNum1Based) {
  619           		// Excel re-writes these to point to no sheet
  620           		nr.setEqualsToIndexToSheet((short)0);
  621           	} else if(nr.getIndexToSheet() > sheetNum1Based) {
  622           		// Bump down by one, so still points
  623           		//  at the same sheet
  624           		nr.setEqualsToIndexToSheet((short)(
  625           				nr.getEqualsToIndexToSheet()-1
  626           		));
  627           	}
  628           }
  629       }
  630   
  631       /**
  632        * make the tabid record look like the current situation.
  633        *
  634        */
  635       private void fixTabIdRecord() {
  636           TabIdRecord tir = ( TabIdRecord ) records.get(records.getTabpos());
  637           short[]     tia = new short[ boundsheets.size() ];
  638   
  639           for (short k = 0; k < tia.length; k++) {
  640               tia[ k ] = k;
  641           }
  642           tir.setTabIdArray(tia);
  643       }
  644   
  645       /**
  646        * returns the number of boundsheet objects contained in this workbook.
  647        *
  648        * @return number of BoundSheet records
  649        */
  650   
  651       public int getNumSheets() {
  652           if (log.check( POILogger.DEBUG ))
  653               log.log(DEBUG, "getNumSheets=", new Integer(boundsheets.size()));
  654           return boundsheets.size();
  655       }
  656   
  657       /**
  658        * get the number of ExtendedFormat records contained in this workbook.
  659        *
  660        * @return int count of ExtendedFormat records
  661        */
  662   
  663       public int getNumExFormats() {
  664           if (log.check( POILogger.DEBUG ))
  665               log.log(DEBUG, "getXF=", new Integer(numxfs));
  666           return numxfs;
  667       }
  668   
  669       /**
  670        * gets the ExtendedFormatRecord at the given 0-based index
  671        *
  672        * @param index of the Extended format record (0-based)
  673        * @return ExtendedFormatRecord at the given index
  674        */
  675   
  676       public ExtendedFormatRecord getExFormatAt(int index) {
  677           int xfptr = records.getXfpos() - (numxfs - 1);
  678   
  679           xfptr += index;
  680           ExtendedFormatRecord retval =
  681           ( ExtendedFormatRecord ) records.get(xfptr);
  682   
  683           return retval;
  684       }
  685   
  686       /**
  687        * creates a new Cell-type Extneded Format Record and adds it to the end of
  688        *  ExtendedFormatRecords collection
  689        *
  690        * @return ExtendedFormatRecord that was created
  691        */
  692   
  693       public ExtendedFormatRecord createCellXF() {
  694           ExtendedFormatRecord xf = createExtendedFormat();
  695   
  696           records.add(records.getXfpos()+1, xf);
  697           records.setXfpos( records.getXfpos() + 1 );
  698           numxfs++;
  699           return xf;
  700       }
  701   
  702       /**
  703        * Adds a string to the SST table and returns its index (if its a duplicate
  704        * just returns its index and update the counts) ASSUMES compressed unicode
  705        * (meaning 8bit)
  706        *
  707        * @param string the string to be added to the SSTRecord
  708        *
  709        * @return index of the string within the SSTRecord
  710        */
  711   
  712       public int addSSTString(UnicodeString string) {
  713           if (log.check( POILogger.DEBUG ))
  714             log.log(DEBUG, "insert to sst string='", string);
  715           if (sst == null) {
  716               insertSST();
  717           }
  718         return sst.addString(string);
  719       }
  720   
  721       /**
  722        * given an index into the SST table, this function returns the corresponding String value
  723        * @return String containing the SST String
  724        */
  725   
  726       public UnicodeString getSSTString(int str) {
  727           if (sst == null) {
  728               insertSST();
  729           }
  730           UnicodeString retval = sst.getString(str);
  731   
  732           if (log.check( POILogger.DEBUG ))
  733               log.log(DEBUG, "Returning SST for index=", new Integer(str),
  734                   " String= ", retval);
  735           return retval;
  736       }
  737   
  738       /**
  739        * use this function to add a Shared String Table to an existing sheet (say
  740        * generated by a different java api) without an sst....
  741        * @see #createSST()
  742        * @see org.apache.poi.hssf.record.SSTRecord
  743        */
  744   
  745       public void insertSST() {
  746           if (log.check( POILogger.DEBUG ))
  747               log.log(DEBUG, "creating new SST via insertSST!");
  748           sst = ( SSTRecord ) createSST();
  749           records.add(records.size() - 1, createExtendedSST());
  750           records.add(records.size() - 2, sst);
  751       }
  752   
  753       /**
  754        * Serializes all records int the worksheet section into a big byte array. Use
  755        * this to write the Workbook out.
  756        *
  757        * @return byte array containing the HSSF-only portions of the POIFS file.
  758        */
  759        // GJS: Not used so why keep it.
  760   //    public byte [] serialize() {
  761   //        log.log(DEBUG, "Serializing Workbook!");
  762   //        byte[] retval    = null;
  763   //
  764   ////         ArrayList bytes     = new ArrayList(records.size());
  765   //        int    arraysize = getSize();
  766   //        int    pos       = 0;
  767   //
  768   //        retval = new byte[ arraysize ];
  769   //        for (int k = 0; k < records.size(); k++) {
  770   //
  771   //            Record record = records.get(k);
  772   ////             Let's skip RECALCID records, as they are only use for optimization
  773   //	    if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) {
  774   //                pos += record.serialize(pos, retval);   // rec.length;
  775   //	    }
  776   //        }
  777   //        log.log(DEBUG, "Exiting serialize workbook");
  778   //        return retval;
  779   //    }
  780   
  781       /**
  782        * Serializes all records int the worksheet section into a big byte array. Use
  783        * this to write the Workbook out.
  784        * @param offset of the data to be written
  785        * @param data array of bytes to write this to
  786        */
  787   
  788       public int serialize( int offset, byte[] data )
  789       {
  790           if (log.check( POILogger.DEBUG ))
  791               log.log( DEBUG, "Serializing Workbook with offsets" );
  792   
  793           int pos = 0;
  794   
  795           SSTRecord sst = null;
  796           int sstPos = 0;
  797           boolean wroteBoundSheets = false;
  798           for ( int k = 0; k < records.size(); k++ )
  799           {
  800   
  801               Record record = records.get( k );
  802               // Let's skip RECALCID records, as they are only use for optimization
  803               if ( record.getSid() != RecalcIdRecord.sid || ( (RecalcIdRecord) record ).isNeeded() )
  804               {
  805                   int len = 0; 
  806                   if (record instanceof SSTRecord)
  807                   {
  808                       sst = (SSTRecord)record;
  809                       sstPos = pos;
  810                   }
  811                   if (record.getSid() == ExtSSTRecord.sid && sst != null)
  812                   {
  813                       record = sst.createExtSSTRecord(sstPos + offset);
  814                   }
  815                   if (record instanceof BoundSheetRecord) {
  816                        if(!wroteBoundSheets) {
  817                           for (int i = 0; i < boundsheets.size(); i++) {
  818                               len+= ((BoundSheetRecord)boundsheets.get(i))
  819                                                .serialize(pos+offset+len, data);
  820                           }
  821                           wroteBoundSheets = true;
  822                        }
  823                   } else {
  824                      len = record.serialize( pos + offset, data );
  825                   }
  826                   /////  DEBUG BEGIN /////
  827   //                if (len != record.getRecordSize())
  828   //                    throw new IllegalStateException("Record size does not match serialized bytes.  Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize());
  829                   /////  DEBUG END /////
  830                   pos += len;   // rec.length;
  831               }
  832           }
  833           if (log.check( POILogger.DEBUG ))
  834               log.log( DEBUG, "Exiting serialize workbook" );
  835           return pos;
  836       }
  837   
  838       public int getSize()
  839       {
  840           int retval = 0;
  841   
  842           SSTRecord sst = null;
  843           for ( int k = 0; k < records.size(); k++ )
  844           {
  845               Record record = records.get( k );
  846               // Let's skip RECALCID records, as they are only use for optimization
  847               if ( record.getSid() != RecalcIdRecord.sid || ( (RecalcIdRecord) record ).isNeeded() )
  848               {
  849                   if (record instanceof SSTRecord)
  850                       sst = (SSTRecord)record;
  851                   if (record.getSid() == ExtSSTRecord.sid && sst != null)
  852                       retval += sst.calcExtSSTRecordSize();
  853                   else
  854                       retval += record.getRecordSize();
  855               }
  856           }
  857           return retval;
  858       }
  859   
  860       /**
  861        * creates the BOF record
  862        * @see org.apache.poi.hssf.record.BOFRecord
  863        * @see org.apache.poi.hssf.record.Record
  864        * @return record containing a BOFRecord
  865        */
  866   
  867       protected Record createBOF() {
  868           BOFRecord retval = new BOFRecord();
  869   
  870           retval.setVersion(( short ) 0x600);
  871           retval.setType(( short ) 5);
  872           retval.setBuild(( short ) 0x10d3);
  873   
  874           //        retval.setBuild((short)0x0dbb);
  875           retval.setBuildYear(( short ) 1996);
  876           retval.setHistoryBitMask(0x41);   // was c1 before verify
  877           retval.setRequiredVersion(0x6);
  878           return retval;
  879       }
  880   
  881       /**
  882        * creates the InterfaceHdr record
  883        * @see org.apache.poi.hssf.record.InterfaceHdrRecord
  884        * @see org.apache.poi.hssf.record.Record
  885        * @return record containing a InterfaceHdrRecord
  886        */
  887   
  888       protected Record createInterfaceHdr() {
  889           InterfaceHdrRecord retval = new InterfaceHdrRecord();
  890   
  891           retval.setCodepage(CODEPAGE);
  892           return retval;
  893       }
  894   
  895       /**
  896        * creates an MMS record
  897        * @see org.apache.poi.hssf.record.MMSRecord
  898        * @see org.apache.poi.hssf.record.Record
  899        * @return record containing a MMSRecord
  900        */
  901   
  902       protected Record createMMS() {
  903           MMSRecord retval = new MMSRecord();
  904   
  905           retval.setAddMenuCount(( byte ) 0);
  906           retval.setDelMenuCount(( byte ) 0);
  907           return retval;
  908       }
  909   
  910       /**
  911        * creates the InterfaceEnd record
  912        * @see org.apache.poi.hssf.record.InterfaceEndRecord
  913        * @see org.apache.poi.hssf.record.Record
  914        * @return record containing a InterfaceEndRecord
  915        */
  916   
  917       protected Record createInterfaceEnd() {
  918           return new InterfaceEndRecord();
  919       }
  920   
  921       /**
  922        * creates the WriteAccess record containing the logged in user's name
  923        * @see org.apache.poi.hssf.record.WriteAccessRecord
  924        * @see org.apache.poi.hssf.record.Record
  925        * @return record containing a WriteAccessRecord
  926        */
  927   
  928       protected Record createWriteAccess() {
  929           WriteAccessRecord retval = new WriteAccessRecord();
  930   
  931           try
  932           {
  933               retval.setUsername(System.getProperty("user.name"));
  934           }
  935           catch (java.security.AccessControlException e)
  936           {
  937                   // AccessControlException can occur in a restricted context
  938                   // (client applet/jws application or restricted security server)
  939                   retval.setUsername("POI");
  940           }
  941           return retval;
  942       }
  943   
  944       /**
  945        * creates the Codepage record containing the constant stored in CODEPAGE
  946        * @see org.apache.poi.hssf.record.CodepageRecord
  947        * @see org.apache.poi.hssf.record.Record
  948        * @return record containing a CodepageRecord
  949        */
  950   
  951       protected Record createCodepage() {
  952           CodepageRecord retval = new CodepageRecord();
  953   
  954           retval.setCodepage(CODEPAGE);
  955           return retval;
  956       }
  957   
  958       /**
  959        * creates the DSF record containing a 0 since HSSF can't even create Dual Stream Files
  960        * @see org.apache.poi.hssf.record.DSFRecord
  961        * @see org.apache.poi.hssf.record.Record
  962        * @return record containing a DSFRecord
  963        */
  964   
  965       protected Record createDSF() {
  966           DSFRecord retval = new DSFRecord();
  967   
  968           retval.setDsf(
  969           ( short ) 0);   // we don't even support double stream files
  970           return retval;
  971       }
  972   
  973       /**
  974        * creates the TabId record containing an array of 0,1,2.  This release of HSSF
  975        * always has the default three sheets, no less, no more.
  976        * @see org.apache.poi.hssf.record.TabIdRecord
  977        * @see org.apache.poi.hssf.record.Record
  978        * @return record containing a TabIdRecord
  979        */
  980   
  981       protected Record createTabId() {
  982           TabIdRecord retval     = new TabIdRecord();
  983           short[]     tabidarray = {
  984               0
  985           };
  986   
  987           retval.setTabIdArray(tabidarray);
  988           return retval;
  989       }
  990   
  991       /**
  992        * creates the FnGroupCount record containing the Magic number constant of 14.
  993        * @see org.apache.poi.hssf.record.FnGroupCountRecord
  994        * @see org.apache.poi.hssf.record.Record
  995        * @return record containing a FnGroupCountRecord
  996        */
  997   
  998       protected Record createFnGroupCount() {
  999           FnGroupCountRecord retval = new FnGroupCountRecord();
 1000   
 1001           retval.setCount(( short ) 14);
 1002           return retval;
 1003       }
 1004   
 1005       /**
 1006        * creates the WindowProtect record with protect set to false.
 1007        * @see org.apache.poi.hssf.record.WindowProtectRecord
 1008        * @see org.apache.poi.hssf.record.Record
 1009        * @return record containing a WindowProtectRecord
 1010        */
 1011   
 1012       protected Record createWindowProtect() {
 1013           WindowProtectRecord retval = new WindowProtectRecord();
 1014   
 1015           retval.setProtect(
 1016           false);   // by default even when we support it we won't
 1017           return retval;   // want it to be protected
 1018       }
 1019   
 1020       /**
 1021        * creates the Protect record with protect set to false.
 1022        * @see org.apache.poi.hssf.record.ProtectRecord
 1023        * @see org.apache.poi.hssf.record.Record
 1024        * @return record containing a ProtectRecord
 1025        */
 1026   
 1027       protected Record createProtect() {
 1028           ProtectRecord retval = new ProtectRecord();
 1029   
 1030           retval.setProtect(
 1031           false);   // by default even when we support it we won't
 1032           return retval;   // want it to be protected
 1033       }
 1034   
 1035       /**
 1036        * creates the Password record with password set to 0.
 1037        * @see org.apache.poi.hssf.record.PasswordRecord
 1038        * @see org.apache.poi.hssf.record.Record
 1039        * @return record containing a PasswordRecord
 1040        */
 1041   
 1042       protected Record createPassword() {
 1043           PasswordRecord retval = new PasswordRecord();
 1044   
 1045           retval.setPassword(( short ) 0);   // no password by default!
 1046           return retval;
 1047       }
 1048   
 1049       /**
 1050        * creates the ProtectionRev4 record with protect set to false.
 1051        * @see org.apache.poi.hssf.record.ProtectionRev4Record
 1052        * @see org.apache.poi.hssf.record.Record
 1053        * @return record containing a ProtectionRev4Record
 1054        */
 1055   
 1056       protected Record createProtectionRev4() {
 1057           ProtectionRev4Record retval = new ProtectionRev4Record();
 1058   
 1059           retval.setProtect(false);
 1060           return retval;
 1061       }
 1062   
 1063       /**
 1064        * creates the PasswordRev4 record with password set to 0.
 1065        * @see org.apache.poi.hssf.record.PasswordRev4Record
 1066        * @see org.apache.poi.hssf.record.Record
 1067        * @return record containing a PasswordRev4Record
 1068        */
 1069   
 1070       protected Record createPasswordRev4() {
 1071           PasswordRev4Record retval = new PasswordRev4Record();
 1072   
 1073           retval.setPassword(( short ) 0);   // no password by default!
 1074           return retval;
 1075       }
 1076   
 1077       /**
 1078        * creates the WindowOne record with the following magic values: <P>
 1079        * horizontal hold - 0x168 <P>
 1080        * vertical hold   - 0x10e <P>
 1081        * width           - 0x3a5c <P>
 1082        * height          - 0x23be <P>
 1083        * options         - 0x38 <P>
 1084        * selected tab    - 0 <P>
 1085        * displayed tab   - 0 <P>
 1086        * num selected tab- 0 <P>
 1087        * tab width ratio - 0x258 <P>
 1088        * @see org.apache.poi.hssf.record.WindowOneRecord
 1089        * @see org.apache.poi.hssf.record.Record
 1090        * @return record containing a WindowOneRecord
 1091        */
 1092   
 1093       protected Record createWindowOne() {
 1094           WindowOneRecord retval = new WindowOneRecord();
 1095   
 1096           retval.setHorizontalHold(( short ) 0x168);
 1097           retval.setVerticalHold(( short ) 0x10e);
 1098           retval.setWidth(( short ) 0x3a5c);
 1099           retval.setHeight(( short ) 0x23be);
 1100           retval.setOptions(( short ) 0x38);
 1101           retval.setSelectedTab(( short ) 0x0);
 1102           retval.setDisplayedTab(( short ) 0x0);
 1103           retval.setNumSelectedTabs(( short ) 1);
 1104           retval.setTabWidthRatio(( short ) 0x258);
 1105           return retval;
 1106       }
 1107   
 1108       /**
 1109        * creates the Backup record with backup set to 0. (loose the data, who cares)
 1110        * @see org.apache.poi.hssf.record.BackupRecord
 1111        * @see org.apache.poi.hssf.record.Record
 1112        * @return record containing a BackupRecord
 1113        */
 1114   
 1115       protected Record createBackup() {
 1116           BackupRecord retval = new BackupRecord();
 1117   
 1118           retval.setBackup(
 1119           ( short ) 0);   // by default DONT save backups of files...just loose data
 1120           return retval;
 1121       }
 1122   
 1123       /**
 1124        * creates the HideObj record with hide object set to 0. (don't hide)
 1125        * @see org.apache.poi.hssf.record.HideObjRecord
 1126        * @see org.apache.poi.hssf.record.Record
 1127        * @return record containing a HideObjRecord
 1128        */
 1129   
 1130       protected Record createHideObj() {
 1131           HideObjRecord retval = new HideObjRecord();
 1132   
 1133           retval.setHideObj(( short ) 0);   // by default set hide object off
 1134           return retval;
 1135       }
 1136   
 1137       /**
 1138        * creates the DateWindow1904 record with windowing set to 0. (don't window)
 1139        * @see org.apache.poi.hssf.record.DateWindow1904Record
 1140        * @see org.apache.poi.hssf.record.Record
 1141        * @return record containing a DateWindow1904Record
 1142        */
 1143   
 1144       protected Record createDateWindow1904() {
 1145           DateWindow1904Record retval = new DateWindow1904Record();
 1146   
 1147           retval.setWindowing(
 1148           ( short ) 0);   // don't EVER use 1904 date windowing...tick tock..
 1149           return retval;
 1150       }
 1151   
 1152       /**
 1153        * creates the Precision record with precision set to true. (full precision)
 1154        * @see org.apache.poi.hssf.record.PrecisionRecord
 1155        * @see org.apache.poi.hssf.record.Record
 1156        * @return record containing a PrecisionRecord
 1157        */
 1158   
 1159       protected Record createPrecision() {
 1160           PrecisionRecord retval = new PrecisionRecord();
 1161   
 1162           retval.setFullPrecision(
 1163           true);   // always use real numbers in calculations!
 1164           return retval;
 1165       }
 1166   
 1167       /**
 1168        * creates the RefreshAll record with refreshAll set to true. (refresh all calcs)
 1169        * @see org.apache.poi.hssf.record.RefreshAllRecord
 1170        * @see org.apache.poi.hssf.record.Record
 1171        * @return record containing a RefreshAllRecord
 1172        */
 1173   
 1174       protected Record createRefreshAll() {
 1175           RefreshAllRecord retval = new RefreshAllRecord();
 1176   
 1177           retval.setRefreshAll(false);
 1178           return retval;
 1179       }
 1180   
 1181       /**
 1182        * creates the BookBool record with saveLinkValues set to 0. (don't save link values)
 1183        * @see org.apache.poi.hssf.record.BookBoolRecord
 1184        * @see org.apache.poi.hssf.record.Record
 1185        * @return record containing a BookBoolRecord
 1186        */
 1187   
 1188       protected Record createBookBool() {
 1189           BookBoolRecord retval = new BookBoolRecord();
 1190   
 1191           retval.setSaveLinkValues(( short ) 0);
 1192           return retval;
 1193       }
 1194   
 1195       /**
 1196        * creates a Font record with the following magic values: <P>
 1197        * fontheight           = 0xc8<P>
 1198        * attributes           = 0x0<P>
 1199        * color palette index  = 0x7fff<P>
 1200        * bold weight          = 0x190<P>
 1201        * Font Name Length     = 5 <P>
 1202        * Font Name            = Arial <P>
 1203        *
 1204        * @see org.apache.poi.hssf.record.FontRecord
 1205        * @see org.apache.poi.hssf.record.Record
 1206        * @return record containing a FontRecord
 1207        */
 1208   
 1209       protected Record createFont() {
 1210           FontRecord retval = new FontRecord();
 1211   
 1212           retval.setFontHeight(( short ) 0xc8);
 1213           retval.setAttributes(( short ) 0x0);
 1214           retval.setColorPaletteIndex(( short ) 0x7fff);
 1215           retval.setBoldWeight(( short ) 0x190);
 1216           retval.setFontNameLength(( byte ) 5);
 1217           retval.setFontName("Arial");
 1218           return retval;
 1219       }
 1220   
 1221       /**
 1222        * Creates a FormatRecord object
 1223        * @param id    the number of the format record to create (meaning its position in
 1224        *        a file as M$ Excel would create it.)
 1225        * @return record containing a FormatRecord
 1226        * @see org.apache.poi.hssf.record.FormatRecord
 1227        * @see org.apache.poi.hssf.record.Record
 1228        */
 1229   
 1230       protected Record createFormat(int id) {   // we'll need multiple editions for
 1231           FormatRecord retval = new FormatRecord();   // the differnt formats
 1232   
 1233           switch (id) {
 1234   
 1235               case 0 :
 1236                   retval.setIndexCode(( short ) 5);
 1237                   retval.setFormatStringLength(( byte ) 0x17);
 1238                   retval.setFormatString("\"$\"#,##0_);\\(\"$\"#,##0\\)");
 1239                   break;
 1240   
 1241               case 1 :
 1242                   retval.setIndexCode(( short ) 6);
 1243                   retval.setFormatStringLength(( byte ) 0x1c);
 1244                   retval.setFormatString("\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)");
 1245                   break;
 1246   
 1247               case 2 :
 1248                   retval.setIndexCode(( short ) 7);
 1249                   retval.setFormatStringLength(( byte ) 0x1d);
 1250                   retval.setFormatString("\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)");
 1251                   break;
 1252   
 1253               case 3 :
 1254                   retval.setIndexCode(( short ) 8);
 1255                   retval.setFormatStringLength(( byte ) 0x22);
 1256                   retval.setFormatString(
 1257                   "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)");
 1258                   break;
 1259   
 1260               case 4 :
 1261                   retval.setIndexCode(( short ) 0x2a);
 1262                   retval.setFormatStringLength(( byte ) 0x32);
 1263                   retval.setFormatString(
 1264                   "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)");
 1265                   break;
 1266   
 1267               case 5 :
 1268                   retval.setIndexCode(( short ) 0x29);
 1269                   retval.setFormatStringLength(( byte ) 0x29);
 1270                   retval.setFormatString(
 1271                   "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)");
 1272                   break;
 1273   
 1274               case 6 :
 1275                   retval.setIndexCode(( short ) 0x2c);
 1276                   retval.setFormatStringLength(( byte ) 0x3a);
 1277                   retval.setFormatString(
 1278                   "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)");
 1279                   break;
 1280   
 1281               case 7 :
 1282                   retval.setIndexCode(( short ) 0x2b);
 1283                   retval.setFormatStringLength(( byte ) 0x31);
 1284                   retval.setFormatString(
 1285                   "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)");
 1286                   break;
 1287           }
 1288           return retval;
 1289       }
 1290   
 1291       /**
 1292        * Creates an ExtendedFormatRecord object
 1293        * @param id    the number of the extended format record to create (meaning its position in
 1294        *        a file as MS Excel would create it.)
 1295        *
 1296        * @return record containing an ExtendedFormatRecord
 1297        * @see org.apache.poi.hssf.record.ExtendedFormatRecord
 1298        * @see org.apache.poi.hssf.record.Record
 1299        */
 1300   
 1301       protected Record createExtendedFormat(int id) {   // we'll need multiple editions
 1302           ExtendedFormatRecord retval = new ExtendedFormatRecord();
 1303   
 1304           switch (id) {
 1305   
 1306               case 0 :
 1307                   retval.setFontIndex(( short ) 0);
 1308                   retval.setFormatIndex(( short ) 0);
 1309                   retval.setCellOptions(( short ) 0xfffffff5);
 1310                   retval.setAlignmentOptions(( short ) 0x20);
 1311                   retval.setIndentionOptions(( short ) 0);
 1312                   retval.setBorderOptions(( short ) 0);
 1313                   retval.setPaletteOptions(( short ) 0);
 1314                   retval.setAdtlPaletteOptions(( short ) 0);
 1315                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1316                   break;
 1317   
 1318               case 1 :
 1319                   retval.setFontIndex(( short ) 1);
 1320                   retval.setFormatIndex(( short ) 0);
 1321                   retval.setCellOptions(( short ) 0xfffffff5);
 1322                   retval.setAlignmentOptions(( short ) 0x20);
 1323                   retval.setIndentionOptions(( short ) 0xfffff400);
 1324                   retval.setBorderOptions(( short ) 0);
 1325                   retval.setPaletteOptions(( short ) 0);
 1326                   retval.setAdtlPaletteOptions(( short ) 0);
 1327                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1328                   break;
 1329   
 1330               case 2 :
 1331                   retval.setFontIndex(( short ) 1);
 1332                   retval.setFormatIndex(( short ) 0);
 1333                   retval.setCellOptions(( short ) 0xfffffff5);
 1334                   retval.setAlignmentOptions(( short ) 0x20);
 1335                   retval.setIndentionOptions(( short ) 0xfffff400);
 1336                   retval.setBorderOptions(( short ) 0);
 1337                   retval.setPaletteOptions(( short ) 0);
 1338                   retval.setAdtlPaletteOptions(( short ) 0);
 1339                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1340                   break;
 1341   
 1342               case 3 :
 1343                   retval.setFontIndex(( short ) 2);
 1344                   retval.setFormatIndex(( short ) 0);
 1345                   retval.setCellOptions(( short ) 0xfffffff5);
 1346                   retval.setAlignmentOptions(( short ) 0x20);
 1347                   retval.setIndentionOptions(( short ) 0xfffff400);
 1348                   retval.setBorderOptions(( short ) 0);
 1349                   retval.setPaletteOptions(( short ) 0);
 1350                   retval.setAdtlPaletteOptions(( short ) 0);
 1351                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1352                   break;
 1353   
 1354               case 4 :
 1355                   retval.setFontIndex(( short ) 2);
 1356                   retval.setFormatIndex(( short ) 0);
 1357                   retval.setCellOptions(( short ) 0xfffffff5);
 1358                   retval.setAlignmentOptions(( short ) 0x20);
 1359                   retval.setIndentionOptions(( short ) 0xfffff400);
 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 5 :
 1367                   retval.setFontIndex(( short ) 0);
 1368                   retval.setFormatIndex(( short ) 0);
 1369                   retval.setCellOptions(( short ) 0xfffffff5);
 1370                   retval.setAlignmentOptions(( short ) 0x20);
 1371                   retval.setIndentionOptions(( short ) 0xfffff400);
 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 6 :
 1379                   retval.setFontIndex(( short ) 0);
 1380                   retval.setFormatIndex(( short ) 0);
 1381                   retval.setCellOptions(( short ) 0xfffffff5);
 1382                   retval.setAlignmentOptions(( short ) 0x20);
 1383                   retval.setIndentionOptions(( short ) 0xfffff400);
 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 7 :
 1391                   retval.setFontIndex(( short ) 0);
 1392                   retval.setFormatIndex(( short ) 0);
 1393                   retval.setCellOptions(( short ) 0xfffffff5);
 1394                   retval.setAlignmentOptions(( short ) 0x20);
 1395                   retval.setIndentionOptions(( short ) 0xfffff400);
 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 8 :
 1403                   retval.setFontIndex(( short ) 0);
 1404                   retval.setFormatIndex(( short ) 0);
 1405                   retval.setCellOptions(( short ) 0xfffffff5);
 1406                   retval.setAlignmentOptions(( short ) 0x20);
 1407                   retval.setIndentionOptions(( short ) 0xfffff400);
 1408                   retval.setBorderOptions(( short ) 0);
 1409                   retval.setPaletteOptions(( short ) 0);
 1410                   retval.setAdtlPaletteOptions(( short ) 0);
 1411                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1412                   break;
 1413   
 1414               case 9 :
 1415                   retval.setFontIndex(( short ) 0);
 1416                   retval.setFormatIndex(( short ) 0);
 1417                   retval.setCellOptions(( short ) 0xfffffff5);
 1418                   retval.setAlignmentOptions(( short ) 0x20);
 1419                   retval.setIndentionOptions(( short ) 0xfffff400);
 1420                   retval.setBorderOptions(( short ) 0);
 1421                   retval.setPaletteOptions(( short ) 0);
 1422                   retval.setAdtlPaletteOptions(( short ) 0);
 1423                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1424                   break;
 1425   
 1426               case 10 :
 1427                   retval.setFontIndex(( short ) 0);
 1428                   retval.setFormatIndex(( short ) 0);
 1429                   retval.setCellOptions(( short ) 0xfffffff5);
 1430                   retval.setAlignmentOptions(( short ) 0x20);
 1431                   retval.setIndentionOptions(( short ) 0xfffff400);
 1432                   retval.setBorderOptions(( short ) 0);
 1433                   retval.setPaletteOptions(( short ) 0);
 1434                   retval.setAdtlPaletteOptions(( short ) 0);
 1435                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1436                   break;
 1437   
 1438               case 11 :
 1439                   retval.setFontIndex(( short ) 0);
 1440                   retval.setFormatIndex(( short ) 0);
 1441                   retval.setCellOptions(( short ) 0xfffffff5);
 1442                   retval.setAlignmentOptions(( short ) 0x20);
 1443                   retval.setIndentionOptions(( short ) 0xfffff400);
 1444                   retval.setBorderOptions(( short ) 0);
 1445                   retval.setPaletteOptions(( short ) 0);
 1446                   retval.setAdtlPaletteOptions(( short ) 0);
 1447                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1448                   break;
 1449   
 1450               case 12 :
 1451                   retval.setFontIndex(( short ) 0);
 1452                   retval.setFormatIndex(( short ) 0);
 1453                   retval.setCellOptions(( short ) 0xfffffff5);
 1454                   retval.setAlignmentOptions(( short ) 0x20);
 1455                   retval.setIndentionOptions(( short ) 0xfffff400);
 1456                   retval.setBorderOptions(( short ) 0);
 1457                   retval.setPaletteOptions(( short ) 0);
 1458                   retval.setAdtlPaletteOptions(( short ) 0);
 1459                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1460                   break;
 1461   
 1462               case 13 :
 1463                   retval.setFontIndex(( short ) 0);
 1464                   retval.setFormatIndex(( short ) 0);
 1465                   retval.setCellOptions(( short ) 0xfffffff5);
 1466                   retval.setAlignmentOptions(( short ) 0x20);
 1467                   retval.setIndentionOptions(( short ) 0xfffff400);
 1468                   retval.setBorderOptions(( short ) 0);
 1469                   retval.setPaletteOptions(( short ) 0);
 1470                   retval.setAdtlPaletteOptions(( short ) 0);
 1471                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1472                   break;
 1473   
 1474               case 14 :
 1475                   retval.setFontIndex(( short ) 0);
 1476                   retval.setFormatIndex(( short ) 0);
 1477                   retval.setCellOptions(( short ) 0xfffffff5);
 1478                   retval.setAlignmentOptions(( short ) 0x20);
 1479                   retval.setIndentionOptions(( short ) 0xfffff400);
 1480                   retval.setBorderOptions(( short ) 0);
 1481                   retval.setPaletteOptions(( short ) 0);
 1482                   retval.setAdtlPaletteOptions(( short ) 0);
 1483                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1484                   break;
 1485   
 1486                   // cell records
 1487               case 15 :
 1488                   retval.setFontIndex(( short ) 0);
 1489                   retval.setFormatIndex(( short ) 0);
 1490                   retval.setCellOptions(( short ) 0x1);
 1491                   retval.setAlignmentOptions(( short ) 0x20);
 1492                   retval.setIndentionOptions(( short ) 0x0);
 1493                   retval.setBorderOptions(( short ) 0);
 1494                   retval.setPaletteOptions(( short ) 0);
 1495                   retval.setAdtlPaletteOptions(( short ) 0);
 1496                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1497                   break;
 1498   
 1499                   // style
 1500               case 16 :
 1501                   retval.setFontIndex(( short ) 1);
 1502                   retval.setFormatIndex(( short ) 0x2b);
 1503                   retval.setCellOptions(( short ) 0xfffffff5);
 1504                   retval.setAlignmentOptions(( short ) 0x20);
 1505                   retval.setIndentionOptions(( short ) 0xfffff800);
 1506                   retval.setBorderOptions(( short ) 0);
 1507                   retval.setPaletteOptions(( short ) 0);
 1508                   retval.setAdtlPaletteOptions(( short ) 0);
 1509                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1510                   break;
 1511   
 1512               case 17 :
 1513                   retval.setFontIndex(( short ) 1);
 1514                   retval.setFormatIndex(( short ) 0x29);
 1515                   retval.setCellOptions(( short ) 0xfffffff5);
 1516                   retval.setAlignmentOptions(( short ) 0x20);
 1517                   retval.setIndentionOptions(( short ) 0xfffff800);
 1518                   retval.setBorderOptions(( short ) 0);
 1519                   retval.setPaletteOptions(( short ) 0);
 1520                   retval.setAdtlPaletteOptions(( short ) 0);
 1521                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1522                   break;
 1523   
 1524               case 18 :
 1525                   retval.setFontIndex(( short ) 1);
 1526                   retval.setFormatIndex(( short ) 0x2c);
 1527                   retval.setCellOptions(( short ) 0xfffffff5);
 1528                   retval.setAlignmentOptions(( short ) 0x20);
 1529                   retval.setIndentionOptions(( short ) 0xfffff800);
 1530                   retval.setBorderOptions(( short ) 0);
 1531                   retval.setPaletteOptions(( short ) 0);
 1532                   retval.setAdtlPaletteOptions(( short ) 0);
 1533                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1534                   break;
 1535   
 1536               case 19 :
 1537                   retval.setFontIndex(( short ) 1);
 1538                   retval.setFormatIndex(( short ) 0x2a);
 1539                   retval.setCellOptions(( short ) 0xfffffff5);
 1540                   retval.setAlignmentOptions(( short ) 0x20);
 1541                   retval.setIndentionOptions(( short ) 0xfffff800);
 1542                   retval.setBorderOptions(( short ) 0);
 1543                   retval.setPaletteOptions(( short ) 0);
 1544                   retval.setAdtlPaletteOptions(( short ) 0);
 1545                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1546                   break;
 1547   
 1548               case 20 :
 1549                   retval.setFontIndex(( short ) 1);
 1550                   retval.setFormatIndex(( short ) 0x9);
 1551                   retval.setCellOptions(( short ) 0xfffffff5);
 1552                   retval.setAlignmentOptions(( short ) 0x20);
 1553                   retval.setIndentionOptions(( short ) 0xfffff800);
 1554                   retval.setBorderOptions(( short ) 0);
 1555                   retval.setPaletteOptions(( short ) 0);
 1556                   retval.setAdtlPaletteOptions(( short ) 0);
 1557                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1558                   break;
 1559   
 1560                   // unused from this point down
 1561               case 21 :
 1562                   retval.setFontIndex(( short ) 5);
 1563                   retval.setFormatIndex(( short ) 0x0);
 1564                   retval.setCellOptions(( short ) 0x1);
 1565                   retval.setAlignmentOptions(( short ) 0x20);
 1566                   retval.setIndentionOptions(( short ) 0x800);
 1567                   retval.setBorderOptions(( short ) 0);
 1568                   retval.setPaletteOptions(( short ) 0);
 1569                   retval.setAdtlPaletteOptions(( short ) 0);
 1570                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1571                   break;
 1572   
 1573               case 22 :
 1574                   retval.setFontIndex(( short ) 6);
 1575                   retval.setFormatIndex(( short ) 0x0);
 1576                   retval.setCellOptions(( short ) 0x1);
 1577                   retval.setAlignmentOptions(( short ) 0x20);
 1578                   retval.setIndentionOptions(( short ) 0x5c00);
 1579                   retval.setBorderOptions(( short ) 0);
 1580                   retval.setPaletteOptions(( short ) 0);
 1581                   retval.setAdtlPaletteOptions(( short ) 0);
 1582                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1583                   break;
 1584   
 1585               case 23 :
 1586                   retval.setFontIndex(( short ) 0);
 1587                   retval.setFormatIndex(( short ) 0x31);
 1588                   retval.setCellOptions(( short ) 0x1);
 1589                   retval.setAlignmentOptions(( short ) 0x20);
 1590                   retval.setIndentionOptions(( short ) 0x5c00);
 1591                   retval.setBorderOptions(( short ) 0);
 1592                   retval.setPaletteOptions(( short ) 0);
 1593                   retval.setAdtlPaletteOptions(( short ) 0);
 1594                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1595                   break;
 1596   
 1597               case 24 :
 1598                   retval.setFontIndex(( short ) 0);
 1599                   retval.setFormatIndex(( short ) 0x8);
 1600                   retval.setCellOptions(( short ) 0x1);
 1601                   retval.setAlignmentOptions(( short ) 0x20);
 1602                   retval.setIndentionOptions(( short ) 0x5c00);
 1603                   retval.setBorderOptions(( short ) 0);
 1604                   retval.setPaletteOptions(( short ) 0);
 1605                   retval.setAdtlPaletteOptions(( short ) 0);
 1606                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1607                   break;
 1608   
 1609               case 25 :
 1610                   retval.setFontIndex(( short ) 6);
 1611                   retval.setFormatIndex(( short ) 0x8);
 1612                   retval.setCellOptions(( short ) 0x1);
 1613                   retval.setAlignmentOptions(( short ) 0x20);
 1614                   retval.setIndentionOptions(( short ) 0x5c00);
 1615                   retval.setBorderOptions(( short ) 0);
 1616                   retval.setPaletteOptions(( short ) 0);
 1617                   retval.setAdtlPaletteOptions(( short ) 0);
 1618                   retval.setFillPaletteOptions(( short ) 0x20c0);
 1619                   break;
 1620           }
 1621           return retval;
 1622       }
 1623   
 1624       /**
 1625        * creates an default cell type ExtendedFormatRecord object.
 1626        * @return ExtendedFormatRecord with intial defaults (cell-type)
 1627        */
 1628   
 1629       protected ExtendedFormatRecord createExtendedFormat() {
 1630           ExtendedFormatRecord retval = new ExtendedFormatRecord();
 1631   
 1632           retval.setFontIndex(( short ) 0);
 1633           retval.setFormatIndex(( short ) 0x0);
 1634           retval.setCellOptions(( short ) 0x1);
 1635           retval.setAlignmentOptions(( short ) 0x20);
 1636           retval.setIndentionOptions(( short ) 0);
 1637           retval.setBorderOptions(( short ) 0);
 1638           retval.setPaletteOptions(( short ) 0);
 1639           retval.setAdtlPaletteOptions(( short ) 0);
 1640           retval.setFillPaletteOptions(( short ) 0x20c0);
 1641           retval.setTopBorderPaletteIdx(HSSFColor.BLACK.index);
 1642           retval.setBottomBorderPaletteIdx(HSSFColor.BLACK.index);
 1643           retval.setLeftBorderPaletteIdx(HSSFColor.BLACK.index);
 1644           retval.setRightBorderPaletteIdx(HSSFColor.BLACK.index);
 1645           return retval;
 1646       }
 1647   
 1648       /**
 1649        * Creates a StyleRecord object
 1650        * @param id        the number of the style record to create (meaning its position in
 1651        *                  a file as MS Excel would create it.
 1652        * @return record containing a StyleRecord
 1653        * @see org.apache.poi.hssf.record.StyleRecord
 1654        * @see org.apache.poi.hssf.record.Record
 1655        */
 1656   
 1657       protected Record createStyle(int id) {   // we'll need multiple editions
 1658           StyleRecord retval = new StyleRecord();
 1659   
 1660           switch (id) {
 1661   
 1662               case 0 :
 1663                   retval.setIndex(( short ) 0xffff8010);
 1664                   retval.setBuiltin(( byte ) 3);
 1665                   retval.setOutlineStyleLevel(( byte ) 0xffffffff);
 1666                   break;
 1667   
 1668               case 1 :
 1669                   retval.setIndex(( short ) 0xffff8011);
 1670                   retval.setBuiltin(( byte ) 6);
 1671                   retval.setOutlineStyleLevel(( byte ) 0xffffffff);
 1672                   break;
 1673   
 1674               case 2 :
 1675                   retval.setIndex(( short ) 0xffff8012);
 1676                   retval.setBuiltin(( byte ) 4);
 1677                   retval.setOutlineStyleLevel(( byte ) 0xffffffff);
 1678                   break;
 1679   
 1680               case 3 :
 1681                   retval.setIndex(( short ) 0xffff8013);
 1682                   retval.setBuiltin(( byte ) 7);
 1683                   retval.setOutlineStyleLevel(( byte ) 0xffffffff);
 1684                   break;
 1685   
 1686               case 4 :
 1687                   retval.setIndex(( short ) 0xffff8000);
 1688                   retval.setBuiltin(( byte ) 0);
 1689                   retval.setOutlineStyleLevel(( byte ) 0xffffffff);
 1690                   break;
 1691   
 1692               case 5 :
 1693                   retval.setIndex(( short ) 0xffff8014);
 1694                   retval.setBuiltin(( byte ) 5);
 1695                   retval.setOutlineStyleLevel(( byte ) 0xffffffff);
 1696                   break;
 1697           }
 1698           return retval;
 1699       }
 1700   
 1701       /**
 1702        * Creates a palette record initialized to the default palette
 1703        * @return a PaletteRecord instance populated with the default colors
 1704        * @see org.apache.poi.hssf.record.PaletteRecord
 1705        */
 1706       protected PaletteRecord createPalette()
 1707       {
 1708           return new PaletteRecord();
 1709       }
 1710       
 1711       /**
 1712        * Creates the UseSelFS object with the use natural language flag set to 0 (false)
 1713        * @return record containing a UseSelFSRecord
 1714        * @see org.apache.poi.hssf.record.UseSelFSRecord
 1715        * @see org.apache.poi.hssf.record.Record
 1716        */
 1717   
 1718       protected Record createUseSelFS() {
 1719           UseSelFSRecord retval = new UseSelFSRecord();
 1720   
 1721           retval.setFlag(( short ) 0);
 1722           return retval;
 1723       }
 1724   
 1725       /**
 1726        * create a "bound sheet" or "bundlesheet" (depending who you ask) record
 1727        * Always sets the sheet's bof to 0.  You'll need to set that yourself.
 1728        * @param id either sheet 0,1 or 2.
 1729        * @return record containing a BoundSheetRecord
 1730        * @see org.apache.poi.hssf.record.BoundSheetRecord
 1731        * @see org.apache.poi.hssf.record.Record
 1732        */
 1733   
 1734       protected Record createBoundSheet(int id) {   // 1,2,3 sheets
 1735           BoundSheetRecord retval = new BoundSheetRecord();
 1736   
 1737           switch (id) {
 1738   
 1739               case 0 :
 1740                   retval.setPositionOfBof(0x0);   // should be set later
 1741                   retval.setOptionFlags(( short ) 0);
 1742                   retval.setSheetnameLength(( byte ) 0x6);
 1743                   retval.setCompressedUnicodeFlag(( byte ) 0);
 1744                   retval.setSheetname("Sheet1");
 1745                   break;
 1746   
 1747               case 1 :
 1748                   retval.setPositionOfBof(0x0);   // should be set later
 1749                   retval.setOptionFlags(( short ) 0);
 1750                   retval.setSheetnameLength(( byte ) 0x6);
 1751                   retval.setCompressedUnicodeFlag(( byte ) 0);
 1752                   retval.setSheetname("Sheet2");
 1753                   break;
 1754   
 1755               case 2 :
 1756                   retval.setPositionOfBof(0x0);   // should be set later
 1757                   retval.setOptionFlags(( short ) 0);
 1758                   retval.setSheetnameLength(( byte ) 0x6);
 1759                   retval.setCompressedUnicodeFlag(( byte ) 0);
 1760                   retval.setSheetname("Sheet3");
 1761                   break;
 1762           }
 1763           return retval;
 1764       }
 1765   
 1766       /**
 1767        * Creates the Country record with the default country set to 1
 1768        * and current country set to 7 in case of russian locale ("ru_RU") and 1 otherwise
 1769        * @return record containing a CountryRecord
 1770        * @see org.apache.poi.hssf.record.CountryRecord
 1771        * @see org.apache.poi.hssf.record.Record
 1772        */
 1773   
 1774       protected Record createCountry() {   // what a novel idea, create your own!
 1775           CountryRecord retval = new CountryRecord();
 1776   
 1777           retval.setDefaultCountry(( short ) 1);
 1778   
 1779           // from Russia with love ;)
 1780           if ( Locale.getDefault().toString().equals( "ru_RU" ) ) {
 1781   	        retval.setCurrentCountry(( short ) 7);
 1782           }
 1783           else {
 1784   	        retval.setCurrentCountry(( short ) 1);
 1785           }
 1786   
 1787           return retval;
 1788       }
 1789   
 1790       /**
 1791        * Creates the SST record with no strings and the unique/num string set to 0
 1792        * @return record containing a SSTRecord
 1793        * @see org.apache.poi.hssf.record.SSTRecord
 1794        * @see org.apache.poi.hssf.record.Record
 1795        */
 1796   
 1797       protected Record createSST() {
 1798           return new SSTRecord();
 1799       }
 1800   
 1801       /**
 1802        * Creates the ExtendedSST record with numstrings per bucket set to 0x8.  HSSF
 1803        * doesn't yet know what to do with this thing, but we create it with nothing in
 1804        * it hardly just to make Excel happy and our sheets look like Excel's
 1805        *
 1806        * @return record containing an ExtSSTRecord
 1807        * @see org.apache.poi.hssf.record.ExtSSTRecord
 1808        * @see org.apache.poi.hssf.record.Record
 1809        */
 1810   
 1811       protected Record createExtendedSST() {
 1812           ExtSSTRecord retval = new ExtSSTRecord();
 1813   
 1814           retval.setNumStringsPerBucket(( short ) 0x8);
 1815           return retval;
 1816       }
 1817   
 1818       /**
 1819        * creates the EOF record
 1820        * @see org.apache.poi.hssf.record.EOFRecord
 1821        * @see org.apache.poi.hssf.record.Record
 1822        * @return record containing a EOFRecord
 1823        */
 1824   
 1825       protected Record createEOF() {
 1826           return new EOFRecord();
 1827       }
 1828       
 1829       /**
 1830        * lazy initialization
 1831        * Note - creating the link table causes creation of 1 EXTERNALBOOK and 1 EXTERNALSHEET record
 1832        */
 1833       private LinkTable getOrCreateLinkTable() {
 1834           if(linkTable == null) {
 1835               linkTable = new LinkTable((short) getNumSheets(), records);
 1836           }
 1837           return linkTable;
 1838       }
 1839   
 1840       public SheetReferences getSheetReferences() {
 1841           SheetReferences refs = new SheetReferences();
 1842           
 1843           if (linkTable != null) {
 1844               int numRefStructures = linkTable.getNumberOfREFStructures();
 1845               for (short k = 0; k < numRefStructures; k++) {
 1846                   
 1847                   String sheetName = findSheetNameFromExternSheet(k);
 1848                   refs.addSheetReference(sheetName, k);
 1849                   
 1850               }
 1851           }
 1852           return refs;
 1853       }
 1854   
 1855       /** finds the sheet name by his extern sheet index
 1856        * @param num extern sheet index
 1857        * @return sheet name
 1858        */
 1859       public String findSheetNameFromExternSheet(short num){
 1860           String result="";
 1861   
 1862           short indexToSheet = linkTable.getIndexToSheet(num);
 1863           
 1864           if (indexToSheet>-1) { //error check, bail out gracefully!
 1865               result = getSheetName(indexToSheet);
 1866           }
 1867   
 1868           return result;
 1869       }
 1870   
 1871       /**
 1872        * Finds the sheet index for a particular external sheet number.
 1873        * @param externSheetNumber     The external sheet number to convert
 1874        * @return  The index to the sheet found.
 1875        */
 1876       public int getSheetIndexFromExternSheetIndex(int externSheetNumber)
 1877       {
 1878           return linkTable.getSheetIndexFromExternSheetIndex(externSheetNumber);
 1879       }
 1880   
 1881       /** returns the extern sheet number for specific sheet number ,
 1882        *  if this sheet doesn't exist in extern sheet , add it
 1883        * @param sheetNumber sheet number
 1884        * @return index to extern sheet
 1885        */
 1886       public short checkExternSheet(int sheetNumber){
 1887           return getOrCreateLinkTable().checkExternSheet(sheetNumber);
 1888       }
 1889   
 1890       /** gets the total number of names
 1891        * @return number of names
 1892        */
 1893       public int getNumNames(){
 1894           if(linkTable == null) {
 1895               return 0;
 1896           }
 1897           return linkTable.getNumNames();
 1898       }
 1899   
 1900       /** gets the name record
 1901        * @param index name index
 1902        * @return name record
 1903        */
 1904       public NameRecord getNameRecord(int index){
 1905           return linkTable.getNameRecord(index);
 1906       }
 1907   
 1908       /** creates new name
 1909        * @return new name record
 1910        */
 1911       public NameRecord createName(){
 1912           return addName(new NameRecord());
 1913       }
 1914   
 1915   
 1916       /** creates new name
 1917        * @return new name record
 1918        */
 1919       public NameRecord addName(NameRecord name)
 1920       {
 1921           
 1922           getOrCreateLinkTable().addName(name);
 1923   
 1924           return name;
 1925       }
 1926   
 1927       /**Generates a NameRecord to represent a built-in region
 1928        * @return a new NameRecord unless the index is invalid
 1929        */
 1930       public NameRecord createBuiltInName(byte builtInName, int index)
 1931       {
 1932           if (index == -1 || index+1 > Short.MAX_VALUE) 
 1933               throw new IllegalArgumentException("Index is not valid ["+index+"]");
 1934           
 1935           NameRecord name = new NameRecord(builtInName, (short)(index));
 1936                   
 1937           addName(name);
 1938           
 1939           return name;
 1940       }
 1941   
 1942   
 1943       /** removes the name
 1944        * @param namenum name index
 1945        */
 1946       public void removeName(int namenum){
 1947           
 1948           if (linkTable.getNumNames() > namenum) {
 1949               int idx = findFirstRecordLocBySid(NameRecord.sid);
 1950               records.remove(idx + namenum);
 1951               linkTable.removeName(namenum);
 1952           }
 1953   
 1954       }
 1955   
 1956       /**
 1957        * Returns a format index that matches the passed in format.  It does not tie into HSSFDataFormat.
 1958        * @param format the format string
 1959        * @param createIfNotFound creates a new format if format not found
 1960        * @return the format id of a format that matches or -1 if none found and createIfNotFound
 1961        */
 1962       public short getFormat(String format, boolean createIfNotFound) {
 1963   	Iterator iterator;
 1964   	for (iterator = formats.iterator(); iterator.hasNext();) {
 1965   	    FormatRecord r = (FormatRecord)iterator.next();
 1966   	    if (r.getFormatString().equals(format)) {
 1967   		return r.getIndexCode();
 1968   	    }
 1969   	}
 1970   
 1971   	if (createIfNotFound) {
 1972   	    return createFormat(format);
 1973   	}
 1974   
 1975   	return -1;
 1976       }
 1977   
 1978       /**
 1979        * Returns the list of FormatRecords in the workbook.
 1980        * @return ArrayList of FormatRecords in the notebook
 1981        */
 1982       public ArrayList getFormats() {
 1983   	return formats;
 1984       }
 1985   
 1986       /**
 1987        * Creates a FormatRecord, inserts it, and returns the index code.
 1988        * @param format the format string
 1989        * @return the index code of the format record.
 1990        * @see org.apache.poi.hssf.record.FormatRecord
 1991        * @see org.apache.poi.hssf.record.Record
 1992        */
 1993       public short createFormat( String format )
 1994       {
 1995   //        ++xfpos;	//These are to ensure that positions are updated properly
 1996   //        ++palettepos;
 1997   //        ++bspos;
 1998           FormatRecord rec = new FormatRecord();
 1999           maxformatid = maxformatid >= (short) 0xa4 ? (short) ( maxformatid + 1 ) : (short) 0xa4; //Starting value from M$ empiracle study.
 2000           rec.setIndexCode( maxformatid );
 2001           rec.setFormatStringLength( (byte) format.length() );
 2002           rec.setFormatString( format );
 2003   
 2004           int pos = 0;
 2005           while ( pos < records.size() && records.get( pos ).getSid() != FormatRecord.sid )
 2006               pos++;
 2007           pos += formats.size();
 2008           formats.add( rec );
 2009           records.add( pos, rec );
 2010           return maxformatid;
 2011       }
 2012   
 2013     
 2014   
 2015       /**
 2016        * Returns the first occurance of a record matching a particular sid.
 2017        */
 2018       public Record findFirstRecordBySid(short sid) {
 2019           for (Iterator iterator = records.iterator(); iterator.hasNext(); ) {
 2020               Record record = ( Record ) iterator.next();
 2021               
 2022               if (record.getSid() == sid) {
 2023                   return record;
 2024               }
 2025           }
 2026           return null;
 2027       }
 2028   
 2029       /**
 2030        * Returns the index of a record matching a particular sid.
 2031        * @param sid   The sid of the record to match
 2032        * @return      The index of -1 if no match made.
 2033        */
 2034       public int findFirstRecordLocBySid(short sid) {
 2035           int index = 0;
 2036           for (Iterator iterator = records.iterator(); iterator.hasNext(); ) {
 2037               Record record = ( Record ) iterator.next();
 2038   
 2039               if (record.getSid() == sid) {
 2040                   return index;
 2041               }
 2042               index ++;
 2043           }
 2044           return -1;
 2045       }
 2046   
 2047       /**
 2048        * Returns the next occurance of a record matching a particular sid.
 2049        */
 2050       public Record findNextRecordBySid(short sid, int pos) {
 2051           int matches = 0;
 2052           for (Iterator iterator = records.iterator(); iterator.hasNext(); ) {
 2053               Record record = ( Record ) iterator.next();
 2054   
 2055               if (record.getSid() == sid) {
 2056                   if (matches++ == pos)
 2057                       return record;
 2058               }
 2059           }
 2060           return null;
 2061       }
 2062   
 2063       public List getHyperlinks()
 2064       {
 2065       	return hyperlinks;
 2066       }
 2067       
 2068       public List getRecords()
 2069       {
 2070           return records.getRecords();
 2071       }
 2072   
 2073   //    public void insertChartRecords( List chartRecords )
 2074   //    {
 2075   //        backuppos += chartRecords.size();
 2076   //        fontpos += chartRecords.size();
 2077   //        palettepos += chartRecords.size();
 2078   //        bspos += chartRecords.size();
 2079   //        xfpos += chartRecords.size();
 2080   //
 2081   //        records.addAll(protpos, chartRecords);
 2082   //    }
 2083   
 2084       /**
 2085       * Whether date windowing is based on 1/2/1904 or 1/1/1900.
 2086       * Some versions of Excel (Mac) can save workbooks using 1904 date windowing.
 2087       *
 2088       * @return true if using 1904 date windowing
 2089       */
 2090       public boolean isUsing1904DateWindowing() {
 2091           return uses1904datewindowing;
 2092       }
 2093       
 2094       /**
 2095        * Returns the custom palette in use for this workbook; if a custom palette record
 2096        * does not exist, then it is created.
 2097        */
 2098       public PaletteRecord getCustomPalette()
 2099       {
 2100         PaletteRecord palette;
 2101         int palettePos = records.getPalettepos();
 2102         if (palettePos != -1) {
 2103           Record rec = records.get(palettePos);
 2104           if (rec instanceof PaletteRecord) {
 2105             palette = (PaletteRecord) rec;
 2106           } else throw new RuntimeException("InternalError: Expected PaletteRecord but got a '"+rec+"'");
 2107         }
 2108         else
 2109         {
 2110             palette = createPalette();
 2111             //Add the palette record after the bof which is always the first record
 2112             records.add(1, palette);
 2113             records.setPalettepos(1);
 2114         }
 2115         return palette;
 2116       }
 2117       
 2118       /**
 2119        * Finds the primary drawing group, if one already exists
 2120        */
 2121       public void findDrawingGroup() {
 2122       	// Need to find a DrawingGroupRecord that
 2123       	//  contains a EscherDggRecord
 2124       	for(Iterator rit = records.iterator(); rit.hasNext();) {
 2125       		Record r = (Record)rit.next();
 2126       		
 2127       		if(r instanceof DrawingGroupRecord) {
 2128               	DrawingGroupRecord dg =	(DrawingGroupRecord)r;
 2129               	dg.processChildRecords();
 2130               	
 2131               	EscherContainerRecord cr =
 2132               		dg.getEscherContainer();
 2133               	if(cr == null) {
 2134               		continue;
 2135               	}
 2136               	
 2137               	EscherDggRecord dgg = null;
 2138               	for(Iterator it = cr.getChildRecords().iterator(); it.hasNext();) {
 2139               		Object er = it.next();
 2140               		if(er instanceof EscherDggRecord) {
 2141               			dgg = (EscherDggRecord)er;
 2142               		}
 2143               	}
 2144               	
 2145               	if(dgg != null) {
 2146               		drawingManager = new DrawingManager2(dgg);
 2147               		return;
 2148               	}
 2149       		}
 2150       	}
 2151   
 2152       	// Look for the DrawingGroup record
 2153           int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
 2154           
 2155       	// If there is one, does it have a EscherDggRecord?
 2156           if(dgLoc != -1) {
 2157           	DrawingGroupRecord dg =
 2158           		(DrawingGroupRecord)records.get(dgLoc);
 2159           	EscherDggRecord dgg = null;
 2160           	for(Iterator it = dg.getEscherRecords().iterator(); it.hasNext();) {
 2161           		Object er = it.next();
 2162           		if(er instanceof EscherDggRecord) {
 2163           			dgg = (EscherDggRecord)er;
 2164           		}
 2165           	}
 2166           	
 2167           	if(dgg != null) {
 2168           		drawingManager = new DrawingManager2(dgg);
 2169           	}
 2170           }
 2171       }
 2172   
 2173       /**
 2174        * Creates a primary drawing group record.  If it already 
 2175        *  exists then it's modified.
 2176        */
 2177       public void createDrawingGroup()
 2178       {
 2179           if (drawingManager == null)
 2180           {
 2181               EscherContainerRecord dggContainer = new EscherContainerRecord();
 2182               EscherDggRecord dgg = new EscherDggRecord();
 2183               EscherOptRecord opt = new EscherOptRecord();
 2184               EscherSplitMenuColorsRecord splitMenuColors = new EscherSplitMenuColorsRecord();
 2185   
 2186               dggContainer.setRecordId((short) 0xF000);
 2187               dggContainer.setOptions((short) 0x000F);
 2188               dgg.setRecordId(EscherDggRecord.RECORD_ID);
 2189               dgg.setOptions((short)0x0000);
 2190               dgg.setShapeIdMax(1024);
 2191               dgg.setNumShapesSaved(0);
 2192               dgg.setDrawingsSaved(0);
 2193               dgg.setFileIdClusters(new EscherDggRecord.FileIdCluster[] {} );
 2194               drawingManager = new DrawingManager2(dgg);
 2195               EscherContainerRecord bstoreContainer = null;
 2196               if (escherBSERecords.size() > 0)
 2197               {
 2198                   bstoreContainer = new EscherContainerRecord();
 2199                   bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER );
 2200                   bstoreContainer.setOptions( (short) ( (escherBSERecords.size() << 4) | 0xF ) );
 2201                   for ( Iterator iterator = escherBSERecords.iterator(); iterator.hasNext(); )
 2202                   {
 2203                       EscherRecord escherRecord = (EscherRecord) iterator.next();
 2204                       bstoreContainer.addChildRecord( escherRecord );
 2205                   }
 2206               }
 2207               opt.setRecordId((short) 0xF00B);
 2208               opt.setOptions((short) 0x0033);
 2209               opt.addEscherProperty( new EscherBoolProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 524296) );
 2210               opt.addEscherProperty( new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, 0x08000041) );
 2211               opt.addEscherProperty( new EscherRGBProperty(EscherProperties.LINESTYLE__COLOR, 134217792) );
 2212               splitMenuColors.setRecordId((short) 0xF11E);
 2213               splitMenuColors.setOptions((short) 0x0040);
 2214               splitMenuColors.setColor1(0x0800000D);
 2215               splitMenuColors.setColor2(0x0800000C);
 2216               splitMenuColors.setColor3(0x08000017);
 2217               splitMenuColors.setColor4(0x100000F7);
 2218   
 2219               dggContainer.addChildRecord(dgg);
 2220               if (bstoreContainer != null)
 2221                   dggContainer.addChildRecord( bstoreContainer );
 2222               dggContainer.addChildRecord(opt);
 2223               dggContainer.addChildRecord(splitMenuColors);
 2224   
 2225               int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
 2226               if (dgLoc == -1)
 2227               {
 2228                   DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
 2229                   drawingGroup.addEscherRecord(dggContainer);
 2230                   int loc = findFirstRecordLocBySid(CountryRecord.sid);
 2231   
 2232                   getRecords().add(loc+1, drawingGroup);
 2233               }
 2234               else
 2235               {
 2236                   DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
 2237                   drawingGroup.addEscherRecord(dggContainer);
 2238                   getRecords().set(dgLoc, drawingGroup);
 2239               }
 2240   
 2241           }
 2242       }
 2243       
 2244       public WindowOneRecord getWindowOne() {
 2245           return windowOne;
 2246       }
 2247   
 2248       public EscherBSERecord getBSERecord(int pictureIndex)
 2249       {
 2250           return (EscherBSERecord)escherBSERecords.get(pictureIndex-1);
 2251       }
 2252   
 2253       public int addBSERecord(EscherBSERecord e)
 2254       {
 2255           createDrawingGroup();
 2256   
 2257           // maybe we don't need that as an instance variable anymore
 2258           escherBSERecords.add( e );
 2259   
 2260           int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
 2261           DrawingGroupRecord drawingGroup = (DrawingGroupRecord) getRecords().get( dgLoc );
 2262   
 2263           EscherContainerRecord dggContainer = (EscherContainerRecord) drawingGroup.getEscherRecord( 0 );
 2264           EscherContainerRecord bstoreContainer;
 2265           if (dggContainer.getChild( 1 ).getRecordId() == EscherContainerRecord.BSTORE_CONTAINER )
 2266           {
 2267               bstoreContainer = (EscherContainerRecord) dggContainer.getChild( 1 );
 2268           }
 2269           else
 2270           {
 2271               bstoreContainer = new EscherContainerRecord();
 2272               bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER );
 2273               dggContainer.getChildRecords().add( 1, bstoreContainer );
 2274           }
 2275           bstoreContainer.setOptions( (short) ( (escherBSERecords.size() << 4) | 0xF ) );
 2276   
 2277           bstoreContainer.addChildRecord( e );
 2278   
 2279           return escherBSERecords.size();
 2280       }
 2281   
 2282       public DrawingManager2 getDrawingManager()
 2283       {
 2284           return drawingManager;
 2285       }
 2286   
 2287       public WriteProtectRecord getWriteProtect() {
 2288           if (this.writeProtect == null) {
 2289              this.writeProtect = new WriteProtectRecord();
 2290              int i = 0;
 2291              for (i = 0; 
 2292                   i < records.size() && !(records.get(i) instanceof BOFRecord); 
 2293                   i++) {
 2294              }
 2295              records.add(i+1,this.writeProtect);
 2296           }
 2297           return this.writeProtect;
 2298       }
 2299   
 2300       public WriteAccessRecord getWriteAccess() {
 2301           if (this.writeAccess == null) {
 2302              this.writeAccess = (WriteAccessRecord)createWriteAccess();
 2303              int i = 0;
 2304              for (i = 0; 
 2305                   i < records.size() && !(records.get(i) instanceof InterfaceEndRecord); 
 2306                   i++) {
 2307              }
 2308              records.add(i+1,this.writeAccess);
 2309           }
 2310           return this.writeAccess;
 2311       }
 2312   
 2313       public FileSharingRecord getFileSharing() {
 2314           if (this.fileShare == null) {
 2315              this.fileShare = new FileSharingRecord();
 2316              int i = 0;
 2317              for (i = 0; 
 2318                   i < records.size() && !(records.get(i) instanceof WriteAccessRecord); 
 2319                   i++) {
 2320              }
 2321              records.add(i+1,this.fileShare);
 2322           }
 2323           return this.fileShare;
 2324       }
 2325       
 2326       /**
 2327        * is the workbook protected with a password (not encrypted)?
 2328        */
 2329       public boolean isWriteProtected() {
 2330           if (this.fileShare == null) {
 2331           	return false;
 2332           }
 2333           FileSharingRecord frec = getFileSharing();
 2334           return (frec.getReadOnly() == 1);
 2335       }
 2336   
 2337       /**
 2338        * protect a workbook with a password (not encypted, just sets writeprotect
 2339        * flags and the password.
 2340        * @param password to set
 2341        */
 2342       public void writeProtectWorkbook( String password, String username ) {
 2343           int protIdx = -1;
 2344           FileSharingRecord frec = getFileSharing();
 2345           WriteAccessRecord waccess = getWriteAccess();
 2346           WriteProtectRecord wprotect = getWriteProtect();
 2347           frec.setReadOnly((short)1);
 2348           frec.setPassword(FileSharingRecord.hashPassword(password));
 2349           frec.setUsername(username);
 2350           waccess.setUsername(username);
 2351       }
 2352   
 2353       /**
 2354        * removes the write protect flag
 2355        */
 2356       public void unwriteProtectWorkbook() {
 2357           records.remove(fileShare);
 2358           records.remove(writeProtect);
 2359           fileShare = null;
 2360           writeProtect = null;
 2361       }
 2362   
 2363       /**
 2364        * @param refIndex Index to REF entry in EXTERNSHEET record in the Link Table
 2365        * @param definedNameIndex zero-based to DEFINEDNAME or EXTERNALNAME record
 2366        * @return the string representation of the defined or external name
 2367        */
 2368       public String resolveNameXText(int refIndex, int definedNameIndex) {
 2369           return linkTable.resolveNameXText(refIndex, definedNameIndex);
 2370       }
 2371   }
 2372   
 2373   

Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache » poi » hssf » model » [javadoc | source]