001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.hssf.record;
019:
020: import org.apache.poi.hssf.util.RKUtil;
021:
022: /**
023: * Title: RK Record
024: * Description: An internal 32 bit number with the two most significant bits
025: * storing the type. This is part of a bizarre scheme to save disk
026: * space and memory (gee look at all the other whole records that
027: * are in the file just "cause"..,far better to waste processor
028: * cycles on this then leave on of those "valuable" records out).<P>
029: * We support this in READ-ONLY mode. HSSF converts these to NUMBER records<P>
030: *
031: *
032: *
033: * REFERENCE: PG 376 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
034: * @author Andrew C. Oliver (acoliver at apache dot org)
035: * @author Jason Height (jheight at chariot dot net dot au)
036: * @version 2.0-pre
037: * @see org.apache.poi.hssf.record.NumberRecord
038: */
039:
040: public class RKRecord extends Record implements
041: CellValueRecordInterface {
042: public final static short sid = 0x27e;
043: public final static short RK_IEEE_NUMBER = 0;
044: public final static short RK_IEEE_NUMBER_TIMES_100 = 1;
045: public final static short RK_INTEGER = 2;
046: public final static short RK_INTEGER_TIMES_100 = 3;
047: //private short field_1_row;
048: private int field_1_row;
049: private short field_2_col;
050: private short field_3_xf_index;
051: private int field_4_rk_number;
052:
053: public RKRecord() {
054: }
055:
056: /**
057: * Constructs a RK record and sets its fields appropriately.
058: * @param in the RecordInputstream to read the record from
059: */
060:
061: public RKRecord(RecordInputStream in) {
062: super (in);
063: }
064:
065: protected void validateSid(short id) {
066: if (id != sid) {
067: throw new RecordFormatException("NOT A valid RK RECORD");
068: }
069: }
070:
071: protected void fillFields(RecordInputStream in) {
072: //field_1_row = LittleEndian.getShort(data, 0 + offset);
073: field_1_row = in.readUShort();
074: field_2_col = in.readShort();
075: field_3_xf_index = in.readShort();
076: field_4_rk_number = in.readInt();
077: }
078:
079: //public short getRow()
080: public int getRow() {
081: return field_1_row;
082: }
083:
084: public short getColumn() {
085: return field_2_col;
086: }
087:
088: public short getXFIndex() {
089: return field_3_xf_index;
090: }
091:
092: public int getRKField() {
093: return field_4_rk_number;
094: }
095:
096: /**
097: * Get the type of the number
098: *
099: * @return one of these values:
100: * <OL START="0">
101: * <LI>RK_IEEE_NUMBER</LI>
102: * <LI>RK_IEEE_NUMBER_TIMES_100</LI>
103: * <LI>RK_INTEGER</LI>
104: * <LI>RK_INTEGER_TIMES_100</LI>
105: * </OL>
106: */
107:
108: public short getRKType() {
109: return (short) (field_4_rk_number & 3);
110: }
111:
112: /**
113: * Extract the value of the number
114: * <P>
115: * The mechanism for determining the value is dependent on the two
116: * low order bits of the raw number. If bit 1 is set, the number
117: * is an integer and can be cast directly as a double, otherwise,
118: * it's apparently the exponent and mantissa of a double (and the
119: * remaining low-order bits of the double's mantissa are 0's).
120: * <P>
121: * If bit 0 is set, the result of the conversion to a double is
122: * divided by 100; otherwise, the value is left alone.
123: * <P>
124: * [insert picture of Screwy Squirrel in full Napoleonic regalia]
125: *
126: * @return the value as a proper double (hey, it <B>could</B>
127: * happen)
128: */
129:
130: public double getRKNumber() {
131: return RKUtil.decodeNumber(field_4_rk_number);
132: }
133:
134: public String toString() {
135: StringBuffer buffer = new StringBuffer();
136:
137: buffer.append("[RK]\n");
138: buffer.append(" .row = ").append(
139: Integer.toHexString(getRow())).append("\n");
140: buffer.append(" .col = ").append(
141: Integer.toHexString(getColumn())).append("\n");
142: buffer.append(" .xfindex = ").append(
143: Integer.toHexString(getXFIndex())).append("\n");
144: buffer.append(" .rknumber = ").append(
145: Integer.toHexString(getRKField())).append("\n");
146: buffer.append(" .rktype = ").append(
147: Integer.toHexString(getRKType())).append("\n");
148: buffer.append(" .rknumber = ").append(getRKNumber())
149: .append("\n");
150: buffer.append("[/RK]\n");
151: return buffer.toString();
152: }
153:
154: //temporarily just constructs a new number record and returns its value
155: public int serialize(int offset, byte[] data) {
156: NumberRecord rec = new NumberRecord();
157:
158: rec.setColumn(getColumn());
159: rec.setRow(getRow());
160: rec.setValue(getRKNumber());
161: rec.setXFIndex(getXFIndex());
162: return rec.serialize(offset, data);
163: }
164:
165: /**
166: * Debugging main()
167: * <P>
168: * Normally I'd do this in a junit test, but let's face it -- once
169: * this algorithm has been tested and it works, we are never ever
170: * going to change it. This is driven by the Faceless Enemy's
171: * minions, who dare not change the algorithm out from under us.
172: *
173: * @param ignored_args command line arguments, which we blithely
174: * ignore
175: */
176:
177: public static void main(String ignored_args[]) {
178: int[] values = { 0x3FF00000, 0x405EC001, 0x02F1853A,
179: 0x02F1853B, 0xFCDD699A };
180: double[] rvalues = { 1, 1.23, 12345678, 123456.78, -13149594 };
181:
182: for (int j = 0; j < values.length; j++) {
183: System.out.println("input = "
184: + Integer.toHexString(values[j]) + " -> "
185: + rvalues[j] + ": "
186: + RKUtil.decodeNumber(values[j]));
187: }
188: }
189:
190: public short getSid() {
191: return sid;
192: }
193:
194: public boolean isBefore(CellValueRecordInterface i) {
195: if (this .getRow() > i.getRow()) {
196: return false;
197: }
198: if ((this .getRow() == i.getRow())
199: && (this .getColumn() > i.getColumn())) {
200: return false;
201: }
202: if ((this .getRow() == i.getRow())
203: && (this .getColumn() == i.getColumn())) {
204: return false;
205: }
206: return true;
207: }
208:
209: public boolean isAfter(CellValueRecordInterface i) {
210: if (this .getRow() < i.getRow()) {
211: return false;
212: }
213: if ((this .getRow() == i.getRow())
214: && (this .getColumn() < i.getColumn())) {
215: return false;
216: }
217: if ((this .getRow() == i.getRow())
218: && (this .getColumn() == i.getColumn())) {
219: return false;
220: }
221: return true;
222: }
223:
224: public boolean isEqual(CellValueRecordInterface i) {
225: return ((this .getRow() == i.getRow()) && (this .getColumn() == i
226: .getColumn()));
227: }
228:
229: public boolean isInValueSection() {
230: return true;
231: }
232:
233: public boolean isValue() {
234: return true;
235: }
236:
237: public void setColumn(short col) {
238: }
239:
240: //public void setRow(short row)
241: public void setRow(int row) {
242: }
243:
244: /**
245: * NO OP!
246: */
247:
248: public void setXFIndex(short xf) {
249: }
250:
251: public Object clone() {
252: RKRecord rec = new RKRecord();
253: rec.field_1_row = field_1_row;
254: rec.field_2_col = field_2_col;
255: rec.field_3_xf_index = field_3_xf_index;
256: rec.field_4_rk_number = field_4_rk_number;
257: return rec;
258: }
259: }
|