1 /* ==================================================================== 2 * The Apache Software License, Version 1.1 3 * 4 * Copyright (c) 2002 The Apache Software Foundation. All rights 5 * reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The end-user documentation included with the redistribution, 20 * if any, must include the following acknowledgment: 21 * "This product includes software developed by the 22 * Apache Software Foundation (http://www.apache.org/)." 23 * Alternately, this acknowledgment may appear in the software itself, 24 * if and wherever such third-party acknowledgments normally appear. 25 * 26 * 4. The names "Apache" and "Apache Software Foundation" and 27 * "Apache POI" must not be used to endorse or promote products 28 * derived from this software without prior written permission. For 29 * written permission, please contact apache@apache.org. 30 * 31 * 5. Products derived from this software may not be called "Apache", 32 * "Apache POI", nor may "Apache" appear in their name, without 33 * prior written permission of the Apache Software Foundation. 34 * 35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This software consists of voluntary contributions made by many 50 * individuals on behalf of the Apache Software Foundation. For more 51 * information on the Apache Software Foundation, please see 52 * <http://www.apache.org/>. 53 */ 54 55 /* 56 * HSSFWorkbook.java 57 * 58 * Created on September 30, 2001, 3:37 PM 59 */ 60 package org.apache.poi.hssf.usermodel; 61 62 import org.apache.poi.util.POILogFactory; 63 import org.apache.poi.hssf.model.Sheet; 64 import org.apache.poi.hssf.model.Workbook; 65 import org.apache.poi.hssf.record.*; 66 import org.apache.poi.poifs.filesystem.POIFSFileSystem; 67 import org.apache.poi.util.POILogger; 68 69 import java.io.ByteArrayInputStream; 70 import java.io.IOException; 71 import java.io.InputStream; 72 import java.io.OutputStream; 73 import java.util.ArrayList; 74 import java.util.List; 75 76 /** 77 * High level representation of a workbook. This is the first object most users 78 * will construct whether they are reading or writing a workbook. It is also the 79 * top level object for creating new sheets/etc. 80 * 81 * @see org.apache.poi.hssf.model.Workbook 82 * @see org.apache.poi.hssf.usermodel.HSSFSheet 83 * @author Andrew C. Oliver (acoliver at apache dot org) 84 * @author Glen Stampoultzis (glens at apache.org) 85 * @version 2.0-pre 86 */ 87 88 public class HSSFWorkbook 89 extends java.lang.java.lang.Objectvate static final int DEBUG = POILogger.DEBUG; 90 91 /** 92 * used for compile-time performance/memory optimization. This determines the 93 * initial capacity for the sheet collection. Its currently set to 3. 94 * Changing it in this release will decrease performance 95 * since you're never allowed to have more or less than three sheets! 96 */ 97 98 public final static int INITIAL_CAPACITY = 3; 99 100 /** 101 * this is the reference to the low level Workbook object 102 */ 103 104 private Workbook workbook; 105 106 /** 107 * this holds the HSSFSheet objects attached to this workbook 108 */ 109 110 private ArrayList sheets; 111 private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class); 112 113 /** 114 * Creates new HSSFWorkbook from scratch (start here!) 115 * 116 */ 117 118 public HSSFWorkbook() 119 { 120 workbook = Workbook.createWorkbook(); 121 sheets = new ArrayList(INITIAL_CAPACITY); 122 } 123 124 /** 125 * given a POI POIFSFileSystem object, read in its Workbook and populate the high and 126 * low level models. If you're reading in a workbook...start here. 127 * 128 * @param fs the POI filesystem that contains the Workbook stream. 129 * @see org.apache.poi.poifs.filesystem.POIFSFileSystem 130 * @exception IOException if the stream cannot be read 131 */ 132 133 public HSSFWorkbook(POIFSFileSystem fs) 134 throws IOException 135 { 136 sheets = new ArrayList(INITIAL_CAPACITY); 137 InputStream stream = fs.createDocumentInputStream("Workbook"); 138 List records = RecordFactory.createRecords(stream); 139 140 workbook = Workbook.createWorkbook(records); 141 setPropertiesFromWorkbook(workbook); 142 int numRecords = workbook.getNumRecords(); 143 int sheetNum = 0; 144 145 while (numRecords < records.size()) 146 { 147 Sheet sheet = Sheet.createSheet(records, sheetNum++, numRecords); 148 149 numRecords += sheet.getNumRecords(); 150 sheet.convertLabelRecords( 151 workbook); // convert all LabelRecord records to LabelSSTRecord 152 HSSFSheet hsheet = new HSSFSheet(workbook, sheet); 153 154 sheets.add(hsheet); 155 156 // workbook.setSheetName(sheets.size() -1, "Sheet"+sheets.size()); 157 } 158 } 159 160 /** 161 * Companion to HSSFWorkbook(POIFSFileSystem), this constructs the POI filesystem around your 162 * inputstream. 163 * 164 * @param s the POI filesystem that contains the Workbook stream. 165 * @see org.apache.poi.poifs.filesystem.POIFSFileSystem 166 * @see #HSSFWorkbook(POIFSFileSystem) 167 * @exception IOException if the stream cannot be read 168 */ 169 170 public HSSFWorkbook(InputStream s) 171 throws IOException 172 { 173 this((new POIFSFileSystem(s))); 174 } 175 176 /** 177 * used internally to set the workbook properties. 178 */ 179 180 private void setPropertiesFromWorkbook(Workbook book) 181 { 182 this.workbook = book; 183 184 // none currently 185 } 186 187 /** 188 * set the sheet name. 189 * @param sheet number (0 based) 190 * @param sheet name 191 */ 192 193 public void setSheetName(int sheet, String name) 194 { 195 if (sheet > (sheets.size() - 1)) 196 { 197 throw new RuntimeException("Sheet out of bounds"); 198 } 199 workbook.setSheetName(sheet, name); 200 } 201 202 /** 203 * get the sheet name 204 * @param sheet Number 205 * @return Sheet name 206 */ 207 208 public String getSheetName(int sheet) 209 { 210 if (sheet > (sheets.size() - 1)) 211 { 212 throw new RuntimeException("Sheet out of bounds"); 213 } 214 return workbook.getSheetName(sheet); 215 } 216 217 /** 218 * get the sheet's index 219 * @param name sheet name 220 * @return sheet index or -1 if it was not found. 221 */ 222 223 public int getSheetIndex(String name) 224 { 225 int retval = -1; 226 227 for (int k = 0; k < sheets.size(); k++) 228 { 229 String sheet = workbook.getSheetName(k); 230 231 if (sheet.equals(name)) 232 { 233 retval = k; 234 break; 235 } 236 } 237 return retval; 238 } 239 240 /** 241 * create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and returns 242 * the high level representation. Use this to create new sheets. 243 * 244 * @return HSSFSheet representing the new sheet. 245 */ 246 247 public HSSFSheet createSheet() 248 { 249 250 // if (getNumberOfSheets() == 3) 251 // throw new RuntimeException("You cannot have more than three sheets in HSSF 1.0"); 252 HSSFSheet sheet = new HSSFSheet(workbook); 253 254 sheets.add(sheet); 255 workbook.setSheetName(sheets.size() - 1, 256 "Sheet" + (sheets.size() - 1)); 257 WindowTwoRecord windowTwo = (WindowTwoRecord) sheet.getSheet().findFirstRecordBySid(WindowTwoRecord.sid); 258 windowTwo.setSelected(sheets.size() == 1); 259 windowTwo.setPaged(sheets.size() == 1); 260 return sheet; 261 } 262 263 /** 264 * create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and returns 265 * the high level representation. Use this to create new sheets. 266 * 267 * @param sheetname sheetname to set for the sheet. 268 * @return HSSFSheet representing the new sheet. 269 */ 270 271 public HSSFSheet createSheet(String sheetname) 272 { 273 274 // if (getNumberOfSheets() == 3) 275 // throw new RuntimeException("You cannot have more than three sheets in HSSF 1.0"); 276 HSSFSheet sheet = new HSSFSheet(workbook); 277 278 sheets.add(sheet); 279 workbook.setSheetName(sheets.size() - 1, sheetname); 280 WindowTwoRecord windowTwo = (WindowTwoRecord) sheet.getSheet().findFirstRecordBySid(WindowTwoRecord.sid); 281 windowTwo.setSelected(sheets.size() == 1); 282 windowTwo.setPaged(sheets.size() == 1); 283 return sheet; 284 } 285 286 /** 287 * get the number of spreadsheets in the workbook (this will be three after serialization) 288 * @return number of sheets 289 */ 290 291 public int getNumberOfSheets() 292 { 293 return sheets.size(); 294 } 295 296 /** 297 * Get the HSSFSheet object at the given index. 298 * @param index of the sheet number (0-based physical & logical) 299 * @return HSSFSheet at the provided index 300 */ 301 302 public HSSFSheet getSheetAt(int index) 303 { 304 return (HSSFSheet) sheets.get(index); 305 } 306 307 /** 308 * Get sheet with the given name 309 * @param name of the sheet 310 * @return HSSFSheet with the name provided or null if it does not exist 311 */ 312 313 public HSSFSheet getSheet(String name) 314 { 315 HSSFSheet retval = null; 316 317 for (int k = 0; k < sheets.size(); k++) 318 { 319 String sheetname = workbook.getSheetName(k); 320 321 if (sheetname.equals(name)) 322 { 323 retval = (HSSFSheet) sheets.get(k); 324 } 325 } 326 return retval; 327 } 328 329 /** 330 * removes sheet at the given index 331 * @param index of the sheet (0-based) 332 */ 333 334 public void removeSheetAt(int index) 335 { 336 sheets.remove(index); 337 workbook.removeSheet(index); 338 } 339 340 /** 341 * determine whether the Excel GUI will backup the workbook when saving. 342 * 343 * @param backupValue true to indicate a backup will be performed. 344 */ 345 346 public void setBackupFlag(boolean backupValue) 347 { 348 BackupRecord backupRecord = workbook.getBackupRecord(); 349 350 backupRecord.setBackup(backupValue ? (short) 1 351 : (short) 0); 352 } 353 354 /** 355 * determine whether the Excel GUI will backup the workbook when saving. 356 * 357 * @return the current setting for backups. 358 */ 359 360 public boolean getBackupFlag() 361 { 362 BackupRecord backupRecord = workbook.getBackupRecord(); 363 364 return (backupRecord.getBackup() == 0) ? false 365 : true; 366 } 367 368 /** 369 * create a new Font and add it to the workbook's font table 370 * @return new font object 371 */ 372 373 public HSSFFont createFont() 374 { 375 FontRecord font = workbook.createNewFont(); 376 short fontindex = (short) (getNumberOfFonts() - 1); 377 378 if (fontindex > 3) 379 { 380 fontindex++; // THERE IS NO FOUR!! 381 } 382 HSSFFont retval = new HSSFFont(fontindex, font); 383 384 return retval; 385 } 386 387 /** 388 * get the number of fonts in the font table 389 * @return number of fonts 390 */ 391 392 public short getNumberOfFonts() 393 { 394 return (short) workbook.getNumberOfFontRecords(); 395 } 396 397 /** 398 * get the font at the given index number 399 * @param idx index number 400 * @return HSSFFont at the index 401 */ 402 403 public HSSFFont getFontAt(short idx) 404 { 405 FontRecord font = workbook.getFontRecordAt(idx); 406 HSSFFont retval = new HSSFFont(idx, font); 407 408 return retval; 409 } 410 411 /** 412 * create a new Cell style and add it to the workbook's style table 413 * @return the new Cell Style object 414 */ 415 416 public HSSFCellStyle createCellStyle() 417 { 418 ExtendedFormatRecord xfr = workbook.createCellXF(); 419 short index = (short) (getNumCellStyles() - 1); 420 HSSFCellStyle style = new HSSFCellStyle(index, xfr); 421 422 return style; 423 } 424 425 /** 426 * get the number of styles the workbook contains 427 * @return count of cell styles 428 */ 429 430 public short getNumCellStyles() 431 { 432 return (short) workbook.getNumExFormats(); 433 } 434 435 /** 436 * get the cell style object at the given index 437 * @param idx index within the set of styles 438 * @return HSSFCellStyle object at the index 439 */ 440 441 public HSSFCellStyle getCellStyleAt(short idx) 442 { 443 ExtendedFormatRecord xfr = workbook.getExFormatAt(idx); 444 HSSFCellStyle style = new HSSFCellStyle(idx, xfr); 445 446 return style; 447 } 448 449 /** 450 * Method write - write out this workbook to an Outputstream. Constructs 451 * a new POI POIFSFileSystem, passes in the workbook binary representation and 452 * writes it out. 453 * 454 * @param stream - the java OutputStream you wish to write the XLS to 455 * 456 * @exception IOException if anything can't be written. 457 * @see org.apache.poi.poifs.filesystem.POIFSFileSystem 458 */ 459 460 public void write(OutputStream stream) 461 throws IOException 462 { 463 byte[] bytes = getBytes(); 464 POIFSFileSystem fs = new POIFSFileSystem(); 465 466 fs.createDocument(new ByteArrayInputStream(bytes), "Workbook"); 467 fs.writeFilesystem(stream); 468 } 469 470 /** 471 * Method getBytes - get the bytes of just the HSSF portions of the XLS file. 472 * Use this to construct a POI POIFSFileSystem yourself. 473 * 474 * 475 * @return byte[] array containing the binary representation of this workbook and all contained 476 * sheets, rows, cells, etc. 477 * 478 * @see org.apache.poi.hssf.model.Workbook 479 * @see org.apache.poi.hssf.model.Sheet 480 */ 481 482 public byte[] getBytes() 483 { 484 log.log(DEBUG, "HSSFWorkbook.getBytes()"); 485 int wbsize = workbook.getSize(); 486 487 // log.debug("REMOVEME: old sizing method "+workbook.serialize().length); 488 // ArrayList sheetbytes = new ArrayList(sheets.size()); 489 int totalsize = wbsize; 490 491 for (int k = 0; k < sheets.size(); k++) 492 { 493 workbook.setSheetBof(k, totalsize); 494 495 // sheetbytes.add((( HSSFSheet ) sheets.get(k)).getSheet().getSize()); 496 totalsize += ((HSSFSheet) sheets.get(k)).getSheet().getSize(); 497 } 498 if (totalsize < 4096) 499 { 500 totalsize = 4096; 501 } 502 byte[] retval = new byte[totalsize]; 503 int pos = workbook.serialize(0, retval); 504 505 // System.arraycopy(wb, 0, retval, 0, wb.length); 506 for (int k = 0; k < sheets.size(); k++) 507 { 508 509 // byte[] sb = (byte[])sheetbytes.get(k); 510 // System.arraycopy(sb, 0, retval, pos, sb.length); 511 pos += ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos, 512 retval); // sb.length; 513 } 514 for (int k = pos; k < totalsize; k++) 515 { 516 retval[k] = 0; 517 } 518 return retval; 519 } 520 521 public int addSSTString(String string) 522 { 523 return workbook.addSSTString(string); 524 } 525 526 public String getSSTString(int index) 527 { 528 return workbook.getSSTString(index); 529 } 530 531 Workbook getWorkbook() 532 { 533 return workbook; 534 } 535 } 536