1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula; 25 26 import java.io.ByteArrayOutputStream; 27 import java.io.IOException; 28 import java.util.Vector; 29 import java.util.Enumeration; 30 31 import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook; 32 33 /** 34 * This Helper class provides a simplified interface to conversion between PocketXL formula representation 35 * and Calc formula representation.<p> 36 * The class is used by {@link org.openoffice.xmerge.converter.xml.sxc.pexcel.Records.Formula} 37 */ 38 public class FormulaHelper { 39 40 private static FormulaParser parser; 41 private static FormulaCompiler compiler; 42 private static TokenEncoder encoder; 43 private static TokenDecoder decoder; 44 private boolean rangeType = false; 45 private boolean expressionType = false; 46 47 static { 48 parser = new FormulaParser(); 49 compiler = new FormulaCompiler(); 50 encoder = new TokenEncoder(); 51 decoder = new TokenDecoder(); 52 } 53 54 /** 55 * Sets the workbook cache so that global data such as 56 * <code>DefinedNames</code>, <code>Boundsheets</code> can be read 57 * 58 * @param wb Wrokbook object containing all the global data 59 */ setWorkbook(Workbook wb)60 public void setWorkbook(Workbook wb) { 61 62 encoder.setWorkbook(wb); 63 decoder.setWorkbook(wb); 64 parser.setWorkbook(wb); 65 } 66 67 /** 68 * Convertes a string representation of a calc formula into an array of PocketXL bytes 69 * @param formula The Formula String (e.g. 1+SUM(A1,B1)) 70 * 71 * @throws UnsupportedFunctionException Thrown if a function in the formula is nto supported by Pocket Excel 72 * @throws FormulaParsingException Thrown when the formula is not well formed 73 * 74 */ convertCalcToPXL(String formula)75 public byte[] convertCalcToPXL(String formula) throws UnsupportedFunctionException, FormulaParsingException { 76 77 Vector parseTokens = parser.parse(formula); 78 Vector rpnTokens = compiler.infix2RPN(parseTokens); 79 80 ByteArrayOutputStream bytes = null; 81 try { 82 bytes = new ByteArrayOutputStream(); 83 for (Enumeration e = rpnTokens.elements(); e.hasMoreElements();) { 84 Token t = (Token)e.nextElement(); 85 bytes.write(encoder.getByte(t)); 86 } 87 } catch (IOException e) { 88 } 89 90 return bytes.toByteArray(); 91 } 92 93 /** 94 * Converts a PocketXL byte array into a Calc function string 95 * @param formula A byte array that contains the PocketXL bytes for a formula 96 * 97 */ convertPXLToCalc(byte[] formula)98 public String convertPXLToCalc(byte[] formula) { 99 100 Vector parseTokens = decoder.getTokenVector(formula); 101 Vector infixTokens = compiler.RPN2Infix(parseTokens); 102 103 StringBuffer buff = new StringBuffer(); 104 for (Enumeration e = infixTokens.elements();e.hasMoreElements();) { 105 Token t = (Token)e.nextElement(); 106 buff.append(t.toString()); 107 // If we are parsing a Name definition we need to know if it is of 108 // type range or expression 109 if(!t.isOperand()) { 110 expressionType = true; 111 } 112 } 113 if(!expressionType) { 114 rangeType = true; 115 } 116 return "=" + buff.toString(); 117 } 118 119 /** 120 * Returns a boolean indicating whether or not the byte[] parsed is of 121 * type range. This means it contains only a cell reference and no 122 * operators. This is necessry because the syntax for range and expression 123 * types differs. This is only of interest when dealing with 124 * <code>DefinedNames</code> and not <code>Formula</code> 125 * 126 * @return a boolean true if of type range otherwise false 127 * 128 */ isRangeType()129 public boolean isRangeType() { 130 131 return rangeType; 132 } 133 134 /** 135 * Returns a boolean indicating whether or not the byte[] parsed is of 136 * type expression. This means it contains operators. This is necessry 137 * because the syntax for range and expression types differs. This is 138 * only of interest when dealing with <code>DefinedNames</code> and not 139 * <code>Formula</code> 140 * 141 * @return a boolean true if of type expression otherwise false 142 * 143 */ isExpressionType()144 public boolean isExpressionType() { 145 146 return expressionType; 147 } 148 } 149