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 specification. 024 */ 025public class SegmentHeader extends BandSet { 026 027 /** 028 * Counter for major/minor class file numbers, so we can work out the default 029 */ 030 private static final class Counter { 031 032 private final int[] objs = new int[8]; 033 private final int[] counts = new int[8]; 034 private int length; 035 036 public void add(final int obj) { 037 boolean found = false; 038 for (int i = 0; i < length; i++) { 039 if (objs[i] == obj) { 040 counts[i]++; 041 found = true; 042 } 043 } 044 if (!found) { 045 objs[length] = obj; 046 counts[length] = 1; 047 length++; 048 if (length > objs.length - 1) { 049 final Object[] newArray = new Object[objs.length + 8]; 050 System.arraycopy(objs, 0, newArray, 0, length); 051 } 052 } 053 } 054 055 public int getMostCommon() { 056 int returnIndex = 0; 057 for (int i = 0; i < length; i++) { 058 if (counts[i] > counts[returnIndex]) { 059 returnIndex = i; 060 } 061 } 062 return objs[returnIndex]; 063 } 064 } 065 066 private static final int[] magic = { 0xCA, 0xFE, 0xD0, 0x0D }; 067 private static final int archive_minver = 7; 068 private static final int archive_majver = 150; 069 070 private int archive_options; 071 072 private int cp_Utf8_count; 073 private int cp_Int_count; 074 private int cp_Float_count; 075 private int cp_Long_count; 076 private int cp_Double_count; 077 private int cp_String_count; 078 private int cp_Class_count; 079 private int cp_Signature_count; 080 private int cp_Descr_count; 081 private int cp_Field_count; 082 private int cp_Method_count; 083 private int cp_Imethod_count; 084 085 private int attribute_definition_count; 086 private final IntList band_headers = new IntList(); 087 088 private boolean have_all_code_flags = true; // true by default 089 090 private int archive_size_hi; 091 private int archive_size_lo; 092 private int archive_next_count; 093 private int archive_modtime; 094 private int file_count; 095 096 private boolean deflate_hint; 097 private final boolean have_file_modtime = true; 098 private final boolean have_file_options = true; 099 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}