1 /********************************************************************* 2 * 3 * Copyright (C) 2002 Andrew Khan 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 ***************************************************************************/ 19 20 package jxl.write.biff; 21 22 import jxl.common.Assert; 23 import jxl.common.Logger; 24 25 import jxl.WorkbookSettings; 26 import jxl.biff.EncodedURLHelper; 27 import jxl.biff.IntegerHelper; 28 import jxl.biff.StringHelper; 29 import jxl.biff.Type; 30 import jxl.biff.WritableRecordData; 31 32 /** 33 * Stores the supporting workbook information. For files written by 34 * JExcelApi this will only reference internal sheets 35 */ 36 class SupbookRecord extends WritableRecordData 37 { 38 /** 39 * The logger 40 */ 41 private static Logger logger = Logger.getLogger(SupbookRecord.class); 42 43 /** 44 * The type of this supbook record 45 */ 46 private SupbookType type; 47 48 /** 49 * The data to be written to the binary file 50 */ 51 private byte[] data; 52 53 /** 54 * The number of sheets - internal & external supbooks only 55 */ 56 private int numSheets; 57 58 /** 59 * The name of the external file 60 */ 61 private String fileName; 62 63 /** 64 * The names of the external sheets 65 */ 66 private String[] sheetNames; 67 68 /** 69 * The workbook settings 70 */ 71 private WorkbookSettings workbookSettings; 72 73 /** 74 * The type of supbook this refers to 75 */ 76 private static class SupbookType {}; 77 78 public final static SupbookType INTERNAL = new SupbookType(); 79 public final static SupbookType EXTERNAL = new SupbookType(); 80 public final static SupbookType ADDIN = new SupbookType(); 81 public final static SupbookType LINK = new SupbookType(); 82 public final static SupbookType UNKNOWN = new SupbookType(); 83 84 /** 85 * Constructor for add in function names 86 */ 87 public SupbookRecord() 88 { 89 super(Type.SUPBOOK); 90 type = ADDIN; 91 } 92 93 /** 94 * Constructor for internal sheets 95 */ 96 public SupbookRecord(int sheets, WorkbookSettings ws) 97 { 98 super(Type.SUPBOOK); 99 100 numSheets = sheets; 101 type = INTERNAL; 102 workbookSettings = ws; 103 } 104 105 /** 106 * Constructor for external sheets 107 * 108 * @param fn the filename of the external supbook 109 * @param ws the workbook settings 110 */ 111 public SupbookRecord(String fn, WorkbookSettings ws) 112 { 113 super(Type.SUPBOOK); 114 115 fileName = fn; 116 numSheets = 1; 117 sheetNames = new String[0]; 118 workbookSettings = ws; 119 120 type = EXTERNAL; 121 } 122 123 /** 124 * Constructor used when copying from an external workbook 125 */ 126 public SupbookRecord(jxl.read.biff.SupbookRecord sr, WorkbookSettings ws) 127 { 128 super(Type.SUPBOOK); 129 130 workbookSettings = ws; 131 if (sr.getType() == sr.INTERNAL) 132 { 133 type = INTERNAL; 134 numSheets = sr.getNumberOfSheets(); 135 } 136 else if (sr.getType() == sr.EXTERNAL) 137 { 138 type = EXTERNAL; 139 numSheets = sr.getNumberOfSheets(); 140 fileName = sr.getFileName(); 141 sheetNames = new String[numSheets]; 142 143 for (int i = 0; i < numSheets; i++) 144 { 145 sheetNames[i] = sr.getSheetName(i); 146 } 147 } 148 149 if (sr.getType() == sr.ADDIN) 150 { 151 logger.warn("Supbook type is addin"); 152 } 153 } 154 155 /** 156 * Initializes an internal supbook record 157 * 158 * @param sr the read supbook record to copy from 159 */ 160 private void initInternal(jxl.read.biff.SupbookRecord sr) 161 { 162 numSheets = sr.getNumberOfSheets(); 163 initInternal(); 164 } 165 166 /** 167 * Initializes an internal supbook record 168 */ 169 private void initInternal() 170 { 171 data = new byte[4]; 172 173 IntegerHelper.getTwoBytes(numSheets, data, 0); 174 data[2] = 0x1; 175 data[3] = 0x4; 176 type = INTERNAL; 177 } 178 179 /** 180 * Adjust the number of internal sheets. Called by WritableSheet when 181 * a sheet is added or or removed to the workbook 182 * 183 * @param sheets the new number of sheets 184 */ 185 void adjustInternal(int sheets) 186 { 187 Assert.verify(type == INTERNAL); 188 numSheets = sheets; 189 initInternal(); 190 } 191 192 /** 193 * Initializes an external supbook record 194 */ 195 private void initExternal() 196 { 197 int totalSheetNameLength = 0; 198 for (int i = 0; i < numSheets; i++) 199 { 200 totalSheetNameLength += sheetNames[i].length(); 201 } 202 203 byte[] fileNameData = EncodedURLHelper.getEncodedURL(fileName, 204 workbookSettings); 205 int dataLength = 2 + // numsheets 206 4 + fileNameData.length + 207 numSheets * 3 + totalSheetNameLength * 2; 208 209 data = new byte[dataLength]; 210 211 IntegerHelper.getTwoBytes(numSheets, data, 0); 212 213 // Add in the file name. Precede with a byte denoting that it is a 214 // file name 215 int pos = 2; 216 IntegerHelper.getTwoBytes(fileNameData.length+1, data, pos); 217 data[pos+2] = 0; // ascii indicator 218 data[pos+3] = 1; // file name indicator 219 System.arraycopy(fileNameData, 0, data, pos+4, fileNameData.length); 220 221 pos += 4 + fileNameData.length; 222 223 // Get the sheet names 224 for (int i = 0; i < sheetNames.length; i++) 225 { 226 IntegerHelper.getTwoBytes(sheetNames[i].length(), data, pos); 227 data[pos+2] = 1; // unicode indicator 228 StringHelper.getUnicodeBytes(sheetNames[i], data, pos+3); 229 pos += 3 + sheetNames[i].length() * 2; 230 } 231 } 232 233 /** 234 * Initializes the supbook record for add in functions 235 */ 236 private void initAddin() 237 { 238 data = new byte[] {0x1, 0x0, 0x1, 0x3a}; 239 } 240 241 /** 242 * The binary data to be written out 243 * 244 * @return the binary data 245 */ 246 public byte[] getData() 247 { 248 if (type == INTERNAL) 249 { 250 initInternal(); 251 } 252 else if (type == EXTERNAL) 253 { 254 initExternal(); 255 } 256 else if (type == ADDIN) 257 { 258 initAddin(); 259 } 260 else 261 { 262 logger.warn("unsupported supbook type - defaulting to internal"); 263 initInternal(); 264 } 265 266 return data; 267 } 268 269 /** 270 * Gets the type of this supbook record 271 * 272 * @return the type of this supbook 273 */ 274 public SupbookType getType() 275 { 276 return type; 277 } 278 279 /** 280 * Gets the number of sheets. This will only be non-zero for internal 281 * and external supbooks 282 * 283 * @return the number of sheets 284 */ 285 public int getNumberOfSheets() 286 { 287 return numSheets; 288 } 289 290 /** 291 * Accessor for the file name 292 * 293 * @return the file name 294 */ 295 public String getFileName() 296 { 297 return fileName; 298 } 299 300 /** 301 * Adds the worksheet name to this supbook 302 * 303 * @param name the worksheet name 304 * @return the index of this sheet in the supbook record 305 */ 306 public int getSheetIndex(String s) 307 { 308 boolean found = false; 309 int sheetIndex = 0; 310 for (int i = 0; i < sheetNames.length && !found; i++) 311 { 312 if (sheetNames[i].equals(s)) 313 { 314 found = true; 315 sheetIndex = 0; 316 } 317 } 318 319 if (found) 320 { 321 return sheetIndex; 322 } 323 324 // Grow the array 325 String[] names = new String[sheetNames.length + 1]; 326 System.arraycopy(sheetNames, 0, names, 0, sheetNames.length); 327 names[sheetNames.length] = s; 328 sheetNames = names; 329 return sheetNames.length - 1; 330 } 331 332 /** 333 * Accessor for the sheet name 334 * 335 * @param s the sheet index 336 */ 337 public String getSheetName(int s) 338 { 339 return sheetNames[s]; 340 } 341 }