/** 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;
   }
 }
Exemple #3
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");
   }
 }
Exemple #6
0
 /*  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]";
  }
Exemple #8
0
/*  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:   */ }
Exemple #9
0
/*  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() {}
}
Exemple #14
0
/*   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));
    }
  }