alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (unpack.h)

This example Java source code file (unpack.h) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

constant_class, constant_groupfirst, constant_grouplimit, constant_limit, constant_nameandtype, file, innerclasses, jar, product, sname, sub_tag, u_new, x_attr_limit_flags_hi, x_attr_limit_no_flags_hi

The unpack.h Java example source code

/*
 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
// Global Structures
struct jar;
struct gunzip;
struct band;
struct cpool;
struct entry;
struct cpindex;
struct inner_class;
struct value_stream;

struct cpindex {
  uint    len;
  entry*  base1;   // base of primary index
  entry** base2;   // base of secondary index
  byte    ixTag;   // type of entries (!= CONSTANT_None), plus 64 if sub-index
  enum { SUB_TAG = 64 };

  entry* get(uint i);

  void init(int len_, entry* base1_, int ixTag_) {
    len = len_;
    base1 = base1_;
    base2 = null;
    ixTag = ixTag_;
  }
  void init(int len_, entry** base2_, int ixTag_) {
    len = len_;
    base1 = null;
    base2 = base2_;
    ixTag = ixTag_;
  }
};

struct cpool {
  uint  nentries;
  entry* entries;
  entry* first_extra_entry;
  uint maxentries;      // total allocated size of entries

  // Position and size of each homogeneous subrange:
  int     tag_count[CONSTANT_Limit];
  int     tag_base[CONSTANT_Limit];
  cpindex tag_index[CONSTANT_Limit];
  ptrlist tag_extras[CONSTANT_Limit];

  int     tag_group_count[CONSTANT_GroupLimit - CONSTANT_GroupFirst];
  cpindex tag_group_index[CONSTANT_GroupLimit - CONSTANT_GroupFirst];

  cpindex* member_indexes;   // indexed by 2*CONSTANT_Class.inord
  cpindex* getFieldIndex(entry* classRef);
  cpindex* getMethodIndex(entry* classRef);

  inner_class** ic_index;
  inner_class** ic_child_index;
  inner_class* getIC(entry* inner);
  inner_class* getFirstChildIC(entry* outer);
  inner_class* getNextChildIC(inner_class* child);

  int outputIndexLimit;  // index limit after renumbering
  ptrlist outputEntries; // list of entry* needing output idx assigned
  ptrlist requested_bsms; // which bsms need output?

  entry** hashTab;
  uint    hashTabLength;
  entry*& hashTabRef(byte tag, bytes& b);
  entry*  ensureUtf8(bytes& b);
  entry*  ensureClass(bytes& b);

  // Well-known Utf8 symbols.
  enum {
    #define SNAME(n,s) s_##s,
    ALL_ATTR_DO(SNAME)
    #undef SNAME
    s_lt_init_gt,  // <init>
    s_LIMIT
  };
  entry* sym[s_LIMIT];

  // read counts from hdr, allocate main arrays
  void init(unpacker* u, int counts[CONSTANT_Limit]);

  // pointer to outer unpacker, for error checks etc.
  unpacker* u;

  int getCount(byte tag) {
    if ((uint)tag >= CONSTANT_GroupFirst) {
      assert((uint)tag < CONSTANT_GroupLimit);
      return tag_group_count[(uint)tag - CONSTANT_GroupFirst];
    } else {
      assert((uint)tag < CONSTANT_Limit);
      return tag_count[(uint)tag];
    }
  }
  cpindex* getIndex(byte tag) {
    if ((uint)tag >= CONSTANT_GroupFirst) {
      assert((uint)tag < CONSTANT_GroupLimit);
      return &tag_group_index[(uint)tag - CONSTANT_GroupFirst];
    } else {
      assert((uint)tag < CONSTANT_Limit);
      return &tag_index[(uint)tag];
    }
  }

  cpindex* getKQIndex();  // uses cur_descr

  void expandSignatures();
  void initGroupIndexes();
  void initMemberIndexes();
  int  initLoadableValues(entry** loadable_entries);

  void computeOutputOrder();
  void computeOutputIndexes();
  void resetOutputIndexes();

  // error handling
  inline void abort(const char* msg);
  inline bool aborting();
};

/*
 * The unpacker provides the entry points to the unpack engine,
 * as well as maintains the state of the engine.
 */
struct unpacker {
  // One element of the resulting JAR.
  struct file {
    const char* name;
    julong      size;
    int         modtime;
    int         options;
    bytes       data[2];
    // Note:  If Sum(data[*].len) < size,
    // remaining bytes must be read directly from the input stream.
    bool deflate_hint() { return ((options & FO_DEFLATE_HINT) != 0); }
  };

  // back pointer to NativeUnpacker obj and Java environment
  void* jniobj;
  void* jnienv;

