| 1 16 17 18 package org.apache.poi.hssf.model; 19 20 import org.apache.poi.ddf.*; 21 import org.apache.poi.hssf.record.*; 22 import org.apache.poi.hssf.util.HSSFColor; 23 import org.apache.poi.hssf.util.SheetReferences; 24 import org.apache.poi.util.POILogFactory; 25 import org.apache.poi.util.POILogger; 26 27 import java.util.ArrayList ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Locale ; 31 32 56 57 public class Workbook implements Model 58 { 59 private static final int DEBUG = POILogger.DEBUG; 60 61 63 67 68 private final static short CODEPAGE = ( short ) 0x4b0; 69 70 73 protected WorkbookRecordList records = new WorkbookRecordList(); 74 75 79 protected SSTRecord sst = null; 80 81 84 protected ExternSheetRecord externSheet= null; 85 86 90 protected ArrayList boundsheets = new ArrayList (); 91 92 protected ArrayList formats = new ArrayList (); 93 94 protected ArrayList names = new ArrayList (); 95 96 protected int numxfs = 0; protected int numfonts = 0; private short maxformatid = -1; private boolean uses1904datewindowing = false; private DrawingManager drawingManager; 101 102 private static POILogger log = POILogFactory.getLogger(Workbook.class); 103 104 108 public Workbook() { 109 } 110 111 123 public static Workbook createWorkbook(List recs) { 124 if (log.check( POILogger.DEBUG )) 125 log.log(DEBUG, "Workbook (readfile) created with reclen=", 126 new Integer (recs.size())); 127 Workbook retval = new Workbook(); 128 ArrayList records = new ArrayList (recs.size() / 3); 129 130 for (int k = 0; k < recs.size(); k++) { 131 Record rec = ( Record ) recs.get(k); 132 133 if (rec.getSid() == EOFRecord.sid) { 134 records.add(rec); 135 if (log.check( POILogger.DEBUG )) 136 log.log(DEBUG, "found workbook eof record at " + k); 137 break; 138 } 139 switch (rec.getSid()) { 140 141 case BoundSheetRecord.sid : 142 if (log.check( POILogger.DEBUG )) 143 log.log(DEBUG, "found boundsheet record at " + k); 144 retval.boundsheets.add(rec); 145 retval.records.setBspos( k ); 146 break; 147 148 case SSTRecord.sid : 149 if (log.check( POILogger.DEBUG )) 150 log.log(DEBUG, "found sst record at " + k); 151 retval.sst = ( SSTRecord ) rec; 152 break; 153 154 case FontRecord.sid : 155 if (log.check( POILogger.DEBUG )) 156 log.log(DEBUG, "found font record at " + k); 157 retval.records.setFontpos( k ); 158 retval.numfonts++; 159 break; 160 161 case ExtendedFormatRecord.sid : 162 if (log.check( POILogger.DEBUG )) 163 log.log(DEBUG, "found XF record at " + k); 164 retval.records.setXfpos( k ); 165 retval.numxfs++; 166 break; 167 168 case TabIdRecord.sid : 169 if (log.check( POILogger.DEBUG )) 170 log.log(DEBUG, "found tabid record at " + k); 171 retval.records.setTabpos( k ); 172 break; 173 174 case ProtectRecord.sid : 175 if (log.check( POILogger.DEBUG )) 176 log.log(DEBUG, "found protect record at " + k); 177 retval.records.setProtpos( k ); 178 break; 179 180 case BackupRecord.sid : 181 if (log.check( POILogger.DEBUG )) 182 log.log(DEBUG, "found backup record at " + k); 183 retval.records.setBackuppos( k ); 184 break; 185 case ExternSheetRecord.sid : 186 if (log.check( POILogger.DEBUG )) 187 log.log(DEBUG, "found extern sheet record at " + k); 188 retval.externSheet = ( ExternSheetRecord ) rec; 189 break; 190 case NameRecord.sid : 191 if (log.check( POILogger.DEBUG )) 192 log.log(DEBUG, "found name record at " + k); 193 retval.names.add(rec); 194 break; 196 case SupBookRecord.sid : 197 if (log.check( POILogger.DEBUG )) 198 log.log(DEBUG, "found SupBook record at " + k); 199 break; 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 default : 217 } 218 records.add(rec); 219 } 220 226 retval.records.setRecords(records); 227 if (log.check( POILogger.DEBUG )) 228 log.log(DEBUG, "exit create workbook from existing file function"); 229 return retval; 230 } 231 232 236 public static Workbook createWorkbook() 237 { 238 if (log.check( POILogger.DEBUG )) 239 log.log( DEBUG, "creating new workbook from scratch" ); 240 Workbook retval = new Workbook(); 241 ArrayList records = new ArrayList ( 30 ); 242 ArrayList formats = new ArrayList ( 8 ); 243 244 records.add( retval.createBOF() ); 245 records.add( retval.createInterfaceHdr() ); 246 records.add( retval.createMMS() ); 247 records.add( retval.createInterfaceEnd() ); 248 records.add( retval.createWriteAccess() ); 249 records.add( retval.createCodepage() ); 250 records.add( retval.createDSF() ); 251 records.add( retval.createTabId() ); 252 retval.records.setTabpos( records.size() - 1 ); 253 records.add( retval.createFnGroupCount() ); 254 records.add( retval.createWindowProtect() ); 255 records.add( retval.createProtect() ); 256 retval.records.setProtpos( records.size() - 1 ); 257 records.add( retval.createPassword() ); 258 records.add( retval.createProtectionRev4() ); 259 records.add( retval.createPasswordRev4() ); 260 records.add( retval.createWindowOne() ); 261 records.add( retval.createBackup() ); 262 retval.records.setBackuppos( records.size() - 1 ); 263 records.add( retval.createHideObj() ); 264 records.add( retval.createDateWindow1904() ); 265 records.add( retval.createPrecision() ); 266 records.add( retval.createRefreshAll() ); 267 records.add( retval.createBookBool() ); 268 records.add( retval.createFont() ); 269 records.add( retval.createFont() ); 270 records.add( retval.createFont() ); 271 records.add( retval.createFont() ); 272 retval.records.setFontpos( records.size() - 1 ); retval.numfonts = 4; 274 275 for ( int i = 0; i <= 7; i++ ) 277 { 278 Record rec; 279 rec = retval.createFormat( i ); 280 retval.maxformatid = retval.maxformatid >= ( (FormatRecord) rec ).getIndexCode() ? retval.maxformatid : ( (FormatRecord) rec ).getIndexCode(); 281 formats.add( rec ); 282 records.add( rec ); 283 } 284 retval.formats = formats; 285 286 for ( int k = 0; k < 21; k++ ) 287 { 288 records.add( retval.createExtendedFormat( k ) ); 289 retval.numxfs++; 290 } 291 retval.records.setXfpos( records.size() - 1 ); 292 for ( int k = 0; k < 6; k++ ) 293 { 294 records.add( retval.createStyle( k ) ); 295 } 296 records.add( retval.createUseSelFS() ); 297 for ( int k = 0; k < 1; k++ ) 298 { BoundSheetRecord bsr = 300 (BoundSheetRecord) retval.createBoundSheet( k ); 301 302 records.add( bsr ); 303 retval.boundsheets.add( bsr ); 304 retval.records.setBspos( records.size() - 1 ); 305 } 306 records.add( retval.createCountry() ); 309 retval.sst = (SSTRecord) retval.createSST(); 310 records.add( retval.sst ); 311 records.add( retval.createExtendedSST() ); 312 313 records.add( retval.createEOF() ); 314 retval.records.setRecords(records); 315 if (log.check( POILogger.DEBUG )) 316 log.log( DEBUG, "exit create new workbook from scratch" ); 317 return retval; 318 } 319 320 321 327 public NameRecord getSpecificBuiltinRecord(byte name, int sheetIndex) 328 { 329 Iterator iterator = names.iterator(); 330 while (iterator.hasNext()) { 331 NameRecord record = ( NameRecord ) iterator.next(); 332 333 if (record.getBuiltInName() == name && record.getIndexToSheet() == sheetIndex) { 335 return record; 336 } 337 } 338 339 return null; 340 341 } 342 343 348 public void removeBuiltinRecord(byte name, int sheetIndex) { 349 NameRecord record = getSpecificBuiltinRecord(name, sheetIndex); 352 if (record != null) { 353 names.remove(record); 354 } 355 356 } 357 358 public int getNumRecords() { 359 return records.size(); 360 } 361 362 370 371 public FontRecord getFontRecordAt(int idx) { 372 int index = idx; 373 374 if (index > 4) { 375 index -= 1; } 377 if (index > (numfonts - 1)) { 378 throw new ArrayIndexOutOfBoundsException ( 379 "There are only " + numfonts 380 + " font records, you asked for " + idx); 381 } 382 FontRecord retval = 383 ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + index); 384 385 return retval; 386 } 387 388 395 396 public FontRecord createNewFont() { 397 FontRecord rec = ( FontRecord ) createFont(); 398 399 records.add(records.getFontpos()+1, rec); 400 records.setFontpos( records.getFontpos() + 1 ); 401 numfonts++; 402 return rec; 403 } 404 405 410 411 public int getNumberOfFontRecords() { 412 return numfonts; 413 } 414 415 421 422 public void setSheetBof(int sheetnum, int pos) { 423 if (log.check( POILogger.DEBUG )) 424 log.log(DEBUG, "setting bof for sheetnum =", new Integer (sheetnum), 425 " at pos=", new Integer (pos)); 426 checkSheets(sheetnum); 427 (( BoundSheetRecord ) boundsheets.get(sheetnum)) 428 .setPositionOfBof(pos); 429 } 430 431 434 435 public BackupRecord getBackupRecord() { 436 return ( BackupRecord ) records.get(records.getBackuppos()); 437 } 438 439 440 448 449 public void setSheetName(int sheetnum, String sheetname ) { 451 setSheetName( sheetnum, sheetname, (byte)0 ); 452 } 453 454 461 public boolean doesContainsSheetName( String name, int excludeSheetIdx ) 462 { 463 for ( int i = 0; i < boundsheets.size(); i++ ) 464 { 465 BoundSheetRecord boundSheetRecord = (BoundSheetRecord) boundsheets.get( i ); 466 if (excludeSheetIdx != i && name.equals(boundSheetRecord.getSheetname())) 467 return true; 468 } 469 return false; 470 } 471 472 public void setSheetName(int sheetnum, String sheetname, short encoding ) { 473 checkSheets(sheetnum); 474 BoundSheetRecord sheet = (BoundSheetRecord)boundsheets.get( sheetnum ); 475 sheet.setSheetname(sheetname); 476 sheet.setSheetnameLength( (byte)sheetname.length() ); 477 sheet.setCompressedUnicodeFlag( (byte)encoding ); 478 } 479 480 486 487 public void setSheetOrder(String sheetname, int pos ) { 488 int sheetNumber = getSheetIndex(sheetname); 489 boundsheets.add(pos, boundsheets.remove(sheetNumber)); 491 } 492 493 499 500 public String getSheetName(int sheetnum) { 501 return (( BoundSheetRecord ) boundsheets.get(sheetnum)) 502 .getSheetname(); 503 } 504 505 510 511 public int getSheetIndex(String name) { 512 int retval = -1; 513 514 for (int k = 0; k < boundsheets.size(); k++) { 515 String sheet = getSheetName(k); 516 517 if (sheet.equalsIgnoreCase(name)) { 518 retval = k; 519 break; 520 } 521 } 522 return retval; 523 } 524 525 529 530 private void checkSheets(int sheetnum) { 531 if ((boundsheets.size()) <= sheetnum) { if ((boundsheets.size() + 1) <= sheetnum) { 533 throw new RuntimeException ("Sheet number out of bounds!"); 534 } 535 BoundSheetRecord bsr = (BoundSheetRecord ) createBoundSheet(sheetnum); 536 537 records.add(records.getBspos()+1, bsr); 538 records.setBspos( records.getBspos() + 1 ); 539 boundsheets.add(bsr); 540 fixTabIdRecord(); 541 } 542 } 543 544 public void removeSheet(int sheetnum) { 545 if (boundsheets.size() > sheetnum) { 546 records.remove(records.getBspos() - (boundsheets.size() - 1) + sheetnum); 547 boundsheets.remove(sheetnum); 549 fixTabIdRecord(); 550 } 551 } 552 553 557 private void fixTabIdRecord() { 558 TabIdRecord tir = ( TabIdRecord ) records.get(records.getTabpos()); 559 short[] tia = new short[ boundsheets.size() ]; 560 561 for (short k = 0; k < tia.length; k++) { 562 tia[ k ] = k; 563 } 564 tir.setTabIdArray(tia); 565 } 566 567 572 573 public int getNumSheets() { 574 if (log.check( POILogger.DEBUG )) 575 log.log(DEBUG, "getNumSheets=", new Integer (boundsheets.size())); 576 return boundsheets.size(); 577 } 578 579 584 585 public int getNumExFormats() { 586 if (log.check( POILogger.DEBUG )) 587 log.log(DEBUG, "getXF=", new Integer (numxfs)); 588 return numxfs; 589 } 590 591 597 598 public ExtendedFormatRecord getExFormatAt(int index) { 599 int xfptr = records.getXfpos() - (numxfs - 1); 600 601 xfptr += index; 602 ExtendedFormatRecord retval = 603 ( ExtendedFormatRecord ) records.get(xfptr); 604 605 return retval; 606 } 607 608 614 615 public ExtendedFormatRecord createCellXF() { 616 ExtendedFormatRecord xf = createExtendedFormat(); 617 618 records.add(records.getXfpos()+1, xf); 619 records.setXfpos( records.getXfpos() + 1 ); 620 numxfs++; 621 return xf; 622 } 623 624 632 633 public int addSSTString(String string, boolean use16bits) { 634 if (log.check( POILogger.DEBUG )) 635 log.log(DEBUG, "insert to sst string='", string, "' and use16bits= ", 636 new Boolean (use16bits)); 637 if (sst == null) { 638 insertSST(); 639 } 640 return sst.addString(string, use16bits); 641 } 642 643 652 653 public int addSSTString(String string) { 654 return addSSTString(string, false); 655 } 656 657 661 662 public String getSSTString(int str) { 663 if (sst == null) { 664 insertSST(); 665 } 666 String retval = sst.getString(str); 667 668 if (log.check( POILogger.DEBUG )) 669 log.log(DEBUG, "Returning SST for index=", new Integer (str), 670 " String= ", retval); 671 return retval; 672 } 673 674 680 681 public void insertSST() { 682 if (log.check( POILogger.DEBUG )) 683 log.log(DEBUG, "creating new SST via insertSST!"); 684 sst = ( SSTRecord ) createSST(); 685 records.add(records.size() - 1, createExtendedSST()); 686 records.add(records.size() - 2, sst); 687 } 688 689 695 717 723 724 public int serialize( int offset, byte[] data ) 725 { 726 if (log.check( POILogger.DEBUG )) 727 log.log( DEBUG, "Serializing Workbook with offsets" ); 728 729 int pos = 0; 730 731 SSTRecord sst = null; 732 int sstPos = 0; 733 for ( int k = 0; k < records.size(); k++ ) 734 { 735 736 Record record = records.get( k ); 737 if ( record.getSid() != RecalcIdRecord.sid || ( (RecalcIdRecord) record ).isNeeded() ) 739 { 740 if (record instanceof SSTRecord) 741 { 742 sst = (SSTRecord)record; 743 sstPos = pos; 744 } 745 if (record.getSid() == ExtSSTRecord.sid && sst != null) 746 { 747 record = sst.createExtSSTRecord(sstPos + offset); 748 } 749 pos += record.serialize( pos + offset, data ); } 751 } 752 if (log.check( POILogger.DEBUG )) 753 log.log( DEBUG, "Exiting serialize workbook" ); 754 return pos; 755 } 756 757 public int getSize() 758 { 759 int retval = 0; 760 761 SSTRecord sst = null; 762 for ( int k = 0; k < records.size(); k++ ) 763 { 764 Record record = records.get( k ); 765 if ( record.getSid() != RecalcIdRecord.sid || ( (RecalcIdRecord) record ).isNeeded() ) 767 { 768 if (record instanceof SSTRecord) 769 sst = (SSTRecord)record; 770 if (record.getSid() == ExtSSTRecord.sid && sst != null) 771 retval += sst.calcExtSSTRecordSize(); 772 else 773 retval += record.getRecordSize(); 774 } 775 } 776 return retval; 777 } 778 779 785 786 protected Record createBOF() { 787 BOFRecord retval = new BOFRecord(); 788 789 retval.setVersion(( short ) 0x600); 790 retval.setType(( short ) 5); 791 retval.setBuild(( short ) 0x10d3); 792 793 retval.setBuildYear(( short ) 1996); 795 retval.setHistoryBitMask(0x41); retval.setRequiredVersion(0x6); 797 return retval; 798 } 799 800 806 807 protected Record createInterfaceHdr() { 808 InterfaceHdrRecord retval = new InterfaceHdrRecord(); 809 810 retval.setCodepage(CODEPAGE); 811 return retval; 812 } 813 814 820 821 protected Record createMMS() { 822 MMSRecord retval = new MMSRecord(); 823 824 retval.setAddMenuCount(( byte ) 0); 825 retval.setDelMenuCount(( byte ) 0); 826 return retval; 827 } 828 829 835 836 protected Record createInterfaceEnd() { 837 return new InterfaceEndRecord(); 838 } 839 840 846 847 protected Record createWriteAccess() { 848 WriteAccessRecord retval = new WriteAccessRecord(); 849 850 try 851 { 852 retval.setUsername(System.getProperty("user.name")); 853 } 854 catch (java.security.AccessControlException e) 855 { 856 retval.setUsername("POI"); 859 } 860 return retval; 861 } 862 863 869 870 protected Record createCodepage() { 871 CodepageRecord retval = new CodepageRecord(); 872 873 retval.setCodepage(CODEPAGE); 874 return retval; 875 } 876 877 883 884 protected Record createDSF() { 885 DSFRecord retval = new DSFRecord(); 886 887 retval.setDsf( 888 ( short ) 0); return retval; 890 } 891 892 899 900 protected Record createTabId() { 901 TabIdRecord retval = new TabIdRecord(); 902 short[] tabidarray = { 903 0 904 }; 905 906 retval.setTabIdArray(tabidarray); 907 return retval; 908 } 909 910 916 917 protected Record createFnGroupCount() { 918 FnGroupCountRecord retval = new FnGroupCountRecord(); 919 920 retval.setCount(( short ) 14); 921 return retval; 922 } 923 924 930 931 protected Record createWindowProtect() { 932 WindowProtectRecord retval = new WindowProtectRecord(); 933 934 retval.setProtect( 935 false); return retval; } 938 939 |