001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.commons.compress.harmony.pack200; 020 021import java.io.IOException; 022import java.io.OutputStream; 023 024/** 025 * SegmentHeader is the header band of a {@link Segment}. Corresponds to {@code segment_header} in the pack200 specification. 026 */ 027public class SegmentHeader extends BandSet { 028 029 /** 030 * Counter for major/minor class file numbers, so we can work out the default 031 */ 032 private static final class Counter { 033 034 private final int[] objs = new int[8]; 035 private final int[] counts = new int[8]; 036 private int length; 037 038 public void add(final int obj) { 039 boolean found = false; 040 for (int i = 0; i < length; i++) { 041 if (objs[i] == obj) { 042 counts[i]++; 043 found = true; 044 } 045 } 046 if (!found) { 047 objs[length] = obj; 048 counts[length] = 1; 049 length++; 050 if (length > objs.length - 1) { 051 final Object[] newArray = new Object[objs.length + 8]; 052 System.arraycopy(objs, 0, newArray, 0, length); 053 } 054 } 055 } 056 057 public int getMostCommon() { 058 int returnIndex = 0; 059 for (int i = 0; i < length; i++) { 060 if (counts[i] > counts[returnIndex]) { 061 returnIndex = i; 062 } 063 } 064 return objs[returnIndex]; 065 } 066 } 067 068 private static final int[] magic = { 0xCA, 0xFE, 0xD0, 0x0D }; 069 private static final int archive_minver = 7; 070 private static final int archive_majver = 150; 071 072 private int archive_options; 073 074 private int cp_Utf8_count; 075 private int cp_Int_count; 076 private int cp_Float_count; 077 private int cp_Long_count; 078 private int cp_Double_count; 079 private int cp_String_count; 080 private int cp_Class_count; 081 private int cp_Signature_count; 082 private int cp_Descr_count; 083 private int cp_Field_count; 084 private int cp_Method_count; 085 private int cp_Imethod_count; 086 087 private int attribute_definition_count; 088 private final IntList band_headers = new IntList(); 089 090 private boolean have_all_code_flags = true; // true by default 091 092 private int archive_size_hi; 093 private int archive_size_lo; 094 private int archive_next_count; 095 private int archive_modtime; 096 private int file_count; 097 098 private boolean deflate_hint; 099 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}