View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one or more
3    *  contributor license agreements.  See the NOTICE file distributed with
4    *  this work for additional information regarding copyright ownership.
5    *  The ASF licenses this file to You under the Apache License, Version 2.0
6    *  (the "License"); you may not use this file except in compliance with
7    *  the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.commons.compress.harmony.pack200;
18  
19  import java.io.IOException;
20  import java.io.OutputStream;
21  
22  /**
23   * SegmentHeader is the header band of a {@link Segment}. Corresponds to {@code segment_header} in the pack200 specification.
24   */
25  public class SegmentHeader extends BandSet {
26  
27      /**
28       * Counter for major/minor class file numbers, so we can work out the default
29       */
30      private static final class Counter {
31  
32          private final int[] objs = new int[8];
33          private final int[] counts = new int[8];
34          private int length;
35  
36          public void add(final int obj) {
37              boolean found = false;
38              for (int i = 0; i < length; i++) {
39                  if (objs[i] == obj) {
40                      counts[i]++;
41                      found = true;
42                  }
43              }
44              if (!found) {
45                  objs[length] = obj;
46                  counts[length] = 1;
47                  length++;
48                  if (length > objs.length - 1) {
49                      final Object[] newArray = new Object[objs.length + 8];
50                      System.arraycopy(objs, 0, newArray, 0, length);
51                  }
52              }
53          }
54  
55          public int getMostCommon() {
56              int returnIndex = 0;
57              for (int i = 0; i < length; i++) {
58                  if (counts[i] > counts[returnIndex]) {
59                      returnIndex = i;
60                  }
61              }
62              return objs[returnIndex];
63          }
64      }
65  
66      private static final int[] magic = { 0xCA, 0xFE, 0xD0, 0x0D };
67      private static final int archive_minver = 7;
68      private static final int archive_majver = 150;
69  
70      private int archive_options;
71  
72      private int cp_Utf8_count;
73      private int cp_Int_count;
74      private int cp_Float_count;
75      private int cp_Long_count;
76      private int cp_Double_count;
77      private int cp_String_count;
78      private int cp_Class_count;
79      private int cp_Signature_count;
80      private int cp_Descr_count;
81      private int cp_Field_count;
82      private int cp_Method_count;
83      private int cp_Imethod_count;
84  
85      private int attribute_definition_count;
86      private final IntList band_headers = new IntList();
87  
88      private boolean have_all_code_flags = true; // true by default
89  
90      private int archive_size_hi;
91      private int archive_size_lo;
92      private int archive_next_count;
93      private int archive_modtime;
94      private int file_count;
95  
96      private boolean deflate_hint;
97      private final boolean have_file_modtime = true;
98      private final boolean have_file_options = true;
99      private boolean have_file_size_hi;
100     private boolean have_class_flags_hi;
101     private boolean have_field_flags_hi;
102     private boolean have_method_flags_hi;
103     private boolean have_code_flags_hi;
104 
105     private int ic_count;
106     private int class_count;
107     private final Counter majverCounter = new Counter();
108 
109     /**
110      * Constructs a new SegmentHeader
111      */
112     public SegmentHeader() {
113         super(1, null); // Pass 1 for effort because bands in the segment header
114                         // should always use the default encoding
115     }
116 
117     public void addMajorVersion(final int major) {
118         majverCounter.add(major);
119     }
120 
121     public void appendBandCodingSpecifier(final int specifier) {
122         band_headers.add(specifier);
123     }
124 
125     private void calculateArchiveOptions() {
126         if (attribute_definition_count > 0 || band_headers.size() > 0) {
127             archive_options |= 1;
128         }
129         if (cp_Int_count > 0 || cp_Float_count > 0 || cp_Long_count > 0 || cp_Double_count > 0) {
130             archive_options |= 1 << 1;
131         }
132         if (have_all_code_flags) {
133             archive_options |= 1 << 2;
134         }
135         if (file_count > 0) {
136             archive_options |= 1 << 4;
137         }
138         if (deflate_hint) {
139             archive_options |= 1 << 5;
140         }
141         if (have_file_modtime) {
142             archive_options |= 1 << 6;
143         }
144         if (have_file_options) {
145             archive_options |= 1 << 7;
146         }
147         if (have_file_size_hi) {
148             archive_options |= 1 << 8;
149         }
150         if (have_class_flags_hi) {
151             archive_options |= 1 << 9;
152         }
153         if (have_field_flags_hi) {
154             archive_options |= 1 << 10;
155         }
156         if (have_method_flags_hi) {
157             archive_options |= 1 << 11;
158         }
159         if (have_code_flags_hi) {
160             archive_options |= 1 << 12;
161         }
162     }
163 
164     public int getArchive_modtime() {
165         return archive_modtime;
166     }
167 
168     public int getDefaultMajorVersion() {
169         return majverCounter.getMostCommon();
170     }
171 
172     public boolean have_all_code_flags() {
173         return have_all_code_flags;
174     }
175 
176     public boolean have_class_flags_hi() {
177         return have_class_flags_hi;
178     }
179 
180     public boolean have_code_flags_hi() {
181         return have_code_flags_hi;
182     }
183 
184     public boolean have_field_flags_hi() {
185         return have_field_flags_hi;
186     }
187 
188     public boolean have_file_modtime() {
189         return have_file_modtime;
190     }
191 
192     public boolean have_file_options() {
193         return have_file_options;
194     }
195 
196     public boolean have_file_size_hi() {
197         return have_file_size_hi;
198     }
199 
200     public boolean have_method_flags_hi() {
201         return have_method_flags_hi;
202     }
203 
204     /**
205      * Encode and write the SegmentHeader bands to the OutputStream
206      */
207     @Override
208     public void pack(final OutputStream out) throws IOException, Pack200Exception {
209         out.write(encodeScalar(magic, Codec.BYTE1));
210         out.write(encodeScalar(archive_minver, Codec.UNSIGNED5));
211         out.write(encodeScalar(archive_majver, Codec.UNSIGNED5));
212         calculateArchiveOptions();
213         out.write(encodeScalar(archive_options, Codec.UNSIGNED5));
214         writeArchiveFileCounts(out);
215         writeArchiveSpecialCounts(out);
216         writeCpCounts(out);
217         writeClassCounts(out);
218         if (band_headers.size() > 0) {
219             out.write(encodeScalar(band_headers.toArray(), Codec.BYTE1));
220         }
221     }
222 
223     public void setAttribute_definition_count(final int attribute_definition_count) {
224         this.attribute_definition_count = attribute_definition_count;
225     }
226 
227     public void setClass_count(final int class_count) {
228         this.class_count = class_count;
229     }
230 
231     public void setCp_Class_count(final int count) {
232         cp_Class_count = count;
233     }
234 
235     public void setCp_Descr_count(final int count) {
236         cp_Descr_count = count;
237     }
238 
239     public void setCp_Double_count(final int count) {
240         cp_Double_count = count;
241     }
242 
243     public void setCp_Field_count(final int count) {
244         cp_Field_count = count;
245     }
246 
247     public void setCp_Float_count(final int count) {
248         cp_Float_count = count;
249     }
250 
251     public void setCp_Imethod_count(final int count) {
252         cp_Imethod_count = count;
253     }
254 
255     public void setCp_Int_count(final int count) {
256         cp_Int_count = count;
257     }
258 
259     public void setCp_Long_count(final int count) {
260         cp_Long_count = count;
261     }
262 
263     public void setCp_Method_count(final int count) {
264         cp_Method_count = count;
265     }
266 
267     public void setCp_Signature_count(final int count) {
268         cp_Signature_count = count;
269     }
270 
271     public void setCp_String_count(final int count) {
272         cp_String_count = count;
273     }
274 
275     public void setCp_Utf8_count(final int count) {
276         cp_Utf8_count = count;
277     }
278 
279     public void setDeflate_hint(final boolean deflate_hint) {
280         this.deflate_hint = deflate_hint;
281     }
282 
283     public void setFile_count(final int file_count) {
284         this.file_count = file_count;
285     }
286 
287     public void setHave_all_code_flags(final boolean have_all_code_flags) {
288         this.have_all_code_flags = have_all_code_flags;
289     }
290 
291     public void setHave_class_flags_hi(final boolean have_class_flags_hi) {
292         this.have_class_flags_hi = have_class_flags_hi;
293     }
294 
295     public void setHave_code_flags_hi(final boolean have_code_flags_hi) {
296         this.have_code_flags_hi = have_code_flags_hi;
297     }
298 
299     public void setHave_field_flags_hi(final boolean have_field_flags_hi) {
300         this.have_field_flags_hi = have_field_flags_hi;
301     }
302 
303     public void setHave_method_flags_hi(final boolean have_method_flags_hi) {
304         this.have_method_flags_hi = have_method_flags_hi;
305     }
306 
307     public void setIc_count(final int ic_count) {
308         this.ic_count = ic_count;
309     }
310 
311     private void writeArchiveFileCounts(final OutputStream out) throws IOException, Pack200Exception {
312         if ((archive_options & 1 << 4) > 0) { // have_file_headers
313             out.write(encodeScalar(archive_size_hi, Codec.UNSIGNED5));
314             out.write(encodeScalar(archive_size_lo, Codec.UNSIGNED5));
315             out.write(encodeScalar(archive_next_count, Codec.UNSIGNED5));
316             out.write(encodeScalar(archive_modtime, Codec.UNSIGNED5));
317             out.write(encodeScalar(file_count, Codec.UNSIGNED5));
318         }
319     }
320 
321     private void writeArchiveSpecialCounts(final OutputStream out) throws IOException, Pack200Exception {
322         if ((archive_options & 1) > 0) { // have_special_formats
323             out.write(encodeScalar(band_headers.size(), Codec.UNSIGNED5));
324             out.write(encodeScalar(attribute_definition_count, Codec.UNSIGNED5));
325         }
326     }
327 
328     private void writeClassCounts(final OutputStream out) throws IOException, Pack200Exception {
329         final int default_class_minver = 0;
330         final int default_class_majver = majverCounter.getMostCommon();
331         out.write(encodeScalar(ic_count, Codec.UNSIGNED5));
332         out.write(encodeScalar(default_class_minver, Codec.UNSIGNED5));
333         out.write(encodeScalar(default_class_majver, Codec.UNSIGNED5));
334         out.write(encodeScalar(class_count, Codec.UNSIGNED5));
335     }
336 
337     private void writeCpCounts(final OutputStream out) throws IOException, Pack200Exception {
338         out.write(encodeScalar(cp_Utf8_count, Codec.UNSIGNED5));
339         if ((archive_options & 1 << 1) != 0) { // have_cp_numbers
340             out.write(encodeScalar(cp_Int_count, Codec.UNSIGNED5));
341             out.write(encodeScalar(cp_Float_count, Codec.UNSIGNED5));
342             out.write(encodeScalar(cp_Long_count, Codec.UNSIGNED5));
343             out.write(encodeScalar(cp_Double_count, Codec.UNSIGNED5));
344         }
345         out.write(encodeScalar(cp_String_count, Codec.UNSIGNED5));
346         out.write(encodeScalar(cp_Class_count, Codec.UNSIGNED5));
347         out.write(encodeScalar(cp_Signature_count, Codec.UNSIGNED5));
348         out.write(encodeScalar(cp_Descr_count, Codec.UNSIGNED5));
349         out.write(encodeScalar(cp_Field_count, Codec.UNSIGNED5));
350         out.write(encodeScalar(cp_Method_count, Codec.UNSIGNED5));
351         out.write(encodeScalar(cp_Imethod_count, Codec.UNSIGNED5));
352     }
353 
354 }