View Javadoc

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 java.io.DataInputStream;
8   import java.io.IOException;
9   import java.util.Comparator;
10  import java.util.HashMap;
11  import java.util.TreeSet;
12  
13  import org.apache.log4j.Logger;
14  
15  import com.jguild.jrpm.io.datatype.DataTypeIf;
16  import com.jguild.jrpm.io.datatype.TypeFactory;
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.10 2004/09/09 09:52:33 pnasrat 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      private HashMap store = new HashMap();
32      private IndexEntry[] indexes;
33      private int version;
34      private long indexDataSize;
35      private long indexNumber;
36      private boolean rawHeader = false;
37      /*** The size in bytes of this structure */
38      protected long size;
39  
40      /***
41       * 
42       * Create a header structure from an input stream.
43       * 
44       * The header structure of a signature or a header can be read and
45       * also the index entries containing the tags for this rpm section
46       * (signature or header).
47       * 
48       * Unless we have a raw header from headerUnload or the database, 
49       * a header is read consisting of the following fields:
50       * <code><pre>
51       * byte magic[3];      (3  byte)  (8e ad e8)
52       * int version;        (1  byte)
53       * byte reserved[4];   (4  byte)
54       * long num_index;     (4  byte)
55       * long num_data;      (4  byte)
56       * </pre></code> 
57       * 
58       * Afterwards the index entries are read and then the tags and the
59       * correspondig data entries are read.
60       *
61       * @param inputStream An inputstream containing rpm file informations
62       * @param rawHeader Are we a raw header (from headerUnload or rpmdb)
63       * @throws IOException if an error occurs on reading informations
64       * out of the stream
65       */
66      public Header(DataInputStream inputStream, boolean rawHeader) throws IOException {
67          if (logger.isDebugEnabled()) {
68              logger.debug("Start Reading Header");
69          }
70  
71          if (!rawHeader) {
72          	// Read header
73          	size = HEADER_LENGTH;
74          	
75          	check(inputStream.readUnsignedByte() == 0x8E);
76          	check(inputStream.readUnsignedByte() == 0xAD);
77          	check(inputStream.readUnsignedByte() == 0xE8);
78          	version = inputStream.readUnsignedByte();
79          	
80          	if (logger.isDebugEnabled()) {
81          		logger.debug("version: " + version);
82          	}
83          	
84          	// skip reserved bytes
85          	inputStream.skipBytes(4);
86          }
87          
88          indexNumber = inputStream.readInt();
89  
90          if (logger.isDebugEnabled()) {
91              logger.debug("indexes available: " + indexNumber);
92          }
93  
94          indexDataSize = inputStream.readInt();
95  
96          if (logger.isDebugEnabled()) {
97              logger.debug("index data size: " + indexDataSize);
98          }
99  
100         // Read indexes
101         // make sure to sort them in order of offset to
102         // be able to read the store without jumping arround in
103         // the file
104         TreeSet _indexes = new TreeSet(new Comparator() {
105                     public int compare(Object o1, Object o2) {
106                         return (int) (((IndexEntry) o1).getOffset() - ((IndexEntry) o2).getOffset());
107                     }
108 
109                     public boolean equals(Object o) {
110                         return false;
111                     }
112                 });
113 
114         for (int i = 0; i < indexNumber; i++) {
115             IndexEntry index = new IndexEntry(inputStream);
116 
117             _indexes.add(index);
118             size += index.getSize();
119         }
120 
121         indexes = new IndexEntry[0];
122         indexes = (IndexEntry[]) _indexes.toArray(indexes);
123 
124         // Read store
125         for (int i = 0; i < indexes.length; i++) {
126             IndexEntry index = indexes[i];
127 
128             //            if (index.getType().equals(RPMIndexType.STRING_ARRAY) || index.getType().equals(RPMIndexType.STRING) ||
129             //                    index.getType().equals(RPMIndexType.I18NSTRING)) {
130             //                if (i < (indexes.length - 1)) {
131             //                    IndexEntry next = indexes[i + 1];
132             //
133             //                    length = next.getOffset() - index.getOffset();
134             //                } else {
135             //                    length = indexDataSize - index.getOffset();
136             //                }
137             //
138             //                // and initialize temporary space for data
139             //                stringData = new byte[(int) length];
140             //
141             //                // and read it from stream
142             //                inputStream.readFully(stringData);
143             //            }
144             DataTypeIf dataObject = null;
145 
146             if (logger.isDebugEnabled()) {
147                 logger.debug("Reading for tag '" + getTagNameForId(index.getTag()) + "' '" + index.getCount() + "' entries of type '" +
148                     index.getType().getName() + "'");
149             }
150 
151             dataObject = TypeFactory.createFromStream(inputStream, index,
152                     (i < (indexes.length - 1)) ? (indexes[i + 1].getOffset() - index.getOffset()) : (indexDataSize - index.getOffset()));
153 
154             // adjust size
155             size += dataObject.getSize();
156 
157             store.put(new Long(index.getTag()), dataObject);
158         }
159 
160         if (logger.isDebugEnabled()) {
161             logger.debug("");
162         }
163 
164         if (logger.isDebugEnabled()) {
165             logger.debug("Finished Reading Header");
166         }
167     }
168     
169     /***
170      * Construct a header structure for the given input stream.
171      * @param inputStream
172      * @throws IOException
173      */
174     public Header(DataInputStream inputStream) throws IOException {
175     	this(inputStream, false);
176     }
177 
178     /***
179      * Read all known tag names for this header structure.
180      *
181      * @return An array of tag names
182      */
183     public static String[] getKnownTagNames() {
184         return new String[0];
185     }
186 
187     /***
188      * Get the size in bytes of this structure
189      *
190      * @return The size in bytes.
191      */
192     public long getSize() {
193         return size;
194     }
195 
196     /***
197      * Get a tag by id as a Long
198      *
199      * @param tag A tag id as a Long
200      * @return A data struct containing the data of this tag
201      */
202     public DataTypeIf getTag(Long tag) {
203         return (DataTypeIf) store.get(tag);
204     }
205 
206     /***
207      * Get a tag by id as a long
208      *
209      * @param tag A tag id as a long
210      * @return A data struct containing the data of this tag
211      */
212     public DataTypeIf getTag(long tag) {
213         return getTag(new Long(tag));
214     }
215 
216     /***
217      * Get a tag by name
218      *
219      * @param tagname A tag name
220      * @return A data struct containing the data of this tag
221      */
222     public DataTypeIf getTag(String tagname) {
223         return getTag(getTagIdForName(tagname));
224     }
225     
226     /***
227      * Set a tag by id as a Long 
228      * 
229      * @param tag A tag id as a Long
230      * @param data A data struct containing the data of this tag
231      */
232     public void setTag(Long tag, DataTypeIf data) {
233         isValidTag(tag.longValue());
234         store.put(tag, data);
235     }
236     
237     /***
238      * Set a tag by id as a long
239      * 
240      * @param tag A tag id as a long
241      * @param data A data struct containing the data of this tag
242      */
243     public void setTag(long tag, DataTypeIf data) {
244         setTag(new Long(tag), data);
245     }
246 
247     /***
248      * Set a tag by id as a string
249      * 
250      * @param tagname A tag id as a string
251      * @param data A data struct containing the data of this tag
252      */
253     public void setTag(String tagname, DataTypeIf data) {
254         setTag(getTagIdForName(tagname), data);
255     }
256 
257     /***
258      * Get all tag ids contained in this rpm file.
259      *
260      * @return All tag ids contained in this rpm file.
261      */
262     public long[] getTagIds() {
263         Long[] tmp = (Long[]) store.keySet().toArray(new Long[0]);
264         long[] ret = new long[tmp.length];
265 
266         for (int i = 0; i < tmp.length; i++) {
267             ret[i] = tmp[i].longValue();
268         }
269 
270         return ret;
271     }
272 
273     /***
274      * Get all tag names contained in this rpm file.
275      *
276      * @return All tag names contained in this rpm file.
277      */
278     public String[] getTagNames() {
279         Long[] tmp = (Long[]) store.keySet().toArray(new Long[0]);
280         String[] ret = new String[tmp.length];
281 
282         for (int i = 0; i < tmp.length; i++) {
283             ret[i] = getTagNameForId(tmp[i].longValue());
284         }
285 
286         return ret;
287     }
288 
289     /***
290      * Asserts a boolean value and throws an exception if it
291      * is false
292      * @param test A boolean test variable
293      * @throws IOException if the variable test is false
294      */
295     private static final void check(boolean test)
296         throws IOException {
297         if (!test) {
298             throw new IOException("Corrupted archive");
299         }
300     }
301 
302     /***
303      * Read a tag with a given tag name. The tag will be read out of the
304      * class defined in getTagEnum().
305      *
306      * @param tagname A RPM tag name
307      * @return The id of the RPM tag
308      * @throws IllegalArgumentException if the tag name was not found
309      */
310     public abstract long getTagIdForName(String tagname);
311     
312     /***
313      * Read a tag with a given tag id. The tag will be read out of the
314      * class defined in getTagEnum().
315      *
316      * @param tagid A RPM tag id
317      * @return The name of the RPM tag
318      * @throws IllegalArgumentException if the tag id was not found
319      */
320     public abstract String getTagNameForId(long tagid);
321 
322     /***
323      * Test if the given tagid is associated with a valid tag
324      * 
325      * @param tagid The id of a tag
326      * @return TRUE if the tagid is valid
327      */
328     public abstract boolean isValidTag(long tagid);
329 
330     /***
331      * Test if the given tagname is associated with a valid tag
332      * 
333      * @param tagname The name of a tag
334      * @return TRUE if the tagname is valid
335      */
336     public abstract boolean isValidTag(String tagname);    
337 }