SegmentHeader.java

  1. /*
  2.  *  Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.commons.compress.harmony.pack200;

  18. import java.io.IOException;
  19. import java.io.OutputStream;

  20. /**
  21.  * SegmentHeader is the header band of a {@link Segment}. Corresponds to {@code segment_header} in the pack200 specification.
  22.  */
  23. public class SegmentHeader extends BandSet {

  24.     /**
  25.      * Counter for major/minor class file numbers, so we can work out the default
  26.      */
  27.     private static final class Counter {

  28.         private final int[] objs = new int[8];
  29.         private final int[] counts = new int[8];
  30.         private int length;

  31.         public void add(final int obj) {
  32.             boolean found = false;
  33.             for (int i = 0; i < length; i++) {
  34.                 if (objs[i] == obj) {
  35.                     counts[i]++;
  36.                     found = true;
  37.                 }
  38.             }
  39.             if (!found) {
  40.                 objs[length] = obj;
  41.                 counts[length] = 1;
  42.                 length++;
  43.                 if (length > objs.length - 1) {
  44.                     final Object[] newArray = new Object[objs.length + 8];
  45.                     System.arraycopy(objs, 0, newArray, 0, length);
  46.                 }
  47.             }
  48.         }

  49.         public int getMostCommon() {
  50.             int returnIndex = 0;
  51.             for (int i = 0; i < length; i++) {
  52.                 if (counts[i] > counts[returnIndex]) {
  53.                     returnIndex = i;
  54.                 }
  55.             }
  56.             return objs[returnIndex];
  57.         }
  58.     }

  59.     private static final int[] magic = { 0xCA, 0xFE, 0xD0, 0x0D };
  60.     private static final int archive_minver = 7;
  61.     private static final int archive_majver = 150;

  62.     private int archive_options;

  63.     private int cp_Utf8_count;
  64.     private int cp_Int_count;
  65.     private int cp_Float_count;
  66.     private int cp_Long_count;
  67.     private int cp_Double_count;
  68.     private int cp_String_count;
  69.     private int cp_Class_count;
  70.     private int cp_Signature_count;
  71.     private int cp_Descr_count;
  72.     private int cp_Field_count;
  73.     private int cp_Method_count;
  74.     private int cp_Imethod_count;

  75.     private int attribute_definition_count;
  76.     private final IntList band_headers = new IntList();

  77.     private boolean have_all_code_flags = true; // true by default

  78.     private int archive_size_hi;
  79.     private int archive_size_lo;
  80.     private int archive_next_count;
  81.     private int archive_modtime;
  82.     private int file_count;

  83.     private boolean deflate_hint;
  84.     private final boolean have_file_modtime = true;
  85.     private final boolean have_file_options = true;
  86.     private boolean have_file_size_hi;
  87.     private boolean have_class_flags_hi;
  88.     private boolean have_field_flags_hi;
  89.     private boolean have_method_flags_hi;
  90.     private boolean have_code_flags_hi;

  91.     private int ic_count;
  92.     private int class_count;
  93.     private final Counter majverCounter = new Counter();

  94.     /**
  95.      * Constructs a new SegmentHeader
  96.      */
  97.     public SegmentHeader() {
  98.         super(1, null); // Pass 1 for effort because bands in the segment header
  99.                         // should always use the default encoding
  100.     }

  101.     public void addMajorVersion(final int major) {
  102.         majverCounter.add(major);
  103.     }

  104.     public void appendBandCodingSpecifier(final int specifier) {
  105.         band_headers.add(specifier);
  106.     }

  107.     private void calculateArchiveOptions() {
  108.         if (attribute_definition_count > 0 || band_headers.size() > 0) {
  109.             archive_options |= 1;
  110.         }
  111.         if (cp_Int_count > 0 || cp_Float_count > 0 || cp_Long_count > 0 || cp_Double_count > 0) {
  112.             archive_options |= 1 << 1;
  113.         }
  114.         if (have_all_code_flags) {
  115.             archive_options |= 1 << 2;
  116.         }
  117.         if (file_count > 0) {
  118.             archive_options |= 1 << 4;
  119.         }
  120.         if (deflate_hint) {
  121.             archive_options |= 1 << 5;
  122.         }
  123.         if (have_file_modtime) {
  124.             archive_options |= 1 << 6;
  125.         }
  126.         if (have_file_options) {
  127.             archive_options |= 1 << 7;
  128.         }
  129.         if (have_file_size_hi) {
  130.             archive_options |= 1 << 8;
  131.         }
  132.         if (have_class_flags_hi) {
  133.             archive_options |= 1 << 9;
  134.         }
  135.         if (have_field_flags_hi) {
  136.             archive_options |= 1 << 10;
  137.         }
  138.         if (have_method_flags_hi) {
  139.             archive_options |= 1 << 11;
  140.         }
  141.         if (have_code_flags_hi) {
  142.             archive_options |= 1 << 12;
  143.         }
  144.     }

  145.     public int getArchive_modtime() {
  146.         return archive_modtime;
  147.     }

  148.     public int getDefaultMajorVersion() {
  149.         return majverCounter.getMostCommon();
  150.     }

  151.     public boolean have_all_code_flags() {
  152.         return have_all_code_flags;
  153.     }

  154.     public boolean have_class_flags_hi() {
  155.         return have_class_flags_hi;
  156.     }

  157.     public boolean have_code_flags_hi() {
  158.         return have_code_flags_hi;
  159.     }

  160.     public boolean have_field_flags_hi() {
  161.         return have_field_flags_hi;
  162.     }

  163.     public boolean have_file_modtime() {
  164.         return have_file_modtime;
  165.     }

  166.     public boolean have_file_options() {
  167.         return have_file_options;
  168.     }

  169.     public boolean have_file_size_hi() {
  170.         return have_file_size_hi;
  171.     }

  172.     public boolean have_method_flags_hi() {
  173.         return have_method_flags_hi;
  174.     }

  175.     /**
  176.      * Encode and write the SegmentHeader bands to the OutputStream
  177.      */
  178.     @Override
  179.     public void pack(final OutputStream out) throws IOException, Pack200Exception {
  180.         out.write(encodeScalar(magic, Codec.BYTE1));
  181.         out.write(encodeScalar(archive_minver, Codec.UNSIGNED5));
  182.         out.write(encodeScalar(archive_majver, Codec.UNSIGNED5));
  183.         calculateArchiveOptions();
  184.         out.write(encodeScalar(archive_options, Codec.UNSIGNED5));
  185.         writeArchiveFileCounts(out);
  186.         writeArchiveSpecialCounts(out);
  187.         writeCpCounts(out);
  188.         writeClassCounts(out);
  189.         if (band_headers.size() > 0) {
  190.             out.write(encodeScalar(band_headers.toArray(), Codec.BYTE1));
  191.         }
  192.     }

  193.     public void setAttribute_definition_count(final int attribute_definition_count) {
  194.         this.attribute_definition_count = attribute_definition_count;
  195.     }

  196.     public void setClass_count(final int class_count) {
  197.         this.class_count = class_count;
  198.     }

  199.     public void setCp_Class_count(final int count) {
  200.         cp_Class_count = count;
  201.     }

  202.     public void setCp_Descr_count(final int count) {
  203.         cp_Descr_count = count;
  204.     }

  205.     public void setCp_Double_count(final int count) {
  206.         cp_Double_count = count;
  207.     }

  208.     public void setCp_Field_count(final int count) {
  209.         cp_Field_count = count;
  210.     }

  211.     public void setCp_Float_count(final int count) {
  212.         cp_Float_count = count;
  213.     }

  214.     public void setCp_Imethod_count(final int count) {
  215.         cp_Imethod_count = count;
  216.     }

  217.     public void setCp_Int_count(final int count) {
  218.         cp_Int_count = count;
  219.     }

  220.     public void setCp_Long_count(final int count) {
  221.         cp_Long_count = count;
  222.     }

  223.     public void setCp_Method_count(final int count) {
  224.         cp_Method_count = count;
  225.     }

  226.     public void setCp_Signature_count(final int count) {
  227.         cp_Signature_count = count;
  228.     }

  229.     public void setCp_String_count(final int count) {
  230.         cp_String_count = count;
  231.     }

  232.     public void setCp_Utf8_count(final int count) {
  233.         cp_Utf8_count = count;
  234.     }

  235.     public void setDeflate_hint(final boolean deflate_hint) {
  236.         this.deflate_hint = deflate_hint;
  237.     }

  238.     public void setFile_count(final int file_count) {
  239.         this.file_count = file_count;
  240.     }

  241.     public void setHave_all_code_flags(final boolean have_all_code_flags) {
  242.         this.have_all_code_flags = have_all_code_flags;
  243.     }

  244.     public void setHave_class_flags_hi(final boolean have_class_flags_hi) {
  245.         this.have_class_flags_hi = have_class_flags_hi;
  246.     }

  247.     public void setHave_code_flags_hi(final boolean have_code_flags_hi) {
  248.         this.have_code_flags_hi = have_code_flags_hi;
  249.     }

  250.     public void setHave_field_flags_hi(final boolean have_field_flags_hi) {
  251.         this.have_field_flags_hi = have_field_flags_hi;
  252.     }

  253.     public void setHave_method_flags_hi(final boolean have_method_flags_hi) {
  254.         this.have_method_flags_hi = have_method_flags_hi;
  255.     }

  256.     public void setIc_count(final int ic_count) {
  257.         this.ic_count = ic_count;
  258.     }

  259.     private void writeArchiveFileCounts(final OutputStream out) throws IOException, Pack200Exception {
  260.         if ((archive_options & 1 << 4) > 0) { // have_file_headers
  261.             out.write(encodeScalar(archive_size_hi, Codec.UNSIGNED5));
  262.             out.write(encodeScalar(archive_size_lo, Codec.UNSIGNED5));
  263.             out.write(encodeScalar(archive_next_count, Codec.UNSIGNED5));
  264.             out.write(encodeScalar(archive_modtime, Codec.UNSIGNED5));
  265.             out.write(encodeScalar(file_count, Codec.UNSIGNED5));
  266.         }
  267.     }

  268.     private void writeArchiveSpecialCounts(final OutputStream out) throws IOException, Pack200Exception {
  269.         if ((archive_options & 1) > 0) { // have_special_formats
  270.             out.write(encodeScalar(band_headers.size(), Codec.UNSIGNED5));
  271.             out.write(encodeScalar(attribute_definition_count, Codec.UNSIGNED5));
  272.         }
  273.     }

  274.     private void writeClassCounts(final OutputStream out) throws IOException, Pack200Exception {
  275.         final int default_class_minver = 0;
  276.         final int default_class_majver = majverCounter.getMostCommon();
  277.         out.write(encodeScalar(ic_count, Codec.UNSIGNED5));
  278.         out.write(encodeScalar(default_class_minver, Codec.UNSIGNED5));
  279.         out.write(encodeScalar(default_class_majver, Codec.UNSIGNED5));
  280.         out.write(encodeScalar(class_count, Codec.UNSIGNED5));
  281.     }

  282.     private void writeCpCounts(final OutputStream out) throws IOException, Pack200Exception {
  283.         out.write(encodeScalar(cp_Utf8_count, Codec.UNSIGNED5));
  284.         if ((archive_options & 1 << 1) != 0) { // have_cp_numbers
  285.             out.write(encodeScalar(cp_Int_count, Codec.UNSIGNED5));
  286.             out.write(encodeScalar(cp_Float_count, Codec.UNSIGNED5));
  287.             out.write(encodeScalar(cp_Long_count, Codec.UNSIGNED5));
  288.             out.write(encodeScalar(cp_Double_count, Codec.UNSIGNED5));
  289.         }
  290.         out.write(encodeScalar(cp_String_count, Codec.UNSIGNED5));
  291.         out.write(encodeScalar(cp_Class_count, Codec.UNSIGNED5));
  292.         out.write(encodeScalar(cp_Signature_count, Codec.UNSIGNED5));
  293.         out.write(encodeScalar(cp_Descr_count, Codec.UNSIGNED5));
  294.         out.write(encodeScalar(cp_Field_count, Codec.UNSIGNED5));
  295.         out.write(encodeScalar(cp_Method_count, Codec.UNSIGNED5));
  296.         out.write(encodeScalar(cp_Imethod_count, Codec.UNSIGNED5));
  297.     }

  298. }