summaryrefslogtreecommitdiff
path: root/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java
diff options
context:
space:
mode:
Diffstat (limited to 'xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java')
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java559
1 files changed, 559 insertions, 0 deletions
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java
new file mode 100644
index 000000000000..249e14ac620f
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java
@@ -0,0 +1,559 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.io.*;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.DefinedName;
+
+/**
+ * The TokenEncoder encodes a Token to an equivalent pexcel byte[]. The only
+ * public method apart from the default constructor is the getByte method.
+ * This method picks an encoder based onthe Token's type or id field and uses
+ * that encoder to return a byte[] which it returns. This Encoder supports
+ * Operands Floating point's, Cell references (absolute and relative),
+ * cell ranges
+ * Operators +,-,*,/,&lt;,&gt;.&lt;=,&gt;=,&lt;&gt;
+ * Functions All pexcel fixed and varaible argument functions
+ *
+ */
+public class TokenEncoder {
+
+ private FunctionLookup fl;
+ private String parseString;
+ private int index;
+ private Workbook wb;
+
+ /**
+ * Default Constructor
+ */
+ public TokenEncoder() {
+
+ parseString = new String();
+ fl = new FunctionLookup();
+ }
+
+ /**
+ * Sets global workbook data needed for defined names
+ */
+ public void setWorkbook(Workbook wb) {
+
+ this.wb = wb;
+ }
+
+
+ /**
+ * Return the byte[] equivalent of a <code>Token</code>. The various
+ * encoders return <code>Vector</code> of <code>Byte</code> instead
+ * of byte[] because the number of bytes returned varies with each
+ * <code>Token</code> encoded. After the encoding is finished the Vector
+ * in converted to a byte[].
+ *
+ * @param t The <code>Token</code> to be encoded
+ * @return An equivalent Pocket Excel byte[]
+ */
+ public byte[] getByte(Token t) throws IOException {
+
+ Vector tmpByteArray = null; // we use this cause we don't know till after
+ // the encoding takes place how big the byte [] will be
+ //index=0; // This class is declared static in
+ // FormulaHelper so better make sure our index is 0
+ if(t.getTokenType()==ParseToken.TOKEN_OPERATOR) {
+ tmpByteArray = operatorEncoder(t);
+ } else if (t.getTokenType()==ParseToken.TOKEN_FUNCTION_VARIABLE || t.getTokenType()==ParseToken.TOKEN_FUNCTION_FIXED){
+ tmpByteArray = functionEncoder(t);
+ } else { // Operands and functions
+ switch(t.getTokenID()) {
+ case TokenConstants.TNAME :
+ tmpByteArray = nameDefinitionEncoder(t);
+ break;
+ case TokenConstants.TREF3D :
+ tmpByteArray = threeDCellRefEncoder(t);
+ break;
+ case TokenConstants.TAREA3D:
+ tmpByteArray = threeDAreaRefEncoder(t);
+ break;
+ case TokenConstants.TREF :
+ tmpByteArray = cellRefEncoder(t);
+ break;
+ case TokenConstants.TAREA :
+ tmpByteArray = areaRefEncoder(t);
+ break;
+ case TokenConstants.TNUM :
+ tmpByteArray = numEncoder(t);
+ break;
+ case TokenConstants.TSTRING :
+ tmpByteArray = stringEncoder(t);
+ break;
+ default :
+ Debug.log(Debug.ERROR, "Encoder found unrecognized Token");
+ }
+ }
+
+ byte cellRefArray[] = new byte[tmpByteArray.size()];
+ int i = 0;
+ String s = new String();
+ for(Enumeration e = tmpByteArray.elements();e.hasMoreElements();) {
+ Byte tmpByte = (Byte) e.nextElement();
+ s = s + tmpByte + " ";
+ cellRefArray[i] = tmpByte.byteValue();
+ i++;
+ }
+ Debug.log(Debug.TRACE, "Encoding Token " + t.getValue() + " as [" + s + "]");
+ return cellRefArray;
+ }
+
+ /**
+ * An Operator Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector operatorEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ return tmpByteArray;
+ }
+
+
+ /**
+ * A String Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector stringEncoder(Token t) throws IOException{
+
+ Vector tmpByteArray = new Vector();
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ tmpByteArray.add(new Byte((byte)(t.getValue().length())));
+ tmpByteArray.add(new Byte((byte)0x01));
+ byte [] stringBytes = t.getValue().getBytes("UTF-16LE");
+ for (int i=0; i<stringBytes.length; i++) {
+ tmpByteArray.add(new Byte(stringBytes[i]));
+ }
+ return tmpByteArray;
+ }
+
+
+ /**
+ * An Integer Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector numEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ double cellLong = (double) Double.parseDouble(t.getValue());
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ byte[] tempByte = EndianConverter.writeDouble(cellLong);
+ for(int byteIter=0;byteIter<tempByte.length;byteIter++) {
+ tmpByteArray.add(new Byte(tempByte[byteIter]));
+ }
+ return tmpByteArray;
+ }
+
+ /**
+ * Converts a char to an int. It is zero based
+ * so a=0, b=1 etc.
+ *
+ * @param ch the character to be converted
+ * @return -1 if not a character otherwise a 0 based index
+ */
+ private int char2int(char ch) {
+ if(!Character.isLetter(ch))
+ return -1;
+
+ ch = Character.toUpperCase(ch);
+ return ch-'A';
+ }
+
+ /**
+ * Identify letters
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAlpha(char c) {
+ return(Character.isLetter(c));
+ }
+
+ /**
+ * Identify numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isDigit(char c) {
+ return(Character.isDigit(c));
+ }
+
+ /**
+ * Identify letters or numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAlphaNum(char c) {
+ return(isAlpha(c) || isDigit(c));
+ }
+
+ /**
+ * Parses a column reference and returns it's integer equivalent. (eg.
+ * A=0, D=3, BA=27)
+ *
+ * @return an 0 based index to a column
+ */
+ private int column() {
+ char ch = parseString.charAt(index);
+ String columnStr = new String();
+ int col = 0;
+
+ while(isAlpha(ch)) {
+ columnStr += ch;
+ index++;
+ ch = parseString.charAt(index);
+ }
+
+ if(columnStr.length()==1) {
+ col = char2int(columnStr.charAt(0));
+ } else if (columnStr.length()==2) {
+ col = char2int(columnStr.charAt(0)) + 1;
+ col = (col*26) + char2int(columnStr.charAt(1));
+ } else {
+ Debug.log(Debug.ERROR, "Invalid Column Reference " + columnStr );
+ }
+
+
+ return col;
+ }
+
+ /**
+ * Parses a column reference and returns it's integer equivalent. (eg.
+ * A=0, D=3, BA=27)
+ *
+ * @return an 0 based index to a column
+ */
+ private int row() {
+ char ch = parseString.charAt(index);
+ String rowStr = new String();
+ int row = 0;
+ boolean status = true;
+
+ do {
+ rowStr += ch;
+ index++;
+ if(index>=parseString.length()) {
+ status = false;
+ } else {
+ ch = parseString.charAt(index);
+ }
+ } while(isDigit(ch) && status);
+ return Integer.parseInt(rowStr)-1; // Pexcel uses a 0 based index
+ }
+
+ /**
+ * A Cell Reference Encoder (It supports absolute and relative addressing)
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private byte[] encodeCellCoordinates(String cellCoordinates) {
+ int col = 0, row = 0;
+ int addressing = 0xC000;
+
+ index = 0;
+ parseString = cellCoordinates;
+ Debug.log(Debug.TRACE,"Encoding cell coordinates " + cellCoordinates);
+ if(cellCoordinates.charAt(index)=='$') {
+ addressing &= 0x8000;
+ index++;
+ }
+ col = column();
+ if(cellCoordinates.charAt(index)=='$') {
+ addressing &= 0x4000;
+ index++;
+ }
+ row = row(); // Pexcel uses a 0 based index
+ row |= addressing;
+ byte tokenBytes[] = new byte[3];
+ tokenBytes[0] = (byte)row;
+ tokenBytes[1] = (byte)(row>>8);
+ tokenBytes[2] = (byte)col;
+ return tokenBytes;
+ }
+
+ /**
+ * A name definition Encoder
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector nameDefinitionEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ String nameString = t.getValue();
+ Debug.log(Debug.TRACE,"NameDefinitionEncoder : " + nameString);
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ Enumeration e = wb.getDefinedNames();
+ DefinedName dn;
+ String name;
+ int definedNameIndex = 0;
+ do {
+ dn = (DefinedName)e.nextElement();
+ name = dn.getName();
+ Debug.log(Debug.TRACE,"Name pulled from DefinedName : " + name);
+ definedNameIndex++;
+ } while(!nameString.equalsIgnoreCase(name) && e.hasMoreElements());
+
+ tmpByteArray.add(new Byte((byte)definedNameIndex));
+ tmpByteArray.add(new Byte((byte)0x00));
+
+ for(int i = 0;i < 12;i++) {
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ return tmpByteArray;
+ }
+ /**
+ * A Cell Reference Encoder. It supports absolute and relative addressing
+ * but not sheetnames.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector cellRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ byte cellRefBytes[] = encodeCellCoordinates(t.getValue());
+ for(int i = 0;i < cellRefBytes.length;i++) {
+ tmpByteArray.add(new Byte(cellRefBytes[i]));
+ }
+ return tmpByteArray;
+ }
+
+ /**
+ * This function will find the sheetname index for a given String
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private short findSheetIndex(String s) {
+
+ short sheetIndex = 0;
+ String savedName;
+ String sheetName;
+ if (s.startsWith("$")) {
+ sheetName = s.substring(1,s.length()); // Remove $
+ } else {
+ sheetName = s.substring(0,s.length());
+ }
+ Debug.log(Debug.TRACE,"Searching for Worksheet : " + sheetName);
+ Vector names = wb.getWorksheetNames();
+ Enumeration e = names.elements();
+ do {
+ savedName = (String) e.nextElement();
+ sheetIndex++;
+ } while(!savedName.equalsIgnoreCase(sheetName) && e.hasMoreElements());
+
+ Debug.log(Debug.TRACE,"Setting sheetindex to " + sheetIndex);
+ return (short)(sheetIndex-1);
+ }
+
+ /**
+ * A 3D Cell reference encoder
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector threeDCellRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+ parseString = t.getValue();
+ Debug.log(Debug.TRACE,"Encoding 3D Cell reference " + t);
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ for(int i = 0;i < 8;i++) {
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ String sheetRef = parseString.substring(0, parseString.indexOf('.') + 1);
+ if (sheetRef.indexOf(':')!=-1) {
+ sheetRef = parseString.substring(0, parseString.indexOf(':'));
+ short sheetNum1 = findSheetIndex(sheetRef);
+ sheetRef = parseString.substring(parseString.indexOf(':') + 1, parseString.length());
+ short sheetNum2 = findSheetIndex(sheetRef);
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum2));
+ tmpByteArray.add(new Byte((byte)0x00));
+ } else {
+ sheetRef = parseString.substring(0, parseString.indexOf('.'));
+ short sheetNum = findSheetIndex(sheetRef);
+ tmpByteArray.add(new Byte((byte)sheetNum));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum));
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+ String s = parseString.substring(parseString.indexOf('.') + 1, parseString.length());
+ Debug.log(Debug.TRACE,"Parsing : " + s);
+ byte cellRefBytes[] = encodeCellCoordinates(s);
+ for(int i = 0;i < cellRefBytes.length;i++) {
+ tmpByteArray.add(new Byte(cellRefBytes[i]));
+ }
+ return tmpByteArray;
+ }
+ /**
+ * A 3D Area Reference Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector threeDAreaRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+ parseString = t.getValue();
+ Debug.log(Debug.TRACE,"Encoding 3D Area reference " + t);
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ for(int i = 0;i < 8;i++) {
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ String param1= parseString.substring(0, parseString.indexOf(':'));
+ String cellRef1 = param1.substring(parseString.indexOf('.') + 1, param1.length());
+ String sheetRef1 = param1.substring(0, param1.indexOf('.'));
+ short sheetNum1 = findSheetIndex(sheetRef1);
+
+ String param2 = parseString.substring(parseString.indexOf(':') + 1, parseString.length());
+ Debug.log(Debug.TRACE,"param2: " + param2);
+ String cellRef2 = param2.substring(param2.indexOf('.') + 1, param2.length());
+ Debug.log(Debug.TRACE,"cellRef2: " + cellRef2);
+
+ if(param2.indexOf('.')==-1) {
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ } else {
+ String sheetRef2 = param2.substring(0, param2.indexOf('.'));
+ short sheetNum2 = findSheetIndex(sheetRef2);
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum2));
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ byte cellRefBytes1[] = encodeCellCoordinates(cellRef1);
+ byte cellRefBytes2[] = encodeCellCoordinates(cellRef2);
+
+ tmpByteArray.add(new Byte(cellRefBytes1[0]));
+ tmpByteArray.add(new Byte(cellRefBytes1[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes2[0]));
+ tmpByteArray.add(new Byte(cellRefBytes2[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes1[2]));
+ tmpByteArray.add(new Byte(cellRefBytes2[2]));
+
+ return tmpByteArray;
+ }
+
+ /**
+ * A Cell Range Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector areaRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ String param = t.getValue();
+ String cellRef1 = new String();
+ String cellRef2 = new String();
+
+ if(param.indexOf(':')==-1) {
+ Debug.log(Debug.ERROR, "Invalid Cell Range, could not find :");
+ } else {
+ cellRef1 = param.substring(0, param.indexOf(':'));
+ cellRef2 = param.substring(param.indexOf(':') + 1, param.length());
+ }
+ byte cellRefBytes1[] = encodeCellCoordinates(cellRef1);
+ byte cellRefBytes2[] = encodeCellCoordinates(cellRef2);
+
+ tmpByteArray.add(new Byte(cellRefBytes1[0]));
+ tmpByteArray.add(new Byte(cellRefBytes1[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes2[0]));
+ tmpByteArray.add(new Byte(cellRefBytes2[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes1[2]));
+ tmpByteArray.add(new Byte(cellRefBytes2[2]));
+
+ return tmpByteArray;
+ }
+
+ /**
+ * A Function Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector functionEncoder(Token t) {
+ Vector tmpByteArray = new Vector();
+
+ int id = t.getTokenID();
+ if(t.getTokenType()==ParseToken.TOKEN_FUNCTION_VARIABLE) {
+ tmpByteArray.add(new Byte((byte)TokenConstants.TFUNCVAR));
+ tmpByteArray.add(new Byte((byte)t.getNumArgs()));
+ } else {
+ tmpByteArray.add(new Byte((byte)TokenConstants.TFUNC));
+ }
+
+ tmpByteArray.add(new Byte((byte)id));
+ tmpByteArray.add(new Byte((byte)(id>>8)));
+ return tmpByteArray;
+ }
+
+
+}