xref: /AOO41X/main/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Formula.java (revision 0c0e82a55dc5b7baa849907647dcb88a54f5f573)
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;
25 
26 import java.io.OutputStream;
27 import java.io.InputStream;
28 import java.io.IOException;
29 
30 import org.openoffice.xmerge.util.Debug;
31 import org.openoffice.xmerge.util.EndianConverter;
32 import org.openoffice.xmerge.converter.xml.OfficeConstants;
33 import org.openoffice.xmerge.converter.xml.sxc.Format;
34 import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula.FormulaHelper;
35 import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
36 import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
37 
38 
39 /**
40  * Represents a BIFF Record describing a formula
41  */
42 public class Formula extends CellValue implements OfficeConstants {
43 
44     private byte[] num      = new byte[8];
45     private byte grbit;
46     private byte[] cce      = new byte[2];
47     private byte[] rgce;
48     private FormulaHelper fh = new FormulaHelper();
49 
50     /**
51      * Constructs a <code>Formula</code> using specified attributes
52      *
53      * @param row row number
54      * @param column column number
55      * @param cellContents contents of the cell
56      * @param ixfe font index
57      */
Formula(int row, int column, String cellContents, int ixfe, Format fmt, Workbook wb)58     public Formula(int row, int column, String cellContents, int ixfe, Format fmt, Workbook wb)
59     throws Exception {
60 
61         fh.setWorkbook(wb);
62 
63         setRow(row);
64         setCol(column);
65         setIxfe(ixfe);
66         setFormula(cellContents);
67 
68         String category = fmt.getCategory();
69         String value = fmt.getValue();
70 
71         if(category.equalsIgnoreCase(CELLTYPE_BOOLEAN)) {
72             num[0]=(byte)0x01;
73             num[1]=(byte)0x00;
74             if(value.equalsIgnoreCase("true")) {
75                 num[2]=(byte)0x01;
76             } else {
77                 num[2]=(byte)0x00;
78             }
79             num[3]=(byte)0x00;num[4]=(byte)0x00;num[5]=(byte)0x00;
80             num[6]=(byte)0xFF;num[7]=(byte)0xFF;
81         } else if(category.equalsIgnoreCase(CELLTYPE_DATE)) {
82             Debug.log(Debug.TRACE,"Date Formula");
83             num = EndianConverter.writeDouble(toExcelSerialDate(fmt.getValue()));
84         } else if(category.equalsIgnoreCase(CELLTYPE_TIME)) {
85             Debug.log(Debug.TRACE,"Time Formula");
86             num = EndianConverter.writeDouble(toExcelSerialTime(fmt.getValue()));
87         } else if(category.equalsIgnoreCase(CELLTYPE_PERCENT)) {
88             Debug.log(Debug.TRACE,"Percent Formula");
89             double percent = (double) Double.parseDouble(fmt.getValue());
90             num = EndianConverter.writeDouble(percent);
91         } else if(category.equalsIgnoreCase(CELLTYPE_CURRENCY)) {
92             Debug.log(Debug.TRACE,"Currency Formula");
93         } else if(category.equalsIgnoreCase(CELLTYPE_STRING)) {
94             Debug.log(Debug.TRACE,"String Formula");
95             num[0]=(byte)0x00;
96             num[1]=(byte)0x00;
97             num[2]=(byte)0x00;
98             num[3]=(byte)0x00;
99             num[4]=(byte)0x00;
100             num[5]=(byte)0x00;
101             num[6]=(byte)0xFF;
102             num[7]=(byte)0xFF;
103         } else {
104             Debug.log(Debug.TRACE,"Float Formula");
105             double cellLong = (double) Double.parseDouble(fmt.getValue());
106             num = EndianConverter.writeDouble(cellLong);
107         }
108     }
109 
110     /**
111      * Translates a <code>String</code> written in infix which represents a
112      * formula into a byte[] what can be written to pocket excel file.
113      *
114      * @param inFormula formula string
115      */
setFormula(String inFormula)116     public void setFormula(String inFormula) throws Exception {
117 
118         rgce = fh.convertCalcToPXL(inFormula);
119         cce = EndianConverter.writeShort((short) rgce.length);
120     }
121 
122     /**
123      * Constructs a pocket Excel formula from the
124      * <code>InputStream</code>
125      *
126      * @param   is InputStream containing a Pocket Excel Data file.
127      */
Formula(InputStream is, Workbook wb)128     public Formula(InputStream is, Workbook wb) throws IOException {
129         read(is);
130         fh.setWorkbook(wb);
131     }
132 
133     /**
134      * Get the hex code for this particular <code>BIFFRecord</code>
135      *
136      * @return the hex code for <code>Formula</code>
137      */
getBiffType()138     public short getBiffType() {
139         return PocketExcelConstants.FORMULA_CELL;
140     }
141 
142     /**
143      * Reads the formula data members from the stream. Byte arrays for Strings
144      * are doubled as they are stored as  unicode
145      *
146      * @return total number of bytes read
147      */
read(InputStream input)148     public int read(InputStream input) throws IOException {
149 
150         int numOfBytesRead = super.read(input);
151 
152         numOfBytesRead += input.read(num);
153         grbit               = (byte) input.read();
154         numOfBytesRead      ++;
155         numOfBytesRead      += input.read(cce);
156 
157         int strLen = EndianConverter.readShort(cce);
158         rgce = new byte[strLen];
159         input.read(rgce, 0, strLen);
160 
161         Debug.log(Debug.TRACE, " num : " + num +
162                             "\n\tgrbit : " + grbit +
163                             " cce : " + EndianConverter.readShort(cce) +
164                             " rgce : " + new String(rgce,"UTF-16LE") +
165                             "\n" + numOfBytesRead + " Bytes Read");
166 
167         return numOfBytesRead;
168     }
169 
170      /**
171      * Writes the Formula record to the <code>OutputStream</code>
172      *
173      * @param output the <code>OutputStream</code> being written to
174      */
write(OutputStream output)175     public void write(OutputStream output) throws IOException {
176 
177         output.write(getBiffType());
178 
179         super.write(output);
180 
181         output.write(num);
182         output.write(grbit);
183         output.write(cce);
184         output.write(rgce);
185 
186         Debug.log(Debug.TRACE,"Writing Formula record");
187     }
188 
189    /**
190      * Gets the <code>String</code> representing the cell value
191      *
192      * @return the <code>String</code> representing the cell value
193      */
getValue()194     public String getValue() throws IOException {
195 
196         double value = EndianConverter.readDouble(num);
197         Double myDo = new Double(value);
198         return myDo.toString();
199     }
200 
201     /**
202      * Gets the <code>String</code> representing the cells contents
203      *
204      * @return the <code>String</code> representing the cells contents
205      */
getString()206     public String getString() throws IOException {
207 
208         return fh.convertPXLToCalc(rgce);
209     }
210 
211     /**
212      * Excel dates are the number of days since 1/1/1900. This method converts
213      * to this date.
214      *
215      * @param s String representing a date in the form YYYY-MM-DD
216      * @return The excel serial date
217      */
toExcelSerialDate(String s)218     public long toExcelSerialDate(String s) throws IOException {
219 
220         int year = Integer.parseInt(s.substring(0,4));
221         int month = Integer.parseInt(s.substring(5,7));
222         int day = Integer.parseInt(s.substring(8,10));
223 
224         long serialDate =   (1461 * (year + 4800 + (month - 14) / 12)) / 4 +
225                             (367 * (month - 2 - 12 * ((month - 14) / 12))) / 12 -
226                             (3 * ((year + 4900 + (month - 14) / 12)) / 100) / 4 +
227                             day - 2415019 - 32075;
228 
229         return serialDate;
230     }
231 
232     /**
233      * Excel times are a fraction of a 24 hour day expressed in seconds. This method converts
234      * to this time.
235      *
236      * @param s String representing a time in the form ??HH?MM?SS?
237      * @return The excel serial time
238      */
toExcelSerialTime(String s)239     public double toExcelSerialTime(String s) throws IOException {
240 
241         int hours = Integer.parseInt(s.substring(2,4));
242         int mins = Integer.parseInt(s.substring(5,7));
243         int secs = Integer.parseInt(s.substring(8,10));
244 
245         int timeSecs = (hours*3600) + (mins*60) + (secs);
246 
247         double d = (double) timeSecs / (24 * 3600);
248 
249         return d;
250     }
251 
252 }
253