001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.compress.harmony.pack200; 018 019import java.io.IOException; 020import java.io.OutputStream; 021 022/** 023 * SegmentHeader is the header band of a {@link Segment}. Corresponds to <code>segment_header</code> in the pack200 024 * specification. 025 */ 026public class SegmentHeader extends BandSet { 027 028 /** 029 * Create a new SegmentHeader 030 */ 031 public SegmentHeader() { 032 super(1, null); // Pass 1 for effort because bands in the segment header 033 // should always use the default encoding 034 } 035 036 private static final int[] magic = {0xCA, 0xFE, 0xD0, 0x0D}; 037 private static final int archive_minver = 7; 038 private static final int archive_majver = 150; 039 040 private int archive_options; 041 042 private int cp_Utf8_count; 043 private int cp_Int_count; 044 private int cp_Float_count; 045 private int cp_Long_count; 046 private int cp_Double_count; 047 private int cp_String_count; 048 private int cp_Class_count; 049 private int cp_Signature_count; 050 private int cp_Descr_count; 051 private int cp_Field_count; 052 private int cp_Method_count; 053 private int cp_Imethod_count; 054 055 private int attribute_definition_count; 056 private final IntList band_headers = new IntList(); 057 058 private boolean have_all_code_flags = true; // true by default 059 060 private int archive_size_hi; 061 private int archive_size_lo; 062 private int archive_next_count; 063 private int archive_modtime; 064 private int file_count; 065 066 private boolean deflate_hint; 067 private final boolean have_file_modtime = true; 068 private final boolean have_file_options = true; 069 private boolean have_file_size_hi; 070 private boolean have_class_flags_hi; 071 private boolean have_field_flags_hi; 072 private boolean have_method_flags_hi; 073 private boolean have_code_flags_hi; 074 075 private int ic_count; 076 private int class_count; 077 private final Counter majverCounter = new Counter(); 078 079 /** 080 * Encode and write the SegmentHeader bands to the OutputStream 081 */ 082 @Override 083 public void pack(final OutputStream out) throws IOException, Pack200Exception { 084 out.write(encodeScalar(magic, Codec.BYTE1)); 085 out.write(encodeScalar(archive_minver, Codec.UNSIGNED5)); 086 out.write(encodeScalar(archive_majver, Codec.UNSIGNED5)); 087 calculateArchiveOptions(); 088 out.write(encodeScalar(archive_options, Codec.UNSIGNED5)); 089 writeArchiveFileCounts(out); 090 writeArchiveSpecialCounts(out); 091 writeCpCounts(out); 092 writeClassCounts(out); 093 if (band_headers.size() > 0) { 094 out.write(encodeScalar(band_headers.toArray(), Codec.BYTE1)); 095 } 096 } 097 098 private void calculateArchiveOptions() { 099 if (attribute_definition_count > 0 || band_headers.size() > 0) { 100 archive_options |= 1; 101 } 102 if (cp_Int_count > 0 || cp_Float_count > 0 || cp_Long_count > 0 || cp_Double_count > 0) { 103 archive_options |= (1 << 1); 104 } 105 if (have_all_code_flags) { 106 archive_options |= (1 << 2); 107 } 108 if (file_count > 0) { 109 archive_options |= (1 << 4); 110 } 111 if (deflate_hint) { 112 archive_options |= (1 << 5); 113 } 114 if (have_file_modtime) { 115 archive_options |= (1 << 6); 116 } 117 if (have_file_options) { 118 archive_options |= (1 << 7); 119 } 120 if (have_file_size_hi) { 121 archive_options |= (1 << 8); 122 } 123 if (have_class_flags_hi) { 124 archive_options |= (1 << 9); 125 } 126 if (have_field_flags_hi) { 127 archive_options |= (1 << 10); 128 } 129 if (have_method_flags_hi) { 130 archive_options |= (1 << 11); 131 } 132 if (have_code_flags_hi) { 133 archive_options |= (1 << 12); 134 } 135 } 136 137 public void setCp_Utf8_count(final int count) { 138 cp_Utf8_count = count; 139 } 140 141 public void setCp_Int_count(final int count) { 142 cp_Int_count = count; 143 } 144 145 public void setCp_Float_count(final int count) { 146 cp_Float_count = count; 147 } 148 149 public void setCp_Long_count(final int count) { 150 cp_Long_count = count; 151 } 152 153 public void setCp_Double_count(final int count) { 154 cp_Double_count = count; 155 } 156 157 public void setCp_String_count(final int count) { 158 cp_String_count = count; 159 } 160 161 public void setCp_Class_count(final int count) { 162 cp_Class_count = count; 163 } 164 165 public void setCp_Signature_count(final int count) { 166 cp_Signature_count = count; 167 } 168 169 public void setCp_Descr_count(final int count) { 170 cp_Descr_count = count; 171 } 172 173 public void setCp_Field_count(final int count) { 174 cp_Field_count = count; 175 } 176 177 public void setCp_Method_count(final int count) { 178 cp_Method_count = count; 179 } 180 181 public void setCp_Imethod_count(final int count) { 182 cp_Imethod_count = count; 183 } 184 185 public void setAttribute_definition_count(final int attribute_definition_count) { 186 this.attribute_definition_count = attribute_definition_count; 187 } 188 189 public void setHave_all_code_flags(final boolean have_all_code_flags) { 190 this.have_all_code_flags = have_all_code_flags; 191 } 192 193 public int getArchive_modtime() { 194 return archive_modtime; 195 } 196 197 public void setFile_count(final int file_count) { 198 this.file_count = file_count; 199 } 200 201 public void setDeflate_hint(final boolean deflate_hint) { 202 this.deflate_hint = deflate_hint; 203 } 204 205 public void setHave_class_flags_hi(final boolean have_class_flags_hi) { 206 this.have_class_flags_hi = have_class_flags_hi; 207 } 208 209 public void setHave_field_flags_hi(final boolean have_field_flags_hi) { 210 this.have_field_flags_hi = have_field_flags_hi; 211 } 212 213 public void setHave_method_flags_hi(final boolean have_method_flags_hi) { 214 this.have_method_flags_hi = have_method_flags_hi; 215 } 216 217 public void setHave_code_flags_hi(final boolean have_code_flags_hi) { 218 this.have_code_flags_hi = have_code_flags_hi; 219 } 220 221 public boolean have_class_flags_hi() { 222 return have_class_flags_hi; 223 } 224 225 public boolean have_field_flags_hi() { 226 return have_field_flags_hi; 227 } 228 229 public boolean have_method_flags_hi() { 230 return have_method_flags_hi; 231 } 232 233 public boolean have_code_flags_hi() { 234 return have_code_flags_hi; 235 } 236 237 public void setIc_count(final int ic_count) { 238 this.ic_count = ic_count; 239 } 240 241 public void setClass_count(final int class_count) { 242 this.class_count = class_count; 243 } 244 245 private void writeCpCounts(final OutputStream out) throws IOException, Pack200Exception { 246 out.write(encodeScalar(cp_Utf8_count, Codec.UNSIGNED5)); 247 if ((archive_options & (1 << 1)) != 0) { // have_cp_numbers 248 out.write(encodeScalar(cp_Int_count, Codec.UNSIGNED5)); 249 out.write(encodeScalar(cp_Float_count, Codec.UNSIGNED5)); 250 out.write(encodeScalar(cp_Long_count, Codec.UNSIGNED5)); 251 out.write(encodeScalar(cp_Double_count, Codec.UNSIGNED5)); 252 } 253 out.write(encodeScalar(cp_String_count, Codec.UNSIGNED5)); 254 out.write(encodeScalar(cp_Class_count, Codec.UNSIGNED5)); 255 out.write(encodeScalar(cp_Signature_count, Codec.UNSIGNED5)); 256 out.write(encodeScalar(cp_Descr_count, Codec.UNSIGNED5)); 257 out.write(encodeScalar(cp_Field_count, Codec.UNSIGNED5)); 258 out.write(encodeScalar(cp_Method_count, Codec.UNSIGNED5)); 259 out.write(encodeScalar(cp_Imethod_count, Codec.UNSIGNED5)); 260 } 261 262 private void writeClassCounts(final OutputStream out) throws IOException, Pack200Exception { 263 final int default_class_minver = 0; 264 final int default_class_majver = majverCounter.getMostCommon(); 265 out.write(encodeScalar(ic_count, Codec.UNSIGNED5)); 266 out.write(encodeScalar(default_class_minver, Codec.UNSIGNED5)); 267 out.write(encodeScalar(default_class_majver, Codec.UNSIGNED5)); 268 out.write(encodeScalar(class_count, Codec.UNSIGNED5)); 269 } 270 271 private void writeArchiveSpecialCounts(final OutputStream out) throws IOException, Pack200Exception { 272 if ((archive_options & 1) > 0) { // have_special_formats 273 out.write(encodeScalar(band_headers.size(), Codec.UNSIGNED5)); 274 out.write(encodeScalar(attribute_definition_count, Codec.UNSIGNED5)); 275 } 276 } 277 278 private void writeArchiveFileCounts(final OutputStream out) throws IOException, Pack200Exception { 279 if ((archive_options & (1 << 4)) > 0) { // have_file_headers 280 out.write(encodeScalar(archive_size_hi, Codec.UNSIGNED5)); 281 out.write(encodeScalar(archive_size_lo, Codec.UNSIGNED5)); 282 out.write(encodeScalar(archive_next_count, Codec.UNSIGNED5)); 283 out.write(encodeScalar(archive_modtime, Codec.UNSIGNED5)); 284 out.write(encodeScalar(file_count, Codec.UNSIGNED5)); 285 } 286 } 287 288 public void addMajorVersion(final int major) { 289 majverCounter.add(major); 290 } 291 292 /** 293 * Counter for major/minor class file numbers so we can work out the default 294 */ 295 private class Counter { 296 297 private final int[] objs = new int[8]; 298 private final int[] counts = new int[8]; 299 private int length; 300 301 public void add(final int obj) { 302 boolean found = false; 303 for (int i = 0; i < length; i++) { 304 if (objs[i] == obj) { 305 counts[i]++; 306 found = true; 307 } 308 } 309 if (!found) { 310 objs[length] = obj; 311 counts[length] = 1; 312 length++; 313 if (length > objs.length - 1) { 314 final Object[] newArray = new Object[objs.length + 8]; 315 System.arraycopy(objs, 0, newArray, 0, length); 316 } 317 } 318 } 319 320 public int getMostCommon() { 321 int returnIndex = 0; 322 for (int i = 0; i < length; i++) { 323 if (counts[i] > counts[returnIndex]) { 324 returnIndex = i; 325 } 326 } 327 return objs[returnIndex]; 328 } 329 } 330 331 public int getDefaultMajorVersion() { 332 return majverCounter.getMostCommon(); 333 } 334 335 public boolean have_file_size_hi() { 336 return have_file_size_hi; 337 } 338 339 public boolean have_file_modtime() { 340 return have_file_modtime; 341 } 342 343 public boolean have_file_options() { 344 return have_file_options; 345 } 346 347 public boolean have_all_code_flags() { 348 return have_all_code_flags; 349 } 350 351 public void appendBandCodingSpecifier(final int specifier) { 352 band_headers.add(specifier); 353 } 354 355}