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