1
2 /* ====================================================================
3 Licensed to the Apache Software Foundation (ASF) under one or more
4 contributor license agreements. See the NOTICE file distributed with
5 this work for additional information regarding copyright ownership.
6 The ASF licenses this file to You under the Apache License, Version 2.0
7 (the "License"); you may not use this file except in compliance with
8 the License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================== */
18
19
20 package org.apache.poi.hssf.record;
21
22 import java.io.ByteArrayInputStream;
23
24 /**
25 * Title: Record
26 * Description: All HSSF Records inherit from this class. It
27 * populates the fields common to all records (id, size and data).
28 * Subclasses should be sure to validate the id,
29 * Company:
30 * @author Andrew C. Oliver
31 * @author Marc Johnson (mjohnson at apache dot org)
32 * @author Jason Height (jheight at chariot dot net dot au)
33 * @version 2.0-pre
34 */
35
36 public abstract class Record
37 {
38
39 /**
40 * instantiates a blank record strictly for ID matching
41 */
42
43 public Record()
44 {
45 }
46
47 /**
48 * Constructor Record
49 *
50 * @param in the RecordInputstream to read the record from
51 */
52 public Record(RecordInputStream in)
53 {
54 validateSid(in.getSid());
55 fillFields(in);
56 }
57
58 /**
59 * called by constructor, should throw runtime exception in the event of a
60 * record passed with a differing ID.
61 *
62 * @param id alleged id for this record
63 */
64
65 protected abstract void validateSid(short id);
66
67 /**
68 * called by the constructor, should set class level fields. Should throw
69 * runtime exception for bad/icomplete data.
70 *
71 * @param in the RecordInputstream to read the record from
72 */
73
74 protected abstract void fillFields(RecordInputStream in);
75
76 /**
77 * called by the class that is responsible for writing this sucker.
78 * Subclasses should implement this so that their data is passed back in a
79 * byte array.
80 *
81 * @return byte array containing instance data
82 */
83
84 public byte [] serialize()
85 {
86 byte[] retval = new byte[ getRecordSize() ];
87
88 serialize(0, retval);
89 return retval;
90 }
91
92 /**
93 * called by the class that is responsible for writing this sucker.
94 * Subclasses should implement this so that their data is passed back in a
95 * byte array.
96 *
97 * @param offset to begin writing at
98 * @param data byte array containing instance data
99 * @return number of bytes written
100 */
101
102 public abstract int serialize(int offset, byte [] data);
103
104 /**
105 * gives the current serialized size of the record. Should include the sid and reclength (4 bytes).
106 */
107
108 public int getRecordSize()
109 {
110
111 // this is kind od a stupid way to do it but for now we just serialize
112 // the record and return the size of the byte array
113 return serialize().length;
114 }
115
116 /**
117 * tells whether this type of record contains a value
118 */
119
120 public boolean isValue()
121 {
122 return false;
123 }
124
125 /**
126 * DBCELL, ROW, VALUES all say yes
127 */
128
129 public boolean isInValueSection()
130 {
131 return false;
132 }
133
134 /**
135 * get a string representation of the record (for biffview/debugging)
136 */
137
138 public String toString()
139 {
140 return super.toString();
141 }
142
143 /**
144 * return the non static version of the id for this record.
145 */
146
147 public abstract short getSid();
148
149 public Object clone() {
150 throw new RuntimeException("The class "+getClass().getName()+" needs to define a clone method");
151 }
152
153 /**
154 * Clone the current record, via a call to serialise
155 * it, and another to create a new record from the
156 * bytes.
157 * May only be used for classes which don't have
158 * internal counts / ids in them. For those which
159 * do, a full record-aware serialise is needed, which
160 * allocates new ids / counts as needed.
161 */
162 public Record cloneViaReserialise()
163 {
164 // Do it via a re-serialise
165 // It's a cheat, but it works...
166 byte[] b = serialize();
167 RecordInputStream rinp = new RecordInputStream(
168 new ByteArrayInputStream(b)
169 );
170 rinp.nextRecord();
171
172 Record[] r = RecordFactory.createRecord(rinp);
173 if(r.length != 1) {
174 throw new IllegalStateException("Re-serialised a record to clone it, but got " + r.length + " records back!");
175 }
176 return r[0];
177 }
178 }