  // global pointer to self, if not running under JNI (not multi-thread safe)
  static unpacker* non_mt_current;

  // if running Unix-style, here are the inputs and outputs
  FILE* infileptr;  // buffered
  int   infileno;   // unbuffered
  bytes inbytes;    // direct
  gunzip* gzin;     // gunzip filter, if any
  jar*  jarout;     // output JAR file

#ifndef PRODUCT
  int   nowrite;
  int   skipfiles;
  int   verbose_bands;
#endif

  // pointer to self, for U_NEW macro
  unpacker* u;

  // private abort message string, allocated to PATH_MAX*2
  const char* abort_message;
  ptrlist mallocs;      // list of guys to free when we are all done
  ptrlist tmallocs;     // list of guys to free on next client request
  fillbytes smallbuf;   // supplies small alloc requests
  fillbytes tsmallbuf;  // supplies temporary small alloc requests

  // option management members
  int   verbose;  // verbose level, 0 means no output
  bool  strip_compile;
  bool  strip_debug;
  bool  strip_jcov;
  bool  remove_packfile;
  int   deflate_hint_or_zero;  // ==0 means not set, otherwise -1 or 1
  int   modification_time_or_zero;

  FILE*       errstrm;
  const char* errstrm_name;

  const char* log_file;

  // input stream
  fillbytes input;       // the whole block (size is predicted, has slop too)
  bool      live_input;  // is the data in this block live?
  bool      free_input;  // must the input buffer be freed?
  byte*     rp;          // read pointer (< rplimit <= input.limit())
  byte*     rplimit;     // how much of the input block has been read?
  julong    bytes_read;
  int       unsized_bytes_read;

  // callback to read at least one byte, up to available input
  typedef jlong (*read_input_fn_t)(unpacker* self, void* buf, jlong minlen, jlong maxlen);
  read_input_fn_t read_input_fn;

  // archive header fields
  int      magic, minver, majver;
  size_t   archive_size;
  int      archive_next_count, archive_options, archive_modtime;
  int      band_headers_size;
  int      file_count, attr_definition_count, ic_count, class_count;
  int      default_class_minver, default_class_majver;
  int      default_file_options, suppress_file_options;  // not header fields
  int      default_archive_modtime, default_file_modtime;  // not header fields
  int      code_count;  // not a header field
  int      files_remaining;  // not a header field

  // engine state
  band*        all_bands;   // indexed by band_number
  byte*        meta_rp;     // read-pointer into (copy of) band_headers
  cpool        cp;          // all constant pool information
  inner_class* ics;         // InnerClasses

  // output stream
  bytes    output;      // output block (either classfile head or tail)
  byte*    wp;          // write pointer (< wplimit == output.limit())
  byte*    wpbase;      // write pointer starting address (<= wp)
  byte*    wplimit;     // how much of the output block has been written?

  // output state
  file      cur_file;
  entry*    cur_class;  // CONSTANT_Class entry
  entry*    cur_super;  // CONSTANT_Class entry or null
  entry*    cur_descr;  // CONSTANT_NameandType entry
  int       cur_descr_flags;  // flags corresponding to cur_descr
  int       cur_class_minver, cur_class_majver;
  bool      cur_class_has_local_ics;
  int       cur_class_local_bsm_count;
  fillbytes cur_classfile_head;
  fillbytes cur_classfile_tail;
  int       files_written;   // also tells which file we're working on
  int       classes_written; // also tells which class we're working on
  julong    bytes_written;
  intlist   bcimap;
  fillbytes class_fixup_type;
  intlist   class_fixup_offset;
  ptrlist   class_fixup_ref;
  fillbytes code_fixup_type;    // which format of branch operand?
  intlist   code_fixup_offset;  // location of operand needing fixup
  intlist   code_fixup_source;  // encoded ID of branch insn
  ptrlist   requested_ics;      // which ics need output?

  // stats pertaining to multiple segments (updated on reset)
  julong    bytes_read_before_reset;
  julong    bytes_written_before_reset;
  int       files_written_before_reset;
  int       classes_written_before_reset;
  int       segments_read_before_reset;

  // attribute state
  struct layout_definition {
    uint          idx;        // index (0..31...) which identifies this layout
    const char*   name;       // name of layout
    entry*        nameEntry;
    const char*   layout;     // string of layout (not yet parsed)
    band**        elems;      // array of top-level layout elems (or callables)

