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