/** Constructor called when doing a cell deep copy */ public DVParser(DVParser copy) { copied = true; type = copy.type; errorStyle = copy.errorStyle; condition = copy.condition; stringListGiven = copy.stringListGiven; emptyCellsAllowed = copy.emptyCellsAllowed; suppressArrow = copy.suppressArrow; showPrompt = copy.showPrompt; showError = copy.showError; promptTitle = copy.promptTitle; promptText = copy.promptText; errorTitle = copy.errorTitle; errorText = copy.errorText; extendedCellsValidation = copy.extendedCellsValidation; row1 = copy.row1; row2 = copy.row2; column1 = copy.column1; column2 = copy.column2; // Don't copy the formula parsers - just take their string equivalents if (copy.formula1String != null) { formula1String = copy.formula1String; formula2String = copy.formula2String; } else { try { formula1String = copy.formula1.getFormula(); formula2String = (copy.formula2 != null) ? copy.formula2.getFormula() : null; } catch (FormulaException e) { logger.warn("Cannot parse validation formula: " + e.getMessage()); } } // Don't copy the cell references - these will be added later }
/** * Constructor for a double value when reading from a string * * @param s the string representation of this token */ public DoubleValue(String s) { try { value = Double.parseDouble(s); } catch (NumberFormatException e) { logger.warn(e, e); value = 0; } }
/* 6: */ /* 7: */ class MulRKRecord /* 8: */ extends RecordData /* 9: */ { /* 10: 35 */ private static Logger logger = Logger.getLogger(MulRKRecord.class); /* 11: */ private int row; /* 12: */ private int colFirst; /* 13: */ private int colLast; /* 14: */ private int numrks; /* 15: */ private int[] rknumbers; /* 16: */ private int[] xfIndices; /* 17: */ /* 18: */ public MulRKRecord(Record t) /* 19: */ { /* 20: 69 */ super(t); /* 21: 70 */ byte[] data = getRecord().getData(); /* 22: 71 */ int length = getRecord().getLength(); /* 23: 72 */ this.row = IntegerHelper.getInt(data[0], data[1]); /* 24: 73 */ this.colFirst = IntegerHelper.getInt(data[2], data[3]); /* 25: 74 */ this.colLast = IntegerHelper.getInt(data[(length - 2)], data[(length - 1)]); /* 26: 75 */ this.numrks = (this.colLast - this.colFirst + 1); /* 27: 76 */ this.rknumbers = new int[this.numrks]; /* 28: 77 */ this.xfIndices = new int[this.numrks]; /* 29: */ /* 30: 79 */ readRks(data); /* 31: */ } /* 32: */ /* 33: */ private void readRks(byte[] data) /* 34: */ { /* 35: 89 */ int pos = 4; /* 36: 91 */ for (int i = 0; i < this.numrks; i++) /* 37: */ { /* 38: 93 */ this.xfIndices[i] = IntegerHelper.getInt(data[pos], data[(pos + 1)]); /* 39: 94 */ int rk = IntegerHelper.getInt(data[(pos + 2)], data[(pos + 3)], data[(pos + 4)], data[(pos + 5)]); /* 40: */ /* 41: 96 */ this.rknumbers[i] = rk; /* 42: 97 */ pos += 6; /* 43: */ } /* 44: */ } /* 45: */ /* 46: */ public int getRow() /* 47: */ { /* 48:108 */ return this.row; /* 49: */ } /* 50: */ /* 51: */ public int getFirstColumn() /* 52: */ { /* 53:118 */ return this.colFirst; /* 54: */ } /* 55: */ /* 56: */ public int getNumberOfColumns() /* 57: */ { /* 58:128 */ return this.numrks; /* 59: */ } /* 60: */ /* 61: */ public int getRKNumber(int index) /* 62: */ { /* 63:139 */ return this.rknumbers[index]; /* 64: */ } /* 65: */ /* 66: */ public int getXFIndex(int index) /* 67: */ { /* 68:150 */ return this.xfIndices[index]; /* 69: */ } /* 70: */ }
/** Constructor called when creating a data validation from the API */ public DVParser(Collection strings) { copied = false; type = LIST; errorStyle = STOP; condition = BETWEEN; extendedCellsValidation = false; // the options stringListGiven = true; emptyCellsAllowed = true; suppressArrow = false; showPrompt = true; showError = true; promptTitle = "\0"; errorTitle = "\0"; promptText = "\0"; errorText = "\0"; if (strings.size() == 0) { logger.warn("no validation strings - ignoring"); } Iterator i = strings.iterator(); StringBuffer formulaString = new StringBuffer(); formulaString.append(i.next().toString()); while (i.hasNext()) { formulaString.append('\0'); formulaString.append(' '); formulaString.append(i.next().toString()); } // If the formula string exceeds // the maximum validation list length, then truncate and stop there if (formulaString.length() > MAX_VALIDATION_LIST_LENGTH) { logger.warn("Validation list exceeds maximum number of characters - " + "truncating"); formulaString.delete(MAX_VALIDATION_LIST_LENGTH, formulaString.length()); } // Put the string in quotes formulaString.insert(0, '\"'); formulaString.append('\"'); formula1String = formulaString.toString(); }
@Test public void test() { try { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); CupTxnUtil cupTxnUtil = (CupTxnUtil) context.getBean("cupTxnUtil"); String option = "state"; int len = cupTxnUtil.getSize(option); assertEquals(len, 304); } catch (Exception ex) { logger.debug("Exception occur while process", ex); fail("Not yet implemented"); } }
/* 99: */ /* 100: */ public void add(DrawingGroupObject d) /* 101: */ { /* 102:233 */ if (this.origin == Origin.READ) /* 103: */ { /* 104:235 */ this.origin = Origin.READ_WRITE; /* 105:236 */ BStoreContainer bsc = getBStoreContainer(); /* 106:237 */ Dgg dgg = (Dgg) this.escherData.getChildren()[0]; /* 107:238 */ this.drawingGroupId = (dgg.getCluster(1).drawingGroupId - this.numBlips - 1); /* 108:239 */ this.numBlips = (bsc != null ? bsc.getNumBlips() : 0); /* 109:241 */ if (bsc != null) { /* 110:243 */ Assert.verify(this.numBlips == bsc.getNumBlips()); /* 111: */ } /* 112: */ } /* 113:247 */ if (!(d instanceof Drawing)) /* 114: */ { /* 115:251 */ this.maxObjectId += 1; /* 116:252 */ this.maxShapeId += 1; /* 117:253 */ d.setDrawingGroup(this); /* 118:254 */ d.setObjectId(this.maxObjectId, this.numBlips + 1, this.maxShapeId); /* 119:255 */ if (this.drawings.size() > this.maxObjectId) { /* 120:257 */ logger.warn( "drawings length " + this.drawings.size() + " exceeds the max object id " + this.maxObjectId); /* 121: */ } /* 122:261 */ return; /* 123: */ } /* 124:264 */ Drawing drawing = (Drawing) d; /* 125: */ /* 126: */ /* 127:267 */ Drawing refImage = (Drawing) this.imageFiles.get(d.getImageFilePath()); /* 128:270 */ if (refImage == null) /* 129: */ { /* 130:274 */ this.maxObjectId += 1; /* 131:275 */ this.maxShapeId += 1; /* 132:276 */ this.drawings.add(drawing); /* 133:277 */ drawing.setDrawingGroup(this); /* 134:278 */ drawing.setObjectId(this.maxObjectId, this.numBlips + 1, this.maxShapeId); /* 135:279 */ this.numBlips += 1; /* 136:280 */ this.imageFiles.put(drawing.getImageFilePath(), drawing); /* 137: */ } /* 138: */ else /* 139: */ { /* 140:287 */ refImage.setReferenceCount(refImage.getReferenceCount() + 1); /* 141:288 */ drawing.setDrawingGroup(this); /* 142:289 */ drawing.setObjectId( refImage.getObjectId(), refImage.getBlipId(), refImage.getShapeId()); /* 143: */ } /* 144: */ }
/** * Gets the name of the external sheet specified by the index * * @param index the external sheet index * @return the name of the external sheet */ public String getLastExternalSheetName(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(index); return br.getName(); } int supbookIndex = externSheet.getSupbookIndex(index); SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex); int lastTab = externSheet.getLastTabIndex(index); if (sr.getType() == SupbookRecord.INTERNAL) { // It's an internal reference - get the name from the boundsheets list if (lastTab == 65535) { return "#REF"; } else { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(lastTab); return br.getName(); } } else if (sr.getType() == SupbookRecord.EXTERNAL) { // External reference - get the sheet name from the supbook record StringBuffer sb = new StringBuffer(); java.io.File fl = new java.io.File(sr.getFileName()); sb.append("'"); sb.append(fl.getAbsolutePath()); sb.append("["); sb.append(fl.getName()); sb.append("]"); sb.append((lastTab == 65535) ? "#REF" : sr.getSheetName(lastTab)); sb.append("'"); return sb.toString(); } // An unknown supbook - return unkown logger.warn("Unknown Supbook 4"); return "[UNKNOWN]"; }
/* 6: */ /* 7: */ class PaneRecord /* 8: */ extends RecordData /* 9: */ { /* 10:35 */ private static Logger logger = Logger.getLogger(PaneRecord.class); /* 11: */ private int rowsVisible; /* 12: */ private int columnsVisible; /* 13: */ /* 14: */ public PaneRecord(Record t) /* 15: */ { /* 16:53 */ super(t); /* 17:54 */ byte[] data = t.getData(); /* 18: */ /* 19:56 */ this.columnsVisible = IntegerHelper.getInt(data[0], data[1]); /* 20:57 */ this.rowsVisible = IntegerHelper.getInt(data[2], data[3]); /* 21: */ } /* 22: */ /* 23: */ public final int getRowsVisible() /* 24: */ { /* 25:67 */ return this.rowsVisible; /* 26: */ } /* 27: */ /* 28: */ public final int getColumnsVisible() /* 29: */ { /* 30:77 */ return this.columnsVisible; /* 31: */ } /* 32: */ }
/* 11: */ /* 12: */ public class DrawingGroup /* 13: */ implements EscherStream /* 14: */ { /* 15: 42 */ private static Logger logger = Logger.getLogger(DrawingGroup.class); /* 16: */ private byte[] drawingData; /* 17: */ private EscherContainer escherData; /* 18: */ private BStoreContainer bstoreContainer; /* 19: */ private boolean initialized; /* 20: */ private ArrayList drawings; /* 21: */ private int numBlips; /* 22: */ private int numCharts; /* 23: */ private int drawingGroupId; /* 24: */ private boolean drawingsOmitted; /* 25: */ private Origin origin; /* 26: */ private HashMap imageFiles; /* 27: */ private int maxObjectId; /* 28: */ private int maxShapeId; /* 29: */ /* 30: */ public DrawingGroup(Origin o) /* 31: */ { /* 32:118 */ this.origin = o; /* 33:119 */ this.initialized = (o == Origin.WRITE); /* 34:120 */ this.drawings = new ArrayList(); /* 35:121 */ this.imageFiles = new HashMap(); /* 36:122 */ this.drawingsOmitted = false; /* 37:123 */ this.maxObjectId = 1; /* 38:124 */ this.maxShapeId = 1024; /* 39: */ } /* 40: */ /* 41: */ public DrawingGroup(DrawingGroup dg) /* 42: */ { /* 43:137 */ this.drawingData = dg.drawingData; /* 44:138 */ this.escherData = dg.escherData; /* 45:139 */ this.bstoreContainer = dg.bstoreContainer; /* 46:140 */ this.initialized = dg.initialized; /* 47:141 */ this.drawingData = dg.drawingData; /* 48:142 */ this.escherData = dg.escherData; /* 49:143 */ this.bstoreContainer = dg.bstoreContainer; /* 50:144 */ this.numBlips = dg.numBlips; /* 51:145 */ this.numCharts = dg.numCharts; /* 52:146 */ this.drawingGroupId = dg.drawingGroupId; /* 53:147 */ this.drawingsOmitted = dg.drawingsOmitted; /* 54:148 */ this.origin = dg.origin; /* 55:149 */ this.imageFiles = ((HashMap) dg.imageFiles.clone()); /* 56:150 */ this.maxObjectId = dg.maxObjectId; /* 57:151 */ this.maxShapeId = dg.maxShapeId; /* 58: */ /* 59: */ /* 60: */ /* 61:155 */ this.drawings = new ArrayList(); /* 62: */ } /* 63: */ /* 64: */ public void add(MsoDrawingGroupRecord mso) /* 65: */ { /* 66:169 */ addData(mso.getData()); /* 67: */ } /* 68: */ /* 69: */ public void add(Record cont) /* 70: */ { /* 71:180 */ addData(cont.getData()); /* 72: */ } /* 73: */ /* 74: */ private void addData(byte[] msodata) /* 75: */ { /* 76:190 */ if (this.drawingData == null) /* 77: */ { /* 78:192 */ this.drawingData = new byte[msodata.length]; /* 79:193 */ System.arraycopy(msodata, 0, this.drawingData, 0, msodata.length); /* 80:194 */ return; /* 81: */ } /* 82:198 */ byte[] newdata = new byte[this.drawingData.length + msodata.length]; /* 83:199 */ System.arraycopy(this.drawingData, 0, newdata, 0, this.drawingData.length); /* 84:200 */ System.arraycopy(msodata, 0, newdata, this.drawingData.length, msodata.length); /* 85:201 */ this.drawingData = newdata; /* 86: */ } /* 87: */ /* 88: */ final void addDrawing(DrawingGroupObject d) /* 89: */ { /* 90:211 */ this.drawings.add(d); /* 91:212 */ this.maxObjectId = Math.max(this.maxObjectId, d.getObjectId()); /* 92:213 */ this.maxShapeId = Math.max(this.maxShapeId, d.getShapeId()); /* 93: */ } /* 94: */ /* 95: */ public void add(Chart c) /* 96: */ { /* 97:223 */ this.numCharts += 1; /* 98: */ } /* 99: */ /* 100: */ public void add(DrawingGroupObject d) /* 101: */ { /* 102:233 */ if (this.origin == Origin.READ) /* 103: */ { /* 104:235 */ this.origin = Origin.READ_WRITE; /* 105:236 */ BStoreContainer bsc = getBStoreContainer(); /* 106:237 */ Dgg dgg = (Dgg) this.escherData.getChildren()[0]; /* 107:238 */ this.drawingGroupId = (dgg.getCluster(1).drawingGroupId - this.numBlips - 1); /* 108:239 */ this.numBlips = (bsc != null ? bsc.getNumBlips() : 0); /* 109:241 */ if (bsc != null) { /* 110:243 */ Assert.verify(this.numBlips == bsc.getNumBlips()); /* 111: */ } /* 112: */ } /* 113:247 */ if (!(d instanceof Drawing)) /* 114: */ { /* 115:251 */ this.maxObjectId += 1; /* 116:252 */ this.maxShapeId += 1; /* 117:253 */ d.setDrawingGroup(this); /* 118:254 */ d.setObjectId(this.maxObjectId, this.numBlips + 1, this.maxShapeId); /* 119:255 */ if (this.drawings.size() > this.maxObjectId) { /* 120:257 */ logger.warn( "drawings length " + this.drawings.size() + " exceeds the max object id " + this.maxObjectId); /* 121: */ } /* 122:261 */ return; /* 123: */ } /* 124:264 */ Drawing drawing = (Drawing) d; /* 125: */ /* 126: */ /* 127:267 */ Drawing refImage = (Drawing) this.imageFiles.get(d.getImageFilePath()); /* 128:270 */ if (refImage == null) /* 129: */ { /* 130:274 */ this.maxObjectId += 1; /* 131:275 */ this.maxShapeId += 1; /* 132:276 */ this.drawings.add(drawing); /* 133:277 */ drawing.setDrawingGroup(this); /* 134:278 */ drawing.setObjectId(this.maxObjectId, this.numBlips + 1, this.maxShapeId); /* 135:279 */ this.numBlips += 1; /* 136:280 */ this.imageFiles.put(drawing.getImageFilePath(), drawing); /* 137: */ } /* 138: */ else /* 139: */ { /* 140:287 */ refImage.setReferenceCount(refImage.getReferenceCount() + 1); /* 141:288 */ drawing.setDrawingGroup(this); /* 142:289 */ drawing.setObjectId( refImage.getObjectId(), refImage.getBlipId(), refImage.getShapeId()); /* 143: */ } /* 144: */ } /* 145: */ /* 146: */ public void remove(DrawingGroupObject d) /* 147: */ { /* 148:304 */ if (getBStoreContainer() == null) { /* 149:306 */ return; /* 150: */ } /* 151:309 */ if (this.origin == Origin.READ) /* 152: */ { /* 153:311 */ this.origin = Origin.READ_WRITE; /* 154:312 */ this.numBlips = getBStoreContainer().getNumBlips(); /* 155:313 */ Dgg dgg = (Dgg) this.escherData.getChildren()[0]; /* 156:314 */ this.drawingGroupId = (dgg.getCluster(1).drawingGroupId - this.numBlips - 1); /* 157: */ } /* 158:318 */ EscherRecord[] children = getBStoreContainer().getChildren(); /* 159:319 */ BlipStoreEntry bse = (BlipStoreEntry) children[(d.getBlipId() - 1)]; /* 160: */ /* 161:321 */ bse.dereference(); /* 162:323 */ if (bse.getReferenceCount() == 0) /* 163: */ { /* 164:326 */ getBStoreContainer().remove(bse); /* 165:329 */ for (Iterator i = this.drawings.iterator(); i.hasNext(); ) /* 166: */ { /* 167:331 */ DrawingGroupObject drawing = (DrawingGroupObject) i.next(); /* 168:333 */ if (drawing.getBlipId() > d.getBlipId()) { /* 169:335 */ drawing.setObjectId( drawing.getObjectId(), drawing.getBlipId() - 1, drawing.getShapeId()); /* 170: */ } /* 171: */ } /* 172:341 */ this.numBlips -= 1; /* 173: */ } /* 174: */ } /* 175: */ /* 176: */ private void initialize() /* 177: */ { /* 178:351 */ EscherRecordData er = new EscherRecordData(this, 0); /* 179: */ /* 180:353 */ Assert.verify(er.isContainer()); /* 181: */ /* 182:355 */ this.escherData = new EscherContainer(er); /* 183: */ /* 184:357 */ Assert.verify(this.escherData.getLength() == this.drawingData.length); /* 185:358 */ Assert.verify(this.escherData.getType() == EscherRecordType.DGG_CONTAINER); /* 186: */ /* 187:360 */ this.initialized = true; /* 188: */ } /* 189: */ /* 190: */ private BStoreContainer getBStoreContainer() /* 191: */ { /* 192:370 */ if (this.bstoreContainer == null) /* 193: */ { /* 194:372 */ if (!this.initialized) { /* 195:374 */ initialize(); /* 196: */ } /* 197:377 */ EscherRecord[] children = this.escherData.getChildren(); /* 198:378 */ if ((children.length > 1) && (children[1].getType() == EscherRecordType.BSTORE_CONTAINER)) { /* 199:381 */ this.bstoreContainer = ((BStoreContainer) children[1]); /* 200: */ } /* 201: */ } /* 202:385 */ return this.bstoreContainer; /* 203: */ } /* 204: */ /* 205: */ public byte[] getData() /* 206: */ { /* 207:395 */ return this.drawingData; /* 208: */ } /* 209: */ /* 210: */ public void write(File outputFile) /* 211: */ throws IOException /* 212: */ { /* 213:406 */ if (this.origin == Origin.WRITE) /* 214: */ { /* 215:408 */ DggContainer dggContainer = new DggContainer(); /* 216: */ /* 217:410 */ Dgg dgg = new Dgg(this.numBlips + this.numCharts + 1, this.numBlips); /* 218: */ /* 219:412 */ dgg.addCluster(1, 0); /* 220:413 */ dgg.addCluster(this.numBlips + 1, 0); /* 221: */ /* 222:415 */ dggContainer.add(dgg); /* 223: */ /* 224:417 */ int drawingsAdded = 0; /* 225:418 */ BStoreContainer bstoreCont = new BStoreContainer(); /* 226:421 */ for (Iterator i = this.drawings.iterator(); i.hasNext(); ) /* 227: */ { /* 228:423 */ Object o = i.next(); /* 229:424 */ if ((o instanceof Drawing)) /* 230: */ { /* 231:426 */ Drawing d = (Drawing) o; /* 232:427 */ BlipStoreEntry bse = new BlipStoreEntry(d); /* 233: */ /* 234:429 */ bstoreCont.add(bse); /* 235:430 */ drawingsAdded++; /* 236: */ } /* 237: */ } /* 238:433 */ if (drawingsAdded > 0) /* 239: */ { /* 240:435 */ bstoreCont.setNumBlips(drawingsAdded); /* 241:436 */ dggContainer.add(bstoreCont); /* 242: */ } /* 243:439 */ Opt opt = new Opt(); /* 244: */ /* 245:441 */ dggContainer.add(opt); /* 246: */ /* 247:443 */ SplitMenuColors splitMenuColors = new SplitMenuColors(); /* 248:444 */ dggContainer.add(splitMenuColors); /* 249: */ /* 250:446 */ this.drawingData = dggContainer.getData(); /* 251: */ } /* 252:448 */ else if (this.origin == Origin.READ_WRITE) /* 253: */ { /* 254:450 */ DggContainer dggContainer = new DggContainer(); /* 255: */ /* 256:452 */ Dgg dgg = new Dgg(this.numBlips + this.numCharts + 1, this.numBlips); /* 257: */ /* 258:454 */ dgg.addCluster(1, 0); /* 259:455 */ dgg.addCluster(this.drawingGroupId + this.numBlips + 1, 0); /* 260: */ /* 261:457 */ dggContainer.add(dgg); /* 262: */ /* 263:459 */ BStoreContainer bstoreCont = new BStoreContainer(); /* 264:460 */ bstoreCont.setNumBlips(this.numBlips); /* 265: */ /* 266: */ /* 267:463 */ BStoreContainer readBStoreContainer = getBStoreContainer(); /* 268:465 */ if (readBStoreContainer != null) /* 269: */ { /* 270:467 */ EscherRecord[] children = readBStoreContainer.getChildren(); /* 271:468 */ for (int i = 0; i < children.length; i++) /* 272: */ { /* 273:470 */ BlipStoreEntry bse = (BlipStoreEntry) children[i]; /* 274:471 */ bstoreCont.add(bse); /* 275: */ } /* 276: */ } /* 277:476 */ for (Iterator i = this.drawings.iterator(); i.hasNext(); ) /* 278: */ { /* 279:478 */ DrawingGroupObject dgo = (DrawingGroupObject) i.next(); /* 280:479 */ if ((dgo instanceof Drawing)) /* 281: */ { /* 282:481 */ Drawing d = (Drawing) dgo; /* 283:482 */ if (d.getOrigin() == Origin.WRITE) /* 284: */ { /* 285:484 */ BlipStoreEntry bse = new BlipStoreEntry(d); /* 286:485 */ bstoreCont.add(bse); /* 287: */ } /* 288: */ } /* 289: */ } /* 290:490 */ dggContainer.add(bstoreCont); /* 291: */ /* 292:492 */ Opt opt = new Opt(); /* 293: */ /* 294:494 */ opt.addProperty(191, false, false, 524296); /* 295:495 */ opt.addProperty(385, false, false, 134217737); /* 296:496 */ opt.addProperty(448, false, false, 134217792); /* 297: */ /* 298:498 */ dggContainer.add(opt); /* 299: */ /* 300:500 */ SplitMenuColors splitMenuColors = new SplitMenuColors(); /* 301:501 */ dggContainer.add(splitMenuColors); /* 302: */ /* 303:503 */ this.drawingData = dggContainer.getData(); /* 304: */ } /* 305:506 */ MsoDrawingGroupRecord msodg = new MsoDrawingGroupRecord(this.drawingData); /* 306:507 */ outputFile.write(msodg); /* 307: */ } /* 308: */ /* 309: */ final int getNumberOfBlips() /* 310: */ { /* 311:517 */ return this.numBlips; /* 312: */ } /* 313: */ /* 314: */ byte[] getImageData(int blipId) /* 315: */ { /* 316:529 */ this.numBlips = getBStoreContainer().getNumBlips(); /* 317: */ /* 318:531 */ Assert.verify(blipId <= this.numBlips); /* 319:532 */ Assert.verify((this.origin == Origin.READ) || (this.origin == Origin.READ_WRITE)); /* 320: */ /* 321: */ /* 322:535 */ EscherRecord[] children = getBStoreContainer().getChildren(); /* 323:536 */ BlipStoreEntry bse = (BlipStoreEntry) children[(blipId - 1)]; /* 324: */ /* 325:538 */ return bse.getImageData(); /* 326: */ } /* 327: */ /* 328: */ public void setDrawingsOmitted(MsoDrawingRecord mso, ObjRecord obj) /* 329: */ { /* 330:550 */ this.drawingsOmitted = true; /* 331:552 */ if (obj != null) { /* 332:554 */ this.maxObjectId = Math.max(this.maxObjectId, obj.getObjectId()); /* 333: */ } /* 334: */ } /* 335: */ /* 336: */ public boolean hasDrawingsOmitted() /* 337: */ { /* 338:565 */ return this.drawingsOmitted; /* 339: */ } /* 340: */ /* 341: */ public void updateData(DrawingGroup dg) /* 342: */ { /* 343:580 */ this.drawingsOmitted = dg.drawingsOmitted; /* 344:581 */ this.maxObjectId = dg.maxObjectId; /* 345:582 */ this.maxShapeId = dg.maxShapeId; /* 346: */ } /* 347: */ }
/** Parses the biff file passed in, and builds up an internal representation of the spreadsheet */ public class WorkbookParser extends Workbook implements ExternalSheet, WorkbookMethods { /** The logger */ private static Logger logger = Logger.getLogger(WorkbookParser.class); /** The excel file */ private File excelFile; /** The number of open bofs */ private int bofs; /** Indicates whether or not the dates are based around the 1904 date system */ private boolean nineteenFour; /** The shared string table */ private SSTRecord sharedStrings; /** The names of all the worksheets */ private ArrayList boundsheets; /** The xf records */ private FormattingRecords formattingRecords; /** The fonts used by this workbook */ private Fonts fonts; /** The sheets contained in this workbook */ private ArrayList sheets; /** The last sheet accessed */ private SheetImpl lastSheet; /** The index of the last sheet retrieved */ private int lastSheetIndex; /** The named records found in this workbook */ private HashMap namedRecords; /** The list of named records */ private ArrayList nameTable; /** The list of add in functions */ private ArrayList addInFunctions; /** The external sheet record. Used by formulas, and names */ private ExternalSheetRecord externSheet; /** The list of supporting workbooks - used by formulas */ private ArrayList supbooks; /** The bof record for this workbook */ private BOFRecord workbookBof; /** The Mso Drawing Group record for this workbook */ private MsoDrawingGroupRecord msoDrawingGroup; /** The property set record associated with this workbook */ private ButtonPropertySetRecord buttonPropertySet; /** Workbook protected flag */ private boolean wbProtected; /** Contains macros flag */ private boolean containsMacros; /** The workbook settings */ private WorkbookSettings settings; /** The drawings contained in this workbook */ private DrawingGroup drawingGroup; /** The country record (containing the language and regional settings) for this workbook */ private CountryRecord countryRecord; private ArrayList xctRecords; /** * Constructs this object from the raw excel data * * @param f the excel 97 biff file * @param s the workbook settings */ public WorkbookParser(File f, WorkbookSettings s) { super(); excelFile = f; boundsheets = new ArrayList(10); fonts = new Fonts(); formattingRecords = new FormattingRecords(fonts); sheets = new ArrayList(10); supbooks = new ArrayList(10); namedRecords = new HashMap(); lastSheetIndex = -1; wbProtected = false; containsMacros = false; settings = s; xctRecords = new ArrayList(10); } /** * Gets the sheets within this workbook. NOTE: Use of this method for very large worksheets can * cause performance and out of memory problems. Use the alternative method getSheet() to retrieve * each sheet individually * * @return an array of the individual sheets */ public Sheet[] getSheets() { Sheet[] sheetArray = new Sheet[getNumberOfSheets()]; return (Sheet[]) sheets.toArray(sheetArray); } /** * Interface method from WorkbookMethods - gets the specified sheet within this workbook * * @param index the zero based index of the required sheet * @return The sheet specified by the index */ public Sheet getReadSheet(int index) { return getSheet(index); } /** * Gets the specified sheet within this workbook * * @param index the zero based index of the required sheet * @return The sheet specified by the index */ public Sheet getSheet(int index) { // First see if the last sheet index is the same as this sheet index. // If so, then the same sheet is being re-requested, so simply // return it instead of rereading it if ((lastSheet != null) && lastSheetIndex == index) { return lastSheet; } // Flush out all of the cached data in the last sheet if (lastSheet != null) { lastSheet.clear(); if (!settings.getGCDisabled()) { System.gc(); } } lastSheet = (SheetImpl) sheets.get(index); lastSheetIndex = index; lastSheet.readSheet(); return lastSheet; } /** * Gets the sheet with the specified name from within this workbook * * @param name the sheet name * @return The sheet with the specified name, or null if it is not found */ public Sheet getSheet(String name) { // Iterate through the boundsheet records int pos = 0; boolean found = false; Iterator i = boundsheets.iterator(); BoundsheetRecord br = null; while (i.hasNext() && !found) { br = (BoundsheetRecord) i.next(); if (br.getName().equals(name)) { found = true; } else { pos++; } } return found ? getSheet(pos) : null; } /** * Gets the sheet names * * @return an array of strings containing the sheet names */ public String[] getSheetNames() { String[] names = new String[boundsheets.size()]; BoundsheetRecord br = null; for (int i = 0; i < names.length; i++) { br = (BoundsheetRecord) boundsheets.get(i); names[i] = br.getName(); } return names; } /** * Package protected function which gets the real internal sheet index based upon the external * sheet reference. This is used for extern sheet references which are specified in formulas * * @param index the external sheet reference * @return the actual sheet index */ public int getExternalSheetIndex(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { return index; } Assert.verify(externSheet != null); int firstTab = externSheet.getFirstTabIndex(index); return firstTab; } /** * Package protected function which gets the real internal sheet index based upon the external * sheet reference. This is used for extern sheet references which are specified in formulas * * @param index the external sheet reference * @return the actual sheet index */ public int getLastExternalSheetIndex(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { return index; } Assert.verify(externSheet != null); int lastTab = externSheet.getLastTabIndex(index); return lastTab; } /** * Gets the name of the external sheet specified by the index * * @param index the external sheet index * @return the name of the external sheet */ public String getExternalSheetName(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(index); return br.getName(); } int supbookIndex = externSheet.getSupbookIndex(index); SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex); int firstTab = externSheet.getFirstTabIndex(index); int lastTab = externSheet.getLastTabIndex(index); String firstTabName = ""; String lastTabName = ""; if (sr.getType() == SupbookRecord.INTERNAL) { // It's an internal reference - get the name from the boundsheets list if (firstTab == 65535) { firstTabName = "#REF"; } else { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(firstTab); firstTabName = br.getName(); } if (lastTab == 65535) { lastTabName = "#REF"; } else { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(lastTab); lastTabName = br.getName(); } String sheetName = (firstTab == lastTab) ? firstTabName : firstTabName + ':' + lastTabName; // if the sheet name contains apostrophes then escape them sheetName = sheetName.indexOf('\'') == -1 ? sheetName : StringHelper.replace(sheetName, "\'", "\'\'"); // if the sheet name contains spaces, then enclose in quotes return sheetName.indexOf(' ') == -1 ? sheetName : '\'' + sheetName + '\''; } else if (sr.getType() == SupbookRecord.EXTERNAL) { // External reference - get the sheet name from the supbook record StringBuffer sb = new StringBuffer(); java.io.File fl = new java.io.File(sr.getFileName()); sb.append("'"); sb.append(fl.getAbsolutePath()); sb.append("["); sb.append(fl.getName()); sb.append("]"); sb.append((firstTab == 65535) ? "#REF" : sr.getSheetName(firstTab)); if (lastTab != firstTab) { sb.append(sr.getSheetName(lastTab)); } sb.append("'"); return sb.toString(); } // An unknown supbook - return unkown logger.warn("Unknown Supbook 3"); return "[UNKNOWN]"; } /** * Gets the name of the external sheet specified by the index * * @param index the external sheet index * @return the name of the external sheet */ public String getLastExternalSheetName(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(index); return br.getName(); } int supbookIndex = externSheet.getSupbookIndex(index); SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex); int lastTab = externSheet.getLastTabIndex(index); if (sr.getType() == SupbookRecord.INTERNAL) { // It's an internal reference - get the name from the boundsheets list if (lastTab == 65535) { return "#REF"; } else { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(lastTab); return br.getName(); } } else if (sr.getType() == SupbookRecord.EXTERNAL) { // External reference - get the sheet name from the supbook record StringBuffer sb = new StringBuffer(); java.io.File fl = new java.io.File(sr.getFileName()); sb.append("'"); sb.append(fl.getAbsolutePath()); sb.append("["); sb.append(fl.getName()); sb.append("]"); sb.append((lastTab == 65535) ? "#REF" : sr.getSheetName(lastTab)); sb.append("'"); return sb.toString(); } // An unknown supbook - return unkown logger.warn("Unknown Supbook 4"); return "[UNKNOWN]"; } /** * Returns the number of sheets in this workbook * * @return the number of sheets in this workbook */ public int getNumberOfSheets() { return sheets.size(); } /** Closes this workbook, and frees makes any memory allocated available for garbage collection */ public void close() { if (lastSheet != null) { lastSheet.clear(); } excelFile.clear(); if (!settings.getGCDisabled()) { System.gc(); } } /** * Adds the sheet to the end of the array * * @param s the sheet to add */ final void addSheet(Sheet s) { sheets.add(s); } /** * Does the hard work of building up the object graph from the excel bytes * * @exception BiffException * @exception PasswordException if the workbook is password protected */ public void parse() throws BiffException, PasswordException { Record r = null; BOFRecord bof = new BOFRecord(excelFile.next()); workbookBof = bof; bofs++; if (!bof.isBiff8() && !bof.isBiff7()) { throw new BiffException(BiffException.unrecognizedBiffVersion); } if (!bof.isWorkbookGlobals()) { throw new BiffException(BiffException.expectedGlobals); } ArrayList continueRecords = new ArrayList(); ArrayList localNames = new ArrayList(); nameTable = new ArrayList(); addInFunctions = new ArrayList(); // Skip to the first worksheet while (bofs == 1) { r = excelFile.next(); if (r.getType() == Type.SST) { continueRecords.clear(); Record nextrec = excelFile.peek(); while (nextrec.getType() == Type.CONTINUE) { continueRecords.add(excelFile.next()); nextrec = excelFile.peek(); } // cast the array Record[] records = new Record[continueRecords.size()]; records = (Record[]) continueRecords.toArray(records); sharedStrings = new SSTRecord(r, records, settings); } else if (r.getType() == Type.FILEPASS) { throw new PasswordException(); } else if (r.getType() == Type.NAME) { NameRecord nr = null; if (bof.isBiff8()) { nr = new NameRecord(r, settings, nameTable.size()); } else { nr = new NameRecord(r, settings, nameTable.size(), NameRecord.biff7); } // Add all local and global names to the name table in order to // preserve the indexing nameTable.add(nr); if (nr.isGlobal()) { namedRecords.put(nr.getName(), nr); } else { localNames.add(nr); } } else if (r.getType() == Type.FONT) { FontRecord fr = null; if (bof.isBiff8()) { fr = new FontRecord(r, settings); } else { fr = new FontRecord(r, settings, FontRecord.biff7); } fonts.addFont(fr); } else if (r.getType() == Type.PALETTE) { PaletteRecord palette = new PaletteRecord(r); formattingRecords.setPalette(palette); } else if (r.getType() == Type.NINETEENFOUR) { NineteenFourRecord nr = new NineteenFourRecord(r); nineteenFour = nr.is1904(); } else if (r.getType() == Type.FORMAT) { FormatRecord fr = null; if (bof.isBiff8()) { fr = new FormatRecord(r, settings, FormatRecord.biff8); } else { fr = new FormatRecord(r, settings, FormatRecord.biff7); } try { formattingRecords.addFormat(fr); } catch (NumFormatRecordsException e) { // This should not happen. Bomb out Assert.verify(false, e.getMessage()); } } else if (r.getType() == Type.XF) { XFRecord xfr = null; if (bof.isBiff8()) { xfr = new XFRecord(r, settings, XFRecord.biff8); } else { xfr = new XFRecord(r, settings, XFRecord.biff7); } try { formattingRecords.addStyle(xfr); } catch (NumFormatRecordsException e) { // This should not happen. Bomb out Assert.verify(false, e.getMessage()); } } else if (r.getType() == Type.BOUNDSHEET) { BoundsheetRecord br = null; if (bof.isBiff8()) { br = new BoundsheetRecord(r, settings); } else { br = new BoundsheetRecord(r, BoundsheetRecord.biff7); } if (br.isSheet()) { boundsheets.add(br); } else if (br.isChart() && !settings.getDrawingsDisabled()) { boundsheets.add(br); } } else if (r.getType() == Type.EXTERNSHEET) { if (bof.isBiff8()) { externSheet = new ExternalSheetRecord(r, settings); } else { externSheet = new ExternalSheetRecord(r, settings, ExternalSheetRecord.biff7); } } else if (r.getType() == Type.XCT) { XCTRecord xctr = new XCTRecord(r); xctRecords.add(xctr); } else if (r.getType() == Type.CODEPAGE) { CodepageRecord cr = new CodepageRecord(r); settings.setCharacterSet(cr.getCharacterSet()); } else if (r.getType() == Type.SUPBOOK) { Record nextrec = excelFile.peek(); while (nextrec.getType() == Type.CONTINUE) { r.addContinueRecord(excelFile.next()); nextrec = excelFile.peek(); } SupbookRecord sr = new SupbookRecord(r, settings); supbooks.add(sr); } else if (r.getType() == Type.EXTERNNAME) { ExternalNameRecord enr = new ExternalNameRecord(r, settings); if (enr.isAddInFunction()) { addInFunctions.add(enr.getName()); } } else if (r.getType() == Type.PROTECT) { ProtectRecord pr = new ProtectRecord(r); wbProtected = pr.isProtected(); } else if (r.getType() == Type.OBJPROJ) { containsMacros = true; } else if (r.getType() == Type.COUNTRY) { countryRecord = new CountryRecord(r); } else if (r.getType() == Type.MSODRAWINGGROUP) { if (!settings.getDrawingsDisabled()) { msoDrawingGroup = new MsoDrawingGroupRecord(r); if (drawingGroup == null) { drawingGroup = new DrawingGroup(Origin.READ); } drawingGroup.add(msoDrawingGroup); Record nextrec = excelFile.peek(); while (nextrec.getType() == Type.CONTINUE) { drawingGroup.add(excelFile.next()); nextrec = excelFile.peek(); } } } else if (r.getType() == Type.BUTTONPROPERTYSET) { buttonPropertySet = new ButtonPropertySetRecord(r); } else if (r.getType() == Type.EOF) { bofs--; } else if (r.getType() == Type.REFRESHALL) { RefreshAllRecord rfm = new RefreshAllRecord(r); settings.setRefreshAll(rfm.getRefreshAll()); } else if (r.getType() == Type.TEMPLATE) { TemplateRecord rfm = new TemplateRecord(r); settings.setTemplate(rfm.getTemplate()); } else if (r.getType() == Type.EXCEL9FILE) { Excel9FileRecord e9f = new Excel9FileRecord(r); settings.setExcel9File(e9f.getExcel9File()); } else if (r.getType() == Type.WINDOWPROTECT) { WindowProtectedRecord winp = new WindowProtectedRecord(r); settings.setWindowProtected(winp.getWindowProtected()); } else if (r.getType() == Type.HIDEOBJ) { HideobjRecord hobj = new HideobjRecord(r); settings.setHideobj(hobj.getHideMode()); } else if (r.getType() == Type.WRITEACCESS) { WriteAccessRecord war = new WriteAccessRecord(r, bof.isBiff8(), settings); settings.setWriteAccess(war.getWriteAccess()); } else { // logger.info("Unsupported record type: " + // Integer.toHexString(r.getCode())+"h"); } } bof = null; if (excelFile.hasNext()) { r = excelFile.next(); if (r.getType() == Type.BOF) { bof = new BOFRecord(r); } } // Only get sheets for which there is a corresponding Boundsheet record while (bof != null && getNumberOfSheets() < boundsheets.size()) { if (!bof.isBiff8() && !bof.isBiff7()) { throw new BiffException(BiffException.unrecognizedBiffVersion); } if (bof.isWorksheet()) { // Read the sheet in SheetImpl s = new SheetImpl( excelFile, sharedStrings, formattingRecords, bof, workbookBof, nineteenFour, this); BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(getNumberOfSheets()); s.setName(br.getName()); s.setHidden(br.isHidden()); addSheet(s); } else if (bof.isChart()) { // Read the sheet in SheetImpl s = new SheetImpl( excelFile, sharedStrings, formattingRecords, bof, workbookBof, nineteenFour, this); BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(getNumberOfSheets()); s.setName(br.getName()); s.setHidden(br.isHidden()); addSheet(s); } else { logger.warn("BOF is unrecognized"); while (excelFile.hasNext() && r.getType() != Type.EOF) { r = excelFile.next(); } } // The next record will normally be a BOF or empty padding until // the end of the block is reached. In exceptionally unlucky cases, // the last EOF will coincide with a block division, so we have to // check there is more data to retrieve. // Thanks to liamg for spotting this bof = null; if (excelFile.hasNext()) { r = excelFile.next(); if (r.getType() == Type.BOF) { bof = new BOFRecord(r); } } } // Add all the local names to the specific sheets for (Iterator it = localNames.iterator(); it.hasNext(); ) { NameRecord nr = (NameRecord) it.next(); if (nr.getBuiltInName() == null) { logger.warn("Usage of a local non-builtin name"); } else if (nr.getBuiltInName() == BuiltInName.PRINT_AREA || nr.getBuiltInName() == BuiltInName.PRINT_TITLES) { // appears to use the internal tab number rather than the // external sheet index SheetImpl s = (SheetImpl) sheets.get(nr.getSheetRef() - 1); s.addLocalName(nr); } } } /** * Accessor for the formattingRecords, used by the WritableWorkbook when creating a copy of this * * @return the formatting records */ public FormattingRecords getFormattingRecords() { return formattingRecords; } /** * Accessor for the externSheet, used by the WritableWorkbook when creating a copy of this * * @return the external sheet record */ public ExternalSheetRecord getExternalSheetRecord() { return externSheet; } /** * Accessor for the MsoDrawingGroup, used by the WritableWorkbook when creating a copy of this * * @return the Mso Drawing Group record */ public MsoDrawingGroupRecord getMsoDrawingGroupRecord() { return msoDrawingGroup; } /** * Accessor for the supbook records, used by the WritableWorkbook when creating a copy of this * * @return the supbook records */ public SupbookRecord[] getSupbookRecords() { SupbookRecord[] sr = new SupbookRecord[supbooks.size()]; return (SupbookRecord[]) supbooks.toArray(sr); } /** * Accessor for the name records. Used by the WritableWorkbook when creating a copy of this * * @return the array of names */ public NameRecord[] getNameRecords() { NameRecord[] na = new NameRecord[nameTable.size()]; return (NameRecord[]) nameTable.toArray(na); } /** * Accessor for the fonts, used by the WritableWorkbook when creating a copy of this * * @return the fonts used in this workbook */ public Fonts getFonts() { return fonts; } /** * Returns the cell for the specified location eg. "Sheet1!A4". This is identical to using the * CellReferenceHelper with its associated performance overheads, consequently it should be use * sparingly * * @param loc the cell to retrieve * @return the cell at the specified location */ public Cell getCell(String loc) { Sheet s = getSheet(CellReferenceHelper.getSheet(loc)); return s.getCell(loc); } /** * Gets the named cell from this workbook. If the name refers to a range of cells, then the cell * on the top left is returned. If the name cannot be found, null is returned * * @param name the name of the cell/range to search for * @return the cell in the top left of the range if found, NULL otherwise */ public Cell findCellByName(String name) { NameRecord nr = (NameRecord) namedRecords.get(name); if (nr == null) { return null; } NameRecord.NameRange[] ranges = nr.getRanges(); // Go and retrieve the first cell in the first range Sheet s = getSheet(getExternalSheetIndex(ranges[0].getExternalSheet())); int col = ranges[0].getFirstColumn(); int row = ranges[0].getFirstRow(); // If the sheet boundaries fall short of the named cell, then return // an empty cell to stop an exception being thrown if (col > s.getColumns() || row > s.getRows()) { return new EmptyCell(col, row); } Cell cell = s.getCell(col, row); return cell; } /** * Gets the named range from this workbook. The Range object returns contains all the cells from * the top left to the bottom right of the range. If the named range comprises an adjacent range, * the Range[] will contain one object; for non-adjacent ranges, it is necessary to return an * array of length greater than one. If the named range contains a single cell, the top left and * bottom right cell will be the same cell * * @param name the name to find * @return the range of cells */ public Range[] findByName(String name) { NameRecord nr = (NameRecord) namedRecords.get(name); if (nr == null) { return null; } NameRecord.NameRange[] ranges = nr.getRanges(); Range[] cellRanges = new Range[ranges.length]; for (int i = 0; i < ranges.length; i++) { cellRanges[i] = new RangeImpl( this, getExternalSheetIndex(ranges[i].getExternalSheet()), ranges[i].getFirstColumn(), ranges[i].getFirstRow(), getLastExternalSheetIndex(ranges[i].getExternalSheet()), ranges[i].getLastColumn(), ranges[i].getLastRow()); } return cellRanges; } /** * Gets the named ranges * * @return the list of named cells within the workbook */ public String[] getRangeNames() { Object[] keys = namedRecords.keySet().toArray(); String[] names = new String[keys.length]; System.arraycopy(keys, 0, names, 0, keys.length); return names; } /** * Method used when parsing formulas to make sure we are trying to parse a supported biff version * * @return the BOF record */ public BOFRecord getWorkbookBof() { return workbookBof; } /** * Determines whether the sheet is protected * * @return whether or not the sheet is protected */ public boolean isProtected() { return wbProtected; } /** * Accessor for the settings * * @return the workbook settings */ public WorkbookSettings getSettings() { return settings; } /** * Accessor/implementation method for the external sheet reference * * @param sheetName the sheet name to look for * @return the external sheet index */ public int getExternalSheetIndex(String sheetName) { return 0; } /** * Accessor/implementation method for the external sheet reference * * @param sheetName the sheet name to look for * @return the external sheet index */ public int getLastExternalSheetIndex(String sheetName) { return 0; } /** * Gets the name at the specified index * * @param index the index into the name table * @return the name of the cell * @exception NameRangeException */ public String getName(int index) throws NameRangeException { // Assert.verify(index >= 0 && index < nameTable.size()); if (index < 0 || index >= nameTable.size()) { throw new NameRangeException(); } return ((NameRecord) nameTable.get(index)).getName(); } /** * Gets the index of the name record for the name * * @param name the name to search for * @return the index in the name table */ public int getNameIndex(String name) { NameRecord nr = (NameRecord) namedRecords.get(name); return nr != null ? nr.getIndex() : 0; } /** * Accessor for the drawing group * * @return the drawing group */ public DrawingGroup getDrawingGroup() { return drawingGroup; } /** * Accessor for the CompoundFile. For this feature to return non-null value, the propertySets * feature in WorkbookSettings must be enabled and the workbook must contain additional property * sets. This method is used during the workbook copy * * @return the base compound file if it contains additional data items and property sets are * enabled */ public CompoundFile getCompoundFile() { return excelFile.getCompoundFile(); } /** * Accessor for the containsMacros * * @return TRUE if this workbook contains macros, FALSE otherwise */ public boolean containsMacros() { return containsMacros; } /** * Accessor for the button property set, used during copying * * @return the button property set */ public ButtonPropertySetRecord getButtonPropertySet() { return buttonPropertySet; } /** * Accessor for the country record, using during copying * * @return the country record read in */ public CountryRecord getCountryRecord() { return countryRecord; } /** * Accessor for addin function names * * @return list of add in function names */ public String[] getAddInFunctionNames() { String[] addins = new String[0]; return (String[]) addInFunctions.toArray(addins); } /** * Gets the sheet index in this workbook. Used when importing a sheet * * @param sheet the sheet * @return the 0-based sheet index, or -1 if it is not found */ public int getIndex(Sheet sheet) { String name = sheet.getName(); int index = -1; int pos = 0; for (Iterator i = boundsheets.iterator(); i.hasNext() && index == -1; ) { BoundsheetRecord br = (BoundsheetRecord) i.next(); if (br.getName().equals(name)) { index = pos; } else { pos++; } } return index; } public XCTRecord[] getXCTRecords() { XCTRecord[] xctr = new XCTRecord[0]; return (XCTRecord[]) xctRecords.toArray(xctr); } }
/** * Does the hard work of building up the object graph from the excel bytes * * @exception BiffException * @exception PasswordException if the workbook is password protected */ public void parse() throws BiffException, PasswordException { Record r = null; BOFRecord bof = new BOFRecord(excelFile.next()); workbookBof = bof; bofs++; if (!bof.isBiff8() && !bof.isBiff7()) { throw new BiffException(BiffException.unrecognizedBiffVersion); } if (!bof.isWorkbookGlobals()) { throw new BiffException(BiffException.expectedGlobals); } ArrayList continueRecords = new ArrayList(); ArrayList localNames = new ArrayList(); nameTable = new ArrayList(); addInFunctions = new ArrayList(); // Skip to the first worksheet while (bofs == 1) { r = excelFile.next(); if (r.getType() == Type.SST) { continueRecords.clear(); Record nextrec = excelFile.peek(); while (nextrec.getType() == Type.CONTINUE) { continueRecords.add(excelFile.next()); nextrec = excelFile.peek(); } // cast the array Record[] records = new Record[continueRecords.size()]; records = (Record[]) continueRecords.toArray(records); sharedStrings = new SSTRecord(r, records, settings); } else if (r.getType() == Type.FILEPASS) { throw new PasswordException(); } else if (r.getType() == Type.NAME) { NameRecord nr = null; if (bof.isBiff8()) { nr = new NameRecord(r, settings, nameTable.size()); } else { nr = new NameRecord(r, settings, nameTable.size(), NameRecord.biff7); } // Add all local and global names to the name table in order to // preserve the indexing nameTable.add(nr); if (nr.isGlobal()) { namedRecords.put(nr.getName(), nr); } else { localNames.add(nr); } } else if (r.getType() == Type.FONT) { FontRecord fr = null; if (bof.isBiff8()) { fr = new FontRecord(r, settings); } else { fr = new FontRecord(r, settings, FontRecord.biff7); } fonts.addFont(fr); } else if (r.getType() == Type.PALETTE) { PaletteRecord palette = new PaletteRecord(r); formattingRecords.setPalette(palette); } else if (r.getType() == Type.NINETEENFOUR) { NineteenFourRecord nr = new NineteenFourRecord(r); nineteenFour = nr.is1904(); } else if (r.getType() == Type.FORMAT) { FormatRecord fr = null; if (bof.isBiff8()) { fr = new FormatRecord(r, settings, FormatRecord.biff8); } else { fr = new FormatRecord(r, settings, FormatRecord.biff7); } try { formattingRecords.addFormat(fr); } catch (NumFormatRecordsException e) { // This should not happen. Bomb out Assert.verify(false, e.getMessage()); } } else if (r.getType() == Type.XF) { XFRecord xfr = null; if (bof.isBiff8()) { xfr = new XFRecord(r, settings, XFRecord.biff8); } else { xfr = new XFRecord(r, settings, XFRecord.biff7); } try { formattingRecords.addStyle(xfr); } catch (NumFormatRecordsException e) { // This should not happen. Bomb out Assert.verify(false, e.getMessage()); } } else if (r.getType() == Type.BOUNDSHEET) { BoundsheetRecord br = null; if (bof.isBiff8()) { br = new BoundsheetRecord(r, settings); } else { br = new BoundsheetRecord(r, BoundsheetRecord.biff7); } if (br.isSheet()) { boundsheets.add(br); } else if (br.isChart() && !settings.getDrawingsDisabled()) { boundsheets.add(br); } } else if (r.getType() == Type.EXTERNSHEET) { if (bof.isBiff8()) { externSheet = new ExternalSheetRecord(r, settings); } else { externSheet = new ExternalSheetRecord(r, settings, ExternalSheetRecord.biff7); } } else if (r.getType() == Type.XCT) { XCTRecord xctr = new XCTRecord(r); xctRecords.add(xctr); } else if (r.getType() == Type.CODEPAGE) { CodepageRecord cr = new CodepageRecord(r); settings.setCharacterSet(cr.getCharacterSet()); } else if (r.getType() == Type.SUPBOOK) { Record nextrec = excelFile.peek(); while (nextrec.getType() == Type.CONTINUE) { r.addContinueRecord(excelFile.next()); nextrec = excelFile.peek(); } SupbookRecord sr = new SupbookRecord(r, settings); supbooks.add(sr); } else if (r.getType() == Type.EXTERNNAME) { ExternalNameRecord enr = new ExternalNameRecord(r, settings); if (enr.isAddInFunction()) { addInFunctions.add(enr.getName()); } } else if (r.getType() == Type.PROTECT) { ProtectRecord pr = new ProtectRecord(r); wbProtected = pr.isProtected(); } else if (r.getType() == Type.OBJPROJ) { containsMacros = true; } else if (r.getType() == Type.COUNTRY) { countryRecord = new CountryRecord(r); } else if (r.getType() == Type.MSODRAWINGGROUP) { if (!settings.getDrawingsDisabled()) { msoDrawingGroup = new MsoDrawingGroupRecord(r); if (drawingGroup == null) { drawingGroup = new DrawingGroup(Origin.READ); } drawingGroup.add(msoDrawingGroup); Record nextrec = excelFile.peek(); while (nextrec.getType() == Type.CONTINUE) { drawingGroup.add(excelFile.next()); nextrec = excelFile.peek(); } } } else if (r.getType() == Type.BUTTONPROPERTYSET) { buttonPropertySet = new ButtonPropertySetRecord(r); } else if (r.getType() == Type.EOF) { bofs--; } else if (r.getType() == Type.REFRESHALL) { RefreshAllRecord rfm = new RefreshAllRecord(r); settings.setRefreshAll(rfm.getRefreshAll()); } else if (r.getType() == Type.TEMPLATE) { TemplateRecord rfm = new TemplateRecord(r); settings.setTemplate(rfm.getTemplate()); } else if (r.getType() == Type.EXCEL9FILE) { Excel9FileRecord e9f = new Excel9FileRecord(r); settings.setExcel9File(e9f.getExcel9File()); } else if (r.getType() == Type.WINDOWPROTECT) { WindowProtectedRecord winp = new WindowProtectedRecord(r); settings.setWindowProtected(winp.getWindowProtected()); } else if (r.getType() == Type.HIDEOBJ) { HideobjRecord hobj = new HideobjRecord(r); settings.setHideobj(hobj.getHideMode()); } else if (r.getType() == Type.WRITEACCESS) { WriteAccessRecord war = new WriteAccessRecord(r, bof.isBiff8(), settings); settings.setWriteAccess(war.getWriteAccess()); } else { // logger.info("Unsupported record type: " + // Integer.toHexString(r.getCode())+"h"); } } bof = null; if (excelFile.hasNext()) { r = excelFile.next(); if (r.getType() == Type.BOF) { bof = new BOFRecord(r); } } // Only get sheets for which there is a corresponding Boundsheet record while (bof != null && getNumberOfSheets() < boundsheets.size()) { if (!bof.isBiff8() && !bof.isBiff7()) { throw new BiffException(BiffException.unrecognizedBiffVersion); } if (bof.isWorksheet()) { // Read the sheet in SheetImpl s = new SheetImpl( excelFile, sharedStrings, formattingRecords, bof, workbookBof, nineteenFour, this); BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(getNumberOfSheets()); s.setName(br.getName()); s.setHidden(br.isHidden()); addSheet(s); } else if (bof.isChart()) { // Read the sheet in SheetImpl s = new SheetImpl( excelFile, sharedStrings, formattingRecords, bof, workbookBof, nineteenFour, this); BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(getNumberOfSheets()); s.setName(br.getName()); s.setHidden(br.isHidden()); addSheet(s); } else { logger.warn("BOF is unrecognized"); while (excelFile.hasNext() && r.getType() != Type.EOF) { r = excelFile.next(); } } // The next record will normally be a BOF or empty padding until // the end of the block is reached. In exceptionally unlucky cases, // the last EOF will coincide with a block division, so we have to // check there is more data to retrieve. // Thanks to liamg for spotting this bof = null; if (excelFile.hasNext()) { r = excelFile.next(); if (r.getType() == Type.BOF) { bof = new BOFRecord(r); } } } // Add all the local names to the specific sheets for (Iterator it = localNames.iterator(); it.hasNext(); ) { NameRecord nr = (NameRecord) it.next(); if (nr.getBuiltInName() == null) { logger.warn("Usage of a local non-builtin name"); } else if (nr.getBuiltInName() == BuiltInName.PRINT_AREA || nr.getBuiltInName() == BuiltInName.PRINT_TITLES) { // appears to use the internal tab number rather than the // external sheet index SheetImpl s = (SheetImpl) sheets.get(nr.getSheetRef() - 1); s.addLocalName(nr); } } }
/** * Gets the name of the external sheet specified by the index * * @param index the external sheet index * @return the name of the external sheet */ public String getExternalSheetName(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(index); return br.getName(); } int supbookIndex = externSheet.getSupbookIndex(index); SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex); int firstTab = externSheet.getFirstTabIndex(index); int lastTab = externSheet.getLastTabIndex(index); String firstTabName = ""; String lastTabName = ""; if (sr.getType() == SupbookRecord.INTERNAL) { // It's an internal reference - get the name from the boundsheets list if (firstTab == 65535) { firstTabName = "#REF"; } else { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(firstTab); firstTabName = br.getName(); } if (lastTab == 65535) { lastTabName = "#REF"; } else { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(lastTab); lastTabName = br.getName(); } String sheetName = (firstTab == lastTab) ? firstTabName : firstTabName + ':' + lastTabName; // if the sheet name contains apostrophes then escape them sheetName = sheetName.indexOf('\'') == -1 ? sheetName : StringHelper.replace(sheetName, "\'", "\'\'"); // if the sheet name contains spaces, then enclose in quotes return sheetName.indexOf(' ') == -1 ? sheetName : '\'' + sheetName + '\''; } else if (sr.getType() == SupbookRecord.EXTERNAL) { // External reference - get the sheet name from the supbook record StringBuffer sb = new StringBuffer(); java.io.File fl = new java.io.File(sr.getFileName()); sb.append("'"); sb.append(fl.getAbsolutePath()); sb.append("["); sb.append(fl.getName()); sb.append("]"); sb.append((firstTab == 65535) ? "#REF" : sr.getSheetName(firstTab)); if (lastTab != firstTab) { sb.append(sr.getSheetName(lastTab)); } sb.append("'"); return sb.toString(); } // An unknown supbook - return unkown logger.warn("Unknown Supbook 3"); return "[UNKNOWN]"; }
/** A cell reference in a formula */ class DoubleValue extends NumberValue implements ParsedThing { /** The logger */ private static Logger logger = Logger.getLogger(DoubleValue.class); /** The value of this double in the formula */ private double value; /** Constructor */ public DoubleValue() {} /** * Constructor - invoked when writing an integer value that's out of range for a short * * @param v the double value */ DoubleValue(double v) { value = v; } /** * Constructor for a double value when reading from a string * * @param s the string representation of this token */ public DoubleValue(String s) { try { value = Double.parseDouble(s); } catch (NumberFormatException e) { logger.warn(e, e); value = 0; } } /** * Reads the ptg data from the array starting at the specified position * * @param data the RPN array * @param pos the current position in the array, excluding the ptg identifier * @return the number of bytes read */ public int read(byte[] data, int pos) { value = DoubleHelper.getIEEEDouble(data, pos); return 8; } /** * Gets the token representation of this item in RPN * * @return the bytes applicable to this formula */ byte[] getBytes() { byte[] data = new byte[9]; data[0] = Token.DOUBLE.getCode(); DoubleHelper.getIEEEBytes(value, data, 1); return data; } /** * The double value * * @return the value */ public double getValue() { return value; } /** * If this formula was on an imported sheet, check that cell references to another sheet are * warned appropriately Does nothing */ void handleImportedCellReferences() {} }
/* 5: */ /* 6: */ public abstract class WritableRecordData /* 7: */ extends RecordData /* 8: */ implements ByteData /* 9: */ { /* 10: 36 */ private static Logger logger = Logger.getLogger(WritableRecordData.class); /* 11: */ protected static final int maxRecordLength = 8228; /* 12: */ /* 13: */ protected WritableRecordData(Type t) /* 14: */ { /* 15: 49 */ super(t); /* 16: */ } /* 17: */ /* 18: */ protected WritableRecordData(Record t) /* 19: */ { /* 20: 59 */ super(t); /* 21: */ } /* 22: */ /* 23: */ public final byte[] getBytes() /* 24: */ { /* 25: 71 */ byte[] data = getData(); /* 26: */ /* 27: 73 */ int dataLength = data.length; /* 28: 79 */ if (data.length > 8224) /* 29: */ { /* 30: 81 */ dataLength = 8224; /* 31: 82 */ data = handleContinueRecords(data); /* 32: */ } /* 33: 85 */ byte[] bytes = new byte[data.length + 4]; /* 34: */ /* 35: 87 */ System.arraycopy(data, 0, bytes, 4, data.length); /* 36: */ /* 37: 89 */ IntegerHelper.getTwoBytes(getCode(), bytes, 0); /* 38: 90 */ IntegerHelper.getTwoBytes(dataLength, bytes, 2); /* 39: */ /* 40: 92 */ return bytes; /* 41: */ } /* 42: */ /* 43: */ private byte[] handleContinueRecords(byte[] data) /* 44: */ { /* 45:104 */ int continuedData = data.length - 8224; /* 46:105 */ int numContinueRecords = continuedData / 8224 + 1; /* 47: */ /* 48: */ /* 49: */ /* 50:109 */ byte[] newdata = new byte[data.length + numContinueRecords * 4]; /* 51: */ /* 52: */ /* 53: */ /* 54:113 */ System.arraycopy(data, 0, newdata, 0, 8224); /* 55:114 */ int oldarraypos = 8224; /* 56:115 */ int newarraypos = 8224; /* 57:118 */ for (int i = 0; i < numContinueRecords; i++) /* 58: */ { /* 59:121 */ int length = Math.min(data.length - oldarraypos, 8224); /* 60: */ /* 61: */ /* 62:124 */ IntegerHelper.getTwoBytes(Type.CONTINUE.value, newdata, newarraypos); /* 63:125 */ IntegerHelper.getTwoBytes(length, newdata, newarraypos + 2); /* 64: */ /* 65: */ /* 66:128 */ System.arraycopy(data, oldarraypos, newdata, newarraypos + 4, length); /* 67: */ /* 68: */ /* 69:131 */ oldarraypos += length; /* 70:132 */ newarraypos += length + 4; /* 71: */ } /* 72:135 */ return newdata; /* 73: */ } /* 74: */ /* 75: */ protected abstract byte[] getData(); /* 76: */ }
/** Class which parses the binary data associated with Data Validity (DV) setting */ public class DVParser { /** The logger */ private static Logger logger = Logger.getLogger(DVParser.class); // DV Type public static class DVType { private int value; private String desc; private static DVType[] types = new DVType[0]; DVType(int v, String d) { value = v; desc = d; DVType[] oldtypes = types; types = new DVType[oldtypes.length + 1]; System.arraycopy(oldtypes, 0, types, 0, oldtypes.length); types[oldtypes.length] = this; } static DVType getType(int v) { DVType found = null; for (int i = 0; i < types.length && found == null; i++) { if (types[i].value == v) { found = types[i]; } } return found; } public int getValue() { return value; } public String getDescription() { return desc; } } // Error Style public static class ErrorStyle { private int value; private static ErrorStyle[] types = new ErrorStyle[0]; ErrorStyle(int v) { value = v; ErrorStyle[] oldtypes = types; types = new ErrorStyle[oldtypes.length + 1]; System.arraycopy(oldtypes, 0, types, 0, oldtypes.length); types[oldtypes.length] = this; } static ErrorStyle getErrorStyle(int v) { ErrorStyle found = null; for (int i = 0; i < types.length && found == null; i++) { if (types[i].value == v) { found = types[i]; } } return found; } public int getValue() { return value; } } // Conditions public static class Condition { private int value; private MessageFormat format; private static Condition[] types = new Condition[0]; Condition(int v, String pattern) { value = v; format = new MessageFormat(pattern); Condition[] oldtypes = types; types = new Condition[oldtypes.length + 1]; System.arraycopy(oldtypes, 0, types, 0, oldtypes.length); types[oldtypes.length] = this; } static Condition getCondition(int v) { Condition found = null; for (int i = 0; i < types.length && found == null; i++) { if (types[i].value == v) { found = types[i]; } } return found; } public int getValue() { return value; } public String getConditionString(String s1, String s2) { return format.format(new String[] {s1, s2}); } } // The values public static final DVType ANY = new DVType(0, "any"); public static final DVType INTEGER = new DVType(1, "int"); public static final DVType DECIMAL = new DVType(2, "dec"); public static final DVType LIST = new DVType(3, "list"); public static final DVType DATE = new DVType(4, "date"); public static final DVType TIME = new DVType(5, "time"); public static final DVType TEXT_LENGTH = new DVType(6, "strlen"); public static final DVType FORMULA = new DVType(7, "form"); // The error styles public static final ErrorStyle STOP = new ErrorStyle(0); public static final ErrorStyle WARNING = new ErrorStyle(1); public static final ErrorStyle INFO = new ErrorStyle(2); // The conditions public static final Condition BETWEEN = new Condition(0, "{0} <= x <= {1}"); public static final Condition NOT_BETWEEN = new Condition(1, "!({0} <= x <= {1}"); public static final Condition EQUAL = new Condition(2, "x == {0}"); public static final Condition NOT_EQUAL = new Condition(3, "x != {0}"); public static final Condition GREATER_THAN = new Condition(4, "x > {0}"); public static final Condition LESS_THAN = new Condition(5, "x < {0}"); public static final Condition GREATER_EQUAL = new Condition(6, "x >= {0}"); public static final Condition LESS_EQUAL = new Condition(7, "x <= {0}"); // The masks private static final int STRING_LIST_GIVEN_MASK = 0x80; private static final int EMPTY_CELLS_ALLOWED_MASK = 0x100; private static final int SUPPRESS_ARROW_MASK = 0x200; private static final int SHOW_PROMPT_MASK = 0x40000; private static final int SHOW_ERROR_MASK = 0x80000; // The decimal format private static DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.#"); // The maximum string length for a data validation list private static final int MAX_VALIDATION_LIST_LENGTH = 254; // The maximum number of rows and columns private static final int MAX_ROWS = 0xffff; private static final int MAX_COLUMNS = 0xff; /** The type */ private DVType type; /** The error style */ private ErrorStyle errorStyle; /** The condition */ private Condition condition; /** String list option */ private boolean stringListGiven; /** Empty cells allowed */ private boolean emptyCellsAllowed; /** Suppress arrow */ private boolean suppressArrow; /** Show prompt */ private boolean showPrompt; /** Show error */ private boolean showError; /** The title of the prompt box */ private String promptTitle; /** The title of the error box */ private String errorTitle; /** The text of the prompt box */ private String promptText; /** The text of the error box */ private String errorText; /** The first formula */ private FormulaParser formula1; /** The first formula string */ private String formula1String; /** The second formula */ private FormulaParser formula2; /** The second formula string */ private String formula2String; /** The column number of the cell at the top left of the range */ private int column1; /** The row number of the cell at the top left of the range */ private int row1; /** The column index of the cell at the bottom right */ private int column2; /** The row index of the cell at the bottom right */ private int row2; /** Flag to indicate that this DV Parser is shared amongst a group of cells */ private boolean extendedCellsValidation; /** Flag indicated whether this has been copied */ private boolean copied; /** Constructor */ public DVParser(byte[] data, ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) { Assert.verify(nt != null); copied = false; int options = IntegerHelper.getInt(data[0], data[1], data[2], data[3]); int typeVal = options & 0xf; type = DVType.getType(typeVal); int errorStyleVal = (options & 0x70) >> 4; errorStyle = ErrorStyle.getErrorStyle(errorStyleVal); int conditionVal = (options & 0xf00000) >> 20; condition = Condition.getCondition(conditionVal); stringListGiven = (options & STRING_LIST_GIVEN_MASK) != 0; emptyCellsAllowed = (options & EMPTY_CELLS_ALLOWED_MASK) != 0; suppressArrow = (options & SUPPRESS_ARROW_MASK) != 0; showPrompt = (options & SHOW_PROMPT_MASK) != 0; showError = (options & SHOW_ERROR_MASK) != 0; int pos = 4; int length = IntegerHelper.getInt(data[pos], data[pos + 1]); if (length > 0 && data[pos + 2] == 0) { promptTitle = StringHelper.getString(data, length, pos + 3, ws); pos += length + 3; } else if (length > 0) { promptTitle = StringHelper.getUnicodeString(data, length, pos + 3); pos += length * 2 + 3; } else { pos += 3; } length = IntegerHelper.getInt(data[pos], data[pos + 1]); if (length > 0 && data[pos + 2] == 0) { errorTitle = StringHelper.getString(data, length, pos + 3, ws); pos += length + 3; } else if (length > 0) { errorTitle = StringHelper.getUnicodeString(data, length, pos + 3); pos += length * 2 + 3; } else { pos += 3; } length = IntegerHelper.getInt(data[pos], data[pos + 1]); if (length > 0 && data[pos + 2] == 0) { promptText = StringHelper.getString(data, length, pos + 3, ws); pos += length + 3; } else if (length > 0) { promptText = StringHelper.getUnicodeString(data, length, pos + 3); pos += length * 2 + 3; } else { pos += 3; } length = IntegerHelper.getInt(data[pos], data[pos + 1]); if (length > 0 && data[pos + 2] == 0) { errorText = StringHelper.getString(data, length, pos + 3, ws); pos += length + 3; } else if (length > 0) { errorText = StringHelper.getUnicodeString(data, length, pos + 3); pos += length * 2 + 3; } else { pos += 3; } int formula1Length = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 4; int formula1Pos = pos; pos += formula1Length; int formula2Length = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 4; int formula2Pos = pos; pos += formula2Length; pos += 2; row1 = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 2; row2 = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 2; column1 = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 2; column2 = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 2; extendedCellsValidation = (row1 == row2 && column1 == column2) ? false : true; // Do the formulas try { // First, create a temporary blank cell for any formula relative // references EmptyCell tmprt = new EmptyCell(column1, row1); if (formula1Length != 0) { byte[] tokens = new byte[formula1Length]; System.arraycopy(data, formula1Pos, tokens, 0, formula1Length); formula1 = new FormulaParser(tokens, tmprt, es, nt, ws, ParseContext.DATA_VALIDATION); formula1.parse(); } if (formula2Length != 0) { byte[] tokens = new byte[formula2Length]; System.arraycopy(data, formula2Pos, tokens, 0, formula2Length); formula2 = new FormulaParser(tokens, tmprt, es, nt, ws, ParseContext.DATA_VALIDATION); formula2.parse(); } } catch (FormulaException e) { logger.warn( e.getMessage() + " for cells " + CellReferenceHelper.getCellReference(column1, row1) + "-" + CellReferenceHelper.getCellReference(column2, row2)); } } /** Constructor called when creating a data validation from the API */ public DVParser(Collection strings) { copied = false; type = LIST; errorStyle = STOP; condition = BETWEEN; extendedCellsValidation = false; // the options stringListGiven = true; emptyCellsAllowed = true; suppressArrow = false; showPrompt = true; showError = true; promptTitle = "\0"; errorTitle = "\0"; promptText = "\0"; errorText = "\0"; if (strings.size() == 0) { logger.warn("no validation strings - ignoring"); } Iterator i = strings.iterator(); StringBuffer formulaString = new StringBuffer(); formulaString.append(i.next().toString()); while (i.hasNext()) { formulaString.append('\0'); formulaString.append(' '); formulaString.append(i.next().toString()); } // If the formula string exceeds // the maximum validation list length, then truncate and stop there if (formulaString.length() > MAX_VALIDATION_LIST_LENGTH) { logger.warn("Validation list exceeds maximum number of characters - " + "truncating"); formulaString.delete(MAX_VALIDATION_LIST_LENGTH, formulaString.length()); } // Put the string in quotes formulaString.insert(0, '\"'); formulaString.append('\"'); formula1String = formulaString.toString(); } /** Constructor called when creating a data validation from the API */ public DVParser(String namedRange) { // Handle the case for an empty string if (namedRange.length() == 0) { copied = false; type = FORMULA; errorStyle = STOP; condition = EQUAL; extendedCellsValidation = false; // the options stringListGiven = false; emptyCellsAllowed = false; suppressArrow = false; showPrompt = true; showError = true; promptTitle = "\0"; errorTitle = "\0"; promptText = "\0"; errorText = "\0"; formula1String = "\"\""; return; } copied = false; type = LIST; errorStyle = STOP; condition = BETWEEN; extendedCellsValidation = false; // the options stringListGiven = false; emptyCellsAllowed = true; suppressArrow = false; showPrompt = true; showError = true; promptTitle = "\0"; errorTitle = "\0"; promptText = "\0"; errorText = "\0"; formula1String = namedRange; } /** Constructor called when creating a data validation from the API */ public DVParser(int c1, int r1, int c2, int r2) { copied = false; type = LIST; errorStyle = STOP; condition = BETWEEN; extendedCellsValidation = false; // the options stringListGiven = false; emptyCellsAllowed = true; suppressArrow = false; showPrompt = true; showError = true; promptTitle = "\0"; errorTitle = "\0"; promptText = "\0"; errorText = "\0"; StringBuffer formulaString = new StringBuffer(); CellReferenceHelper.getCellReference(c1, r1, formulaString); formulaString.append(':'); CellReferenceHelper.getCellReference(c2, r2, formulaString); formula1String = formulaString.toString(); } /** Constructor called when creating a data validation from the API */ public DVParser(double val1, double val2, Condition c) { copied = false; type = DECIMAL; errorStyle = STOP; condition = c; extendedCellsValidation = false; // the options stringListGiven = false; emptyCellsAllowed = true; suppressArrow = false; showPrompt = true; showError = true; promptTitle = "\0"; errorTitle = "\0"; promptText = "\0"; errorText = "\0"; formula1String = DECIMAL_FORMAT.format(val1); if (!Double.isNaN(val2)) { formula2String = DECIMAL_FORMAT.format(val2); } } /** Constructor called when doing a cell deep copy */ public DVParser(DVParser copy) { copied = true; type = copy.type; errorStyle = copy.errorStyle; condition = copy.condition; stringListGiven = copy.stringListGiven; emptyCellsAllowed = copy.emptyCellsAllowed; suppressArrow = copy.suppressArrow; showPrompt = copy.showPrompt; showError = copy.showError; promptTitle = copy.promptTitle; promptText = copy.promptText; errorTitle = copy.errorTitle; errorText = copy.errorText; extendedCellsValidation = copy.extendedCellsValidation; row1 = copy.row1; row2 = copy.row2; column1 = copy.column1; column2 = copy.column2; // Don't copy the formula parsers - just take their string equivalents if (copy.formula1String != null) { formula1String = copy.formula1String; formula2String = copy.formula2String; } else { try { formula1String = copy.formula1.getFormula(); formula2String = (copy.formula2 != null) ? copy.formula2.getFormula() : null; } catch (FormulaException e) { logger.warn("Cannot parse validation formula: " + e.getMessage()); } } // Don't copy the cell references - these will be added later } /** Gets the data */ public byte[] getData() { // Compute the length of the data byte[] f1Bytes = formula1 != null ? formula1.getBytes() : new byte[0]; byte[] f2Bytes = formula2 != null ? formula2.getBytes() : new byte[0]; int dataLength = 4 + // the options promptTitle.length() * 2 + 3 + // the prompt title errorTitle.length() * 2 + 3 + // the error title promptText.length() * 2 + 3 + // the prompt text errorText.length() * 2 + 3 + // the error text f1Bytes.length + 2 + // first formula f2Bytes.length + 2 + // second formula +4 + // unused bytes 10; // cell range byte[] data = new byte[dataLength]; // The position int pos = 0; // The options int options = 0; options |= type.getValue(); options |= errorStyle.getValue() << 4; options |= condition.getValue() << 20; if (stringListGiven) { options |= STRING_LIST_GIVEN_MASK; } if (emptyCellsAllowed) { options |= EMPTY_CELLS_ALLOWED_MASK; } if (suppressArrow) { options |= SUPPRESS_ARROW_MASK; } if (showPrompt) { options |= SHOW_PROMPT_MASK; } if (showError) { options |= SHOW_ERROR_MASK; } // The text IntegerHelper.getFourBytes(options, data, pos); pos += 4; IntegerHelper.getTwoBytes(promptTitle.length(), data, pos); pos += 2; data[pos] = (byte) 0x1; // unicode indicator pos++; StringHelper.getUnicodeBytes(promptTitle, data, pos); pos += promptTitle.length() * 2; IntegerHelper.getTwoBytes(errorTitle.length(), data, pos); pos += 2; data[pos] = (byte) 0x1; // unicode indicator pos++; StringHelper.getUnicodeBytes(errorTitle, data, pos); pos += errorTitle.length() * 2; IntegerHelper.getTwoBytes(promptText.length(), data, pos); pos += 2; data[pos] = (byte) 0x1; // unicode indicator pos++; StringHelper.getUnicodeBytes(promptText, data, pos); pos += promptText.length() * 2; IntegerHelper.getTwoBytes(errorText.length(), data, pos); pos += 2; data[pos] = (byte) 0x1; // unicode indicator pos++; StringHelper.getUnicodeBytes(errorText, data, pos); pos += errorText.length() * 2; // Formula 1 IntegerHelper.getTwoBytes(f1Bytes.length, data, pos); pos += 4; System.arraycopy(f1Bytes, 0, data, pos, f1Bytes.length); pos += f1Bytes.length; // Formula 2 IntegerHelper.getTwoBytes(f2Bytes.length, data, pos); pos += 4; System.arraycopy(f2Bytes, 0, data, pos, f2Bytes.length); pos += f2Bytes.length; // The cell ranges IntegerHelper.getTwoBytes(1, data, pos); pos += 2; IntegerHelper.getTwoBytes(row1, data, pos); pos += 2; IntegerHelper.getTwoBytes(row2, data, pos); pos += 2; IntegerHelper.getTwoBytes(column1, data, pos); pos += 2; IntegerHelper.getTwoBytes(column2, data, pos); pos += 2; return data; } /** * Inserts a row * * @param row the row to insert */ public void insertRow(int row) { if (formula1 != null) { formula1.rowInserted(0, row, true); } if (formula2 != null) { formula2.rowInserted(0, row, true); } if (row1 >= row) { row1++; } if (row2 >= row && row2 != MAX_ROWS) { row2++; } } /** * Inserts a column * * @param col the column to insert */ public void insertColumn(int col) { if (formula1 != null) { formula1.columnInserted(0, col, true); } if (formula2 != null) { formula2.columnInserted(0, col, true); } if (column1 >= col) { column1++; } if (column2 >= col && column2 != MAX_COLUMNS) { column2++; } } /** * Removes a row * * @param row the row to insert */ public void removeRow(int row) { if (formula1 != null) { formula1.rowRemoved(0, row, true); } if (formula2 != null) { formula2.rowRemoved(0, row, true); } if (row1 > row) { row1--; } if (row2 >= row) { row2--; } } /** * Removes a column * * @param col the row to remove */ public void removeColumn(int col) { if (formula1 != null) { formula1.columnRemoved(0, col, true); } if (formula2 != null) { formula2.columnRemoved(0, col, true); } if (column1 > col) { column1--; } if (column2 >= col && column2 != MAX_COLUMNS) { column2--; } } /** * Accessor for first column * * @return the first column */ public int getFirstColumn() { return column1; } /** * Accessor for the last column * * @return the last column */ public int getLastColumn() { return column2; } /** * Accessor for first row * * @return the first row */ public int getFirstRow() { return row1; } /** * Accessor for the last row * * @return the last row */ public int getLastRow() { return row2; } /** * Gets the formula present in the validation * * @return the validation formula as a string * @exception FormulaException */ String getValidationFormula() throws FormulaException { if (type == LIST) { return formula1.getFormula(); } String s1 = formula1.getFormula(); String s2 = formula2 != null ? formula2.getFormula() : null; return condition.getConditionString(s1, s2) + "; x " + type.getDescription(); } /** Called by the cell value when the cell features are added to the sheet */ public void setCell(int col, int row, ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) throws FormulaException { // If this is part of an extended cells validation, then do nothing // as this will already have been called and parsed when the top left // cell was added if (extendedCellsValidation) { return; } row1 = row; row2 = row; column1 = col; column2 = col; formula1 = new FormulaParser(formula1String, es, nt, ws, ParseContext.DATA_VALIDATION); formula1.parse(); if (formula2String != null) { formula2 = new FormulaParser(formula2String, es, nt, ws, ParseContext.DATA_VALIDATION); formula2.parse(); } } /** * Indicates that the data validation extends across several more cells * * @param cols - the number of extra columns * @param rows - the number of extra rows */ public void extendCellValidation(int cols, int rows) { row2 = row1 + rows; column2 = column1 + cols; extendedCellsValidation = true; } /** Accessor which indicates whether this validation applies across multiple cels */ public boolean extendedCellsValidation() { return extendedCellsValidation; } public boolean copied() { return copied; } }
/** Constructor */ public DVParser(byte[] data, ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) { Assert.verify(nt != null); copied = false; int options = IntegerHelper.getInt(data[0], data[1], data[2], data[3]); int typeVal = options & 0xf; type = DVType.getType(typeVal); int errorStyleVal = (options & 0x70) >> 4; errorStyle = ErrorStyle.getErrorStyle(errorStyleVal); int conditionVal = (options & 0xf00000) >> 20; condition = Condition.getCondition(conditionVal); stringListGiven = (options & STRING_LIST_GIVEN_MASK) != 0; emptyCellsAllowed = (options & EMPTY_CELLS_ALLOWED_MASK) != 0; suppressArrow = (options & SUPPRESS_ARROW_MASK) != 0; showPrompt = (options & SHOW_PROMPT_MASK) != 0; showError = (options & SHOW_ERROR_MASK) != 0; int pos = 4; int length = IntegerHelper.getInt(data[pos], data[pos + 1]); if (length > 0 && data[pos + 2] == 0) { promptTitle = StringHelper.getString(data, length, pos + 3, ws); pos += length + 3; } else if (length > 0) { promptTitle = StringHelper.getUnicodeString(data, length, pos + 3); pos += length * 2 + 3; } else { pos += 3; } length = IntegerHelper.getInt(data[pos], data[pos + 1]); if (length > 0 && data[pos + 2] == 0) { errorTitle = StringHelper.getString(data, length, pos + 3, ws); pos += length + 3; } else if (length > 0) { errorTitle = StringHelper.getUnicodeString(data, length, pos + 3); pos += length * 2 + 3; } else { pos += 3; } length = IntegerHelper.getInt(data[pos], data[pos + 1]); if (length > 0 && data[pos + 2] == 0) { promptText = StringHelper.getString(data, length, pos + 3, ws); pos += length + 3; } else if (length > 0) { promptText = StringHelper.getUnicodeString(data, length, pos + 3); pos += length * 2 + 3; } else { pos += 3; } length = IntegerHelper.getInt(data[pos], data[pos + 1]); if (length > 0 && data[pos + 2] == 0) { errorText = StringHelper.getString(data, length, pos + 3, ws); pos += length + 3; } else if (length > 0) { errorText = StringHelper.getUnicodeString(data, length, pos + 3); pos += length * 2 + 3; } else { pos += 3; } int formula1Length = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 4; int formula1Pos = pos; pos += formula1Length; int formula2Length = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 4; int formula2Pos = pos; pos += formula2Length; pos += 2; row1 = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 2; row2 = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 2; column1 = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 2; column2 = IntegerHelper.getInt(data[pos], data[pos + 1]); pos += 2; extendedCellsValidation = (row1 == row2 && column1 == column2) ? false : true; // Do the formulas try { // First, create a temporary blank cell for any formula relative // references EmptyCell tmprt = new EmptyCell(column1, row1); if (formula1Length != 0) { byte[] tokens = new byte[formula1Length]; System.arraycopy(data, formula1Pos, tokens, 0, formula1Length); formula1 = new FormulaParser(tokens, tmprt, es, nt, ws, ParseContext.DATA_VALIDATION); formula1.parse(); } if (formula2Length != 0) { byte[] tokens = new byte[formula2Length]; System.arraycopy(data, formula2Pos, tokens, 0, formula2Length); formula2 = new FormulaParser(tokens, tmprt, es, nt, ws, ParseContext.DATA_VALIDATION); formula2.parse(); } } catch (FormulaException e) { logger.warn( e.getMessage() + " for cells " + CellReferenceHelper.getCellReference(column1, row1) + "-" + CellReferenceHelper.getCellReference(column2, row2)); } }