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 import java.io.UnsupportedEncodingException; 30 31 import org.openoffice.xmerge.util.Debug; 32 import org.openoffice.xmerge.util.EndianConverter; 33 import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook; 34 import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula.FormulaHelper; 35 import org.openoffice.xmerge.converter.xml.sxc.NameDefinition; 36 import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants; 37 38 /** 39 * Represents a BIFF Record representing a defined name in the workbook 40 */ 41 public class DefinedName implements BIFFRecord { 42 43 private byte[] grbit = new byte[2]; 44 private byte cch; 45 private byte[] cce = new byte[2]; 46 private byte[] ixals = new byte[2]; 47 private byte[] rgch; 48 private byte[] rgce; 49 private FormulaHelper fh = new FormulaHelper(); 50 private String definition = new String(""); 51 private Workbook wb; 52 DefinedName(NameDefinition nd, Workbook wb)53 public DefinedName(NameDefinition nd, Workbook wb) throws IOException { 54 55 fh.setWorkbook(wb); 56 this.wb = wb; 57 String name = nd.getName(); 58 59 // we have to insert an = to stop the formulaParser throwing an exception 60 definition = "=" + nd.getDefinition(); 61 62 cch = (byte)name.length(); 63 rgch = new byte[cch*2]; 64 rgch = name.getBytes("UTF-16LE"); 65 grbit = EndianConverter.writeShort((short)0); 66 ixals[0] = (byte)0xFF;ixals[1] = (byte)0xFF; 67 } 68 /** 69 * Constructs a Defined Name from the <code>InputStream</code> 70 * 71 * @param is InputStream containing the record data 72 */ DefinedName(InputStream is, Workbook wb)73 public DefinedName(InputStream is, Workbook wb) throws IOException { 74 75 read(is); 76 fh.setWorkbook(wb); 77 this.wb = wb; 78 } 79 80 /** 81 * Get the hex code for this particular <code>BIFFRecord</code> 82 * 83 * @return the hex code for <code>DefinedName</code> 84 */ getBiffType()85 public short getBiffType() { 86 return PocketExcelConstants.DEFINED_NAME; 87 } 88 89 /** 90 * Reads a Defined Name from the <code>InputStream</code> The byte array 91 * must be twice the size of the String as it uses unicode. 92 * 93 * @param input InputStream containing the record data 94 */ read(InputStream input)95 public int read(InputStream input) throws IOException { 96 97 int numOfBytesRead = input.read(grbit); 98 cch = (byte) input.read(); 99 numOfBytesRead++; 100 numOfBytesRead += input.read(cce); 101 numOfBytesRead += input.read(ixals); 102 103 rgch = new byte[cch*2]; 104 input.read(rgch, 0, cch*2); 105 106 rgce = new byte[EndianConverter.readShort(cce)]; 107 input.read(rgce, 0, EndianConverter.readShort(cce)); 108 109 110 111 Debug.log(Debug.TRACE, "\tgrbit : "+ EndianConverter.readShort(grbit) + 112 " cch : " + cch + 113 " cce : " + EndianConverter.readShort(cce) + 114 " ixals : " + EndianConverter.readShort(ixals) + 115 "\n\trgch : " + rgch + 116 " rgce : " + rgce); 117 118 return numOfBytesRead; 119 } 120 121 /** 122 * Write this particular <code>BIFFRecord</code> to the <code>OutputStream</code> 123 * 124 * @param output the <code>OutputStream</code> 125 */ write(OutputStream output)126 public void write(OutputStream output) throws IOException { 127 128 try { 129 Debug.log(Debug.TRACE,"Writing out " + definition); 130 rgce = fh.convertCalcToPXL(definition); 131 cce = EndianConverter.writeShort((short) rgce.length); 132 } catch(Exception e) { 133 Debug.log(Debug.TRACE,"Error in Parsing Name Definition"); 134 cce = EndianConverter.writeShort((short) 0); 135 } 136 137 138 output.write(getBiffType()); 139 output.write(grbit); 140 output.write(cch); 141 output.write(cce); 142 output.write(ixals); 143 output.write(rgch); 144 if(rgce.length!=0) 145 output.write(rgce); 146 147 Debug.log(Debug.TRACE,"Writing DefinedName record"); 148 } 149 150 /** 151 * Returns definition name. This is public because the 152 * <code>TokenDecoder</code> has to substitue the Name token with this 153 * String when writing out to sxc 154 * 155 * @return the <code>String</code> containing the name 156 */ getName()157 public String getName() { 158 String name; 159 160 try { 161 name = new String(rgch, "UTF-16LE"); 162 } catch (UnsupportedEncodingException e){ 163 name = "unknown"; 164 } 165 return name; 166 } 167 168 /** 169 * Returns a definition table which can be used by the pocket excel 170 * decoder to build a complete definitions table for writing to the sxc 171 * document 172 */ getNameDefinition()173 public NameDefinition getNameDefinition() { 174 175 String baseCellAddress; 176 getDefinition(); // This must be called first so we know the type 177 178 baseCellAddress = "$" + wb.getSheetName(0) + ".A1"; 179 180 NameDefinition nd = new NameDefinition(getName(),definition, baseCellAddress, isRangeType(), isExpressionType()); 181 return nd; 182 } 183 184 /** 185 * Returns the definition 186 * 187 * @return the <code>String</code> containing the definition 188 */ getDefinition()189 private String getDefinition() { 190 // pexcel sometimes creates Name definition with no defintion, bug?? 191 if(EndianConverter.readShort(cce)!=0) { 192 definition = fh.convertPXLToCalc(rgce); 193 definition = definition.substring(1); // remove the '=' 194 definition = definition.replace(',', ';'); 195 } 196 return definition; 197 } 198 199 /** 200 * Returns the defintion 201 * 202 * @return the <code>String</code> containing the definition 203 */ isRangeType()204 private boolean isRangeType() { 205 206 return fh.isRangeType(); 207 } 208 /** 209 * Returns the defintion 210 * 211 * @return the <code>String</code> containing the definition 212 */ isExpressionType()213 private boolean isExpressionType() { 214 215 return fh.isExpressionType(); 216 } 217 } 218