    bool hasCallables()   { return layout[0] == '['; }
    band** bands()        { assert(elems != null); return elems; }
  };
  struct attr_definitions {
    unpacker* u;  // pointer to self, for U_NEW macro
    int     xxx_flags_hi_bn;// locator for flags, count, indexes, calls bands
    int     attrc;          // ATTR_CONTEXT_CLASS, etc.
    uint    flag_limit;     // 32 or 63, depending on archive_options bit
    julong  predef;         // mask of built-in definitions
    julong  redef;          // mask of local flag definitions or redefinitions
    ptrlist layouts;        // local (compressor-defined) defs, in index order
    int     flag_count[X_ATTR_LIMIT_FLAGS_HI];
    intlist overflow_count;
    ptrlist strip_names;    // what attribute names are being stripped?
    ptrlist band_stack;     // Temp., used during layout parsing.
    ptrlist calls_to_link;  //  (ditto)
    int     bands_made;     //  (ditto)

    void free() {
      layouts.free();
      overflow_count.free();
      strip_names.free();
      band_stack.free();
      calls_to_link.free();
    }

    // Locate the five fixed bands.
    band& xxx_flags_hi();
    band& xxx_flags_lo();
    band& xxx_attr_count();
    band& xxx_attr_indexes();
    band& xxx_attr_calls();
    band& fixed_band(int e_class_xxx);

    // Register a new layout, and make bands for it.
    layout_definition* defineLayout(int idx, const char* name, const char* layout);
    layout_definition* defineLayout(int idx, entry* nameEntry, const char* layout);
    band** buildBands(layout_definition* lo);

    // Parse a layout string or part of one, recursively if necessary.
    const char* parseLayout(const char* lp,    band** &res, int curCble);
    const char* parseNumeral(const char* lp,   int    &res);
    const char* parseIntLayout(const char* lp, band*  &res, byte le_kind,
                               bool can_be_signed = false);
    band** popBody(int band_stack_base);  // pops a body off band_stack

    // Read data into the bands of the idx-th layout.
    void readBandData(int idx);  // parse layout, make bands, read data
    void readBandData(band** body, uint count);  // recursive helper

    layout_definition* getLayout(uint idx) {
      if (idx >= (uint)layouts.length())  return null;
      return (layout_definition*) layouts.get(idx);
    }

    void setHaveLongFlags(bool z) {
      assert(flag_limit == 0);  // not set up yet
      flag_limit = (z? X_ATTR_LIMIT_FLAGS_HI: X_ATTR_LIMIT_NO_FLAGS_HI);
    }
    bool haveLongFlags() {
     assert(flag_limit == X_ATTR_LIMIT_NO_FLAGS_HI ||
            flag_limit == X_ATTR_LIMIT_FLAGS_HI);
      return flag_limit == X_ATTR_LIMIT_FLAGS_HI;
    }

    // Return flag_count if idx is predef and not redef, else zero.
    int predefCount(uint idx);

    bool isRedefined(uint idx) {
      if (idx >= flag_limit) return false;
      return (bool)((redef >> idx) & 1);
    }
    bool isPredefined(uint idx) {
      if (idx >= flag_limit) return false;
      return (bool)(((predef & ~redef) >> idx) & 1);
    }
    julong flagIndexMask() {
      return (predef | redef);
    }
    bool isIndex(uint idx) {
      assert(flag_limit != 0);  // must be set up already
      if (idx < flag_limit)
        return (bool)(((predef | redef) >> idx) & 1);
      else
        return (idx - flag_limit < (uint)overflow_count.length());
    }
    int& getCount(uint idx) {
      assert(isIndex(idx));
      if (idx < flag_limit)
        return flag_count[idx];
      else
        return overflow_count.get(idx - flag_limit);
    }
    bool aborting()             { return u->aborting(); }
    void abort(const char* msg) { u->abort(msg); }
  };

  attr_definitions attr_defs[ATTR_CONTEXT_LIMIT];

  // Initialization
  void         init(read_input_fn_t input_fn = null);
  // Resets to a known sane state
  void         reset();
  // Deallocates all storage.
  void         free();
  // Deallocates temporary storage (volatile after next client call).
  void         free_temps() { tsmallbuf.init(); tmallocs.freeAll(); }

  // Option management methods
  bool         set_option(const char* option, const char* value);
  const char*  get_option(const char* option);

  void         dump_options();

  // Fetching input.
  bool   ensure_input(jlong more);
  byte*  input_scan()               { return rp; }
  size_t input_remaining()          { return rplimit - rp; }
  size_t input_consumed()           { return rp - input.base(); }

  // Entry points to the unpack engine
  static int   run(int argc, char **argv);   // Unix-style entry point.
  void         check_options();
  void         start(void* packptr = null, size_t len = 0);
  void         redirect_stdio();
  void         write_file_to_jar(file* f);
  void         finish();

  // Public post unpack methods
  int          get_files_remaining()    { return files_remaining; }
  int          get_segments_remaining() { return archive_next_count; }
  file*        get_next_file();  // returns null on last file

