Source code: com/jguild/jrpm/io/Header.java
1 /*
2 * jGuild Project: jRPM
3 * Released under the Apache License ( http://www.apache.org/LICENSE )
4 */
5 package com.jguild.jrpm.io;
6
7 import com.jguild.jrpm.io.datatype.*;
8
9 import org.apache.log4j.Logger;
10
11 import java.io.DataInputStream;
12 import java.io.IOException;
13
14 import java.util.Comparator;
15 import java.util.HashMap;
16 import java.util.TreeSet;
17
18
19 /**
20 * This class represents the abstract definition of a header structur.
21 * It can be either a signature or a header. The tags of such a structure
22 * can be accessed by either their tag id or by their tag name.
23 * Also all available and all read tag names in this structure can be accessed.
24 *
25 * @author kuss
26 * @version $Id: Header.java,v 1.8 2003/10/20 16:32:11 mkuss Exp $
27 **/
28 public abstract class Header {
29 private static final int HEADER_LENGTH = 16;
30 private static final Logger logger = Logger.getLogger(Header.class);
31 protected long size;
32 private HashMap store = new HashMap();
33 private IndexEntry[] indexes;
34 private int version;
35 private long indexDataSize;
36 private long indexNumber;
37
38 /**
39 * Construct a header structure for the given input stream.
40 * The header structure of a signature or a header can be read and
41 * also the index entries containig the tags for this rpm section
42 * (signature or header).
43 * First a header is read consisting of the following fields:
44 * <code><pre>
45 * byte magic[3]; (3 byte) (8e ad e8)
46 * int version; (1 byte)
47 * byte reserved[4]; (4 byte)
48 * long num_index; (4 byte)
49 * long num_data; (4 byte)
50 * </pre></code>
51 * Afterwareds the index entries are read and then the tags and the
52 * correspondig data entries are read.
53 *
54 * @param inputStream An inputstream containing rpm file informations
55 * @throws IOException if an error occurs on reading informations
56 * out of the stream
57 */
58 public Header(DataInputStream inputStream) throws IOException {
59 if (logger.isDebugEnabled()) {
60 logger.debug("Start Reading Header");
61 }
62
63 // Read header
64 size = HEADER_LENGTH;
65
66 check(inputStream.readUnsignedByte() == 0x8E);
67 check(inputStream.readUnsignedByte() == 0xAD);
68 check(inputStream.readUnsignedByte() == 0xE8);
69 version = inputStream.readUnsignedByte();
70
71 if (logger.isDebugEnabled()) {
72 logger.debug("version: " + version);
73 }
74
75 // skip reserved bytes
76 inputStream.skipBytes(4);
77 indexNumber = (long) inputStream.readInt();
78
79 if (logger.isDebugEnabled()) {
80 logger.debug("indexes available: " + indexNumber);
81 }
82
83 indexDataSize = (long) inputStream.readInt();
84
85 if (logger.isDebugEnabled()) {
86 logger.debug("index data size: " + indexDataSize);
87 }
88
89 // Read indexes
90 // make sure to sort them in order of offset to
91 // be able to read the store without jumping arround in
92 // the file
93 TreeSet _indexes = new TreeSet(new Comparator() {
94 public int compare(Object o1, Object o2) {
95 return (int) (((IndexEntry) o1).getOffset() - ((IndexEntry) o2).getOffset());
96 }
97
98 public boolean equals(Object o) {
99 return false;
100 }
101 });
102
103 for (int i = 0; i < indexNumber; i++) {
104 IndexEntry index = new IndexEntry(inputStream);
105
106 _indexes.add(index);
107 size += index.getSize();
108 }
109
110 indexes = new IndexEntry[0];
111 indexes = (IndexEntry[]) _indexes.toArray(indexes);
112
113 // Read store
114 for (int i = 0; i < indexes.length; i++) {
115 IndexEntry index = indexes[i];
116
117 // if (index.getType().equals(RPMIndexType.STRING_ARRAY) || index.getType().equals(RPMIndexType.STRING) ||
118 // index.getType().equals(RPMIndexType.I18NSTRING)) {
119 // if (i < (indexes.length - 1)) {
120 // IndexEntry next = indexes[i + 1];
121 //
122 // length = next.getOffset() - index.getOffset();
123 // } else {
124 // length = indexDataSize - index.getOffset();
125 // }
126 //
127 // // and initialize temporary space for data
128 // stringData = new byte[(int) length];
129 //
130 // // and read it from stream
131 // inputStream.readFully(stringData);
132 // }
133 DataTypeIf dataObject = null;
134
135 if (logger.isDebugEnabled()) {
136 logger.debug("Reading for tag '" + getTagNameForId(index.getTag()) + "' '" + index.getCount() + "' entries of type '" +
137 index.getType().getName() + "'");
138 }
139
140 dataObject = TypeFactory.createFromStream(inputStream, index,
141 (i < (indexes.length - 1)) ? (indexes[i + 1].getOffset() - index.getOffset()) : (indexDataSize - index.getOffset()));
142
143 // adjust size
144 size += dataObject.getSize();
145
146 store.put(new Long(index.getTag()), dataObject);
147 }
148
149 if (logger.isDebugEnabled()) {
150 logger.debug("");
151 }
152
153 if (logger.isDebugEnabled()) {
154 logger.debug("Finished Reading Header");
155 }
156 }
157
158 /**
159 * Read all known tag names for this header structure.
160 *
161 * @return An array of tag names
162 */
163 public static String[] getKnownTagNames() {
164 return new String[0];
165 }
166
167 /**
168 * Get the size in bytes of this structure
169 *
170 * @return The size in bytes.
171 */
172 public long getSize() {
173 return size;
174 }
175
176 /**
177 * Get a tag by id as a Long
178 *
179 * @param tag A tag id as a Long
180 * @return A data struct containing the data of this tag
181 */
182 public DataTypeIf getTag(Long tag) {
183 return (DataTypeIf) store.get(tag);
184 }
185
186 /**
187 * Get a tag by id as a long
188 *
189 * @param tag A tag id as a long
190 * @return A data struct containing the data of this tag
191 */
192 public DataTypeIf getTag(long tag) {
193 return getTag(new Long(tag));
194 }
195
196 /**
197 * Get a tag by name
198 *
199 * @param tagname A tag name
200 * @return A data struct containing the data of this tag
201 */
202 public DataTypeIf getTag(String tagname) {
203 return getTag(getTagIdForName(tagname));
204 }
205
206 /**
207 * Read a tag with a given tag name. The tag will be read out of the
208 * class defined in getTagEnum().
209 *
210 * @param tagname A RPM tag name
211 * @return The id of the RPM tag
212 * @throws IllegalArgumentException if the tag name was not found
213 */
214 public abstract long getTagIdForName(String tagname);
215
216 /**
217 * Get all tag ids contained in this rpm file.
218 *
219 * @return All tag ids contained in this rpm file.
220 */
221 public long[] getTagIds() {
222 Long[] tmp = (Long[]) store.keySet().toArray(new Long[0]);
223 long[] ret = new long[tmp.length];
224
225 for (int i = 0; i < tmp.length; i++) {
226 ret[i] = tmp[i].longValue();
227 }
228
229 return ret;
230 }
231
232 /**
233 * Read a tag with a given tag id. The tag will be read out of the
234 * class defined in getTagEnum().
235 *
236 * @param tagid A RPM tag id
237 * @return The name of the RPM tag
238 * @throws IllegalArgumentException if the tag id was not found
239 */
240 public abstract String getTagNameForId(long tagid);
241
242 /**
243 * Get all tag names contained in this rpm file.
244 *
245 * @return All tag names contained in this rpm file.
246 */
247 public String[] getTagNames() {
248 Long[] tmp = (Long[]) store.keySet().toArray(new Long[0]);
249 String[] ret = new String[tmp.length];
250
251 for (int i = 0; i < tmp.length; i++) {
252 ret[i] = getTagNameForId(tmp[i].longValue());
253 }
254
255 return ret;
256 }
257
258 /**
259 * Asserts a boolean value and throws an exception if it
260 * is false
261 * @param test A boolean test variable
262 * @throws IOException if the variable test is false
263 */
264 private static final void check(boolean test)
265 throws IOException {
266 if (!test) {
267 throw new IOException("Corrupted archive");
268 }
269 }
270 }