  // General purpose methods
  void*        alloc(size_t size) { return alloc_heap(size, true); }
  void*        temp_alloc(size_t size) { return alloc_heap(size, true, true); }
  void*        alloc_heap(size_t size, bool smallOK = false, bool temp = false);
  void         saveTo(bytes& b, const char* str) { saveTo(b, (byte*)str, strlen(str)); }
  void         saveTo(bytes& b, bytes& data) { saveTo(b, data.ptr, data.len); }
  void         saveTo(bytes& b, byte* ptr, size_t len); //{ b.ptr = U_NEW...}
  const char*  saveStr(const char* str) { bytes buf; saveTo(buf, str); return buf.strval(); }
  const char*  saveIntStr(int num) { char buf[30]; sprintf(buf, "%d", num); return saveStr(buf); }
#ifndef PRODUCT
  int printcr_if_verbose(int level, const char* fmt,...);
#endif
  const char*  get_abort_message();
  void         abort(const char* s = null);
  bool         aborting() { return abort_message != null; }
  static unpacker* current();  // find current instance
  void checkLegacy(const char* name);
  // Output management
  void set_output(fillbytes* which) {
    assert(wp == null);
    which->ensureSize(1 << 12);  // covers the average classfile
    wpbase  = which->base();
    wp      = which->limit();
    wplimit = which->end();
  }
  fillbytes* close_output(fillbytes* which = null);  // inverse of set_output

  // These take an implicit parameter of wp/wplimit, and resize as necessary:
  byte*  put_space(size_t len);  // allocates space at wp, returns pointer
  size_t put_empty(size_t s)    { byte* p = put_space(s); return p - wpbase; }
  void   ensure_put_space(size_t len);
  void   put_bytes(bytes& b)    { b.writeTo(put_space(b.len)); }
  void   putu1(int n)           { putu1_at(put_space(1), n); }
  void   putu1_fast(int n)      { putu1_at(wp++,         n); }
  void   putu2(int n);       // { putu2_at(put_space(2), n); }
  void   putu4(int n);       // { putu4_at(put_space(4), n); }
  void   putu8(jlong n);     // { putu8_at(put_space(8), n); }
  void   putref(entry* e);   // { putu2_at(put_space(2), putref_index(e, 2)); }
  void   putu1ref(entry* e); // { putu1_at(put_space(1), putref_index(e, 1)); }
  int    putref_index(entry* e, int size);  // size in [1..2]
  void   put_label(int curIP, int size);    // size in {2,4}
  void   putlayout(band** body);
  void   put_stackmap_type();

  size_t wpoffset() { return (size_t)(wp - wpbase); }  // (unvariant across overflow)
  byte*  wp_at(size_t offset) { return wpbase + offset; }
  uint to_bci(uint bii);
  void get_code_header(int& max_stack,
                       int& max_na_locals,
                       int& handler_count,
                       int& cflags);
  band* ref_band_for_self_op(int bc, bool& isAloadVar, int& origBCVar);
  band* ref_band_for_op(int bc);

  // Definitions of standard classfile int formats:
  static void putu1_at(byte* wp, int n) { assert(n == (n & 0xFF)); wp[0] = n; }
  static void putu2_at(byte* wp, int n);
  static void putu4_at(byte* wp, int n);
  static void putu8_at(byte* wp, jlong n);

  // Private stuff
  void reset_cur_classfile();
  void write_classfile_tail();
  void write_classfile_head();
  void write_code();
  void write_bc_ops();
  void write_members(int num, int attrc);  // attrc=ATTR_CONTEXT_FIELD/METHOD
  int  write_attrs(int attrc, julong indexBits);
  int  write_ics(int naOffset, int na);
  int  write_bsms(int naOffset, int na);

  // The readers
  void read_bands();
  void read_file_header();
  void read_cp();
  void read_cp_counts(value_stream& hdr);
  void read_attr_defs();
  void read_ics();
  void read_attrs(int attrc, int obj_count);
  void read_classes();
  void read_code_headers();
  void read_bcs();
  void read_bc_ops();
  void read_files();
  void read_Utf8_values(entry* cpMap, int len);
  void read_single_words(band& cp_band, entry* cpMap, int len);
  void read_double_words(band& cp_bands, entry* cpMap, int len);
  void read_single_refs(band& cp_band, byte refTag, entry* cpMap, int len);
  void read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag, entry* cpMap, int len);
  void read_signature_values(entry* cpMap, int len);
  void read_method_handle(entry* cpMap, int len);
  void read_method_type(entry* cpMap, int len);
  void read_bootstrap_methods(entry* cpMap, int len);
};

inline void cpool::abort(const char* msg) { u->abort(msg); }
inline bool cpool::aborting()             { return u->aborting(); }

Other Java examples (source code examples)

Here is a short list of links related to this Java unpack.h source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.