1 /*
   2  * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.internal.jimage;
  27 
  28 import java.nio.ByteBuffer;
  29 import java.nio.ByteOrder;
  30 import java.util.Arrays;
  31 import java.util.Objects;
  32 
  33 /**
  34  * @implNote This class needs to maintain JDK 8 source compatibility.
  35  *
  36  * It is used internally in the JDK to implement jimage/jrtfs access,
  37  * but also compiled and delivered as part of the jrtfs.jar to support access
  38  * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  39  */
  40 public class ImageStream {
  41     private ByteBuffer buffer;
  42 
  43     public ImageStream() {
  44         this(1024, ByteOrder.nativeOrder());
  45     }
  46 
  47     public ImageStream(int size) {
  48         this(size, ByteOrder.nativeOrder());
  49     }
  50 
  51     public ImageStream(byte[] bytes) {
  52        this(bytes, ByteOrder.nativeOrder());
  53     }
  54 
  55     public ImageStream(ByteOrder byteOrder) {
  56         this(1024, byteOrder);
  57     }
  58 
  59     public ImageStream(int size, ByteOrder byteOrder) {
  60         buffer = ByteBuffer.allocate(size);
  61         buffer.order(Objects.requireNonNull(byteOrder));
  62     }
  63 
  64     public ImageStream(byte[] bytes, ByteOrder byteOrder) {
  65         buffer = ByteBuffer.wrap(Objects.requireNonNull(bytes));
  66         buffer.order(Objects.requireNonNull(byteOrder));
  67     }
  68 
  69     public ImageStream(ByteBuffer buffer) {
  70         this.buffer = Objects.requireNonNull(buffer);
  71     }
  72 
  73     public ImageStream align(int alignment) {
  74         int padding = (getSize() - 1) & ((1 << alignment) - 1);
  75 
  76         for (int i = 0; i < padding; i++) {
  77             put((byte)0);
  78         }
  79 
  80         return this;
  81     }
  82 
  83     public void ensure(int needs) {
  84         if (needs < 0) {
  85             throw new IndexOutOfBoundsException("Bad value: " + needs);
  86         }
  87 
  88         if (needs > buffer.remaining()) {
  89             byte[] bytes = buffer.array();
  90             ByteOrder byteOrder = buffer.order();
  91             int position = buffer.position();
  92             int newSize = needs <= bytes.length ? bytes.length << 1 : position + needs;
  93             buffer = ByteBuffer.allocate(newSize);
  94             buffer.order(byteOrder);
  95             buffer.put(bytes, 0, position);
  96         }
  97     }
  98 
  99     public boolean hasByte() {
 100         return buffer.remaining() != 0;
 101     }
 102 
 103     public boolean hasBytes(int needs) {
 104         return needs <= buffer.remaining();
 105     }
 106 
 107     public void skip(int n) {
 108         if (n < 0) {
 109             throw new IndexOutOfBoundsException("skip value = " + n);
 110         }
 111 
 112         buffer.position(buffer.position() + n);
 113     }
 114 
 115     public int get() {
 116         return buffer.get() & 0xFF;
 117     }
 118 
 119     public void get(byte bytes[], int offset, int size) {
 120         buffer.get(bytes, offset, size);
 121     }
 122 
 123     public int getShort() {
 124         return buffer.getShort();
 125     }
 126 
 127     public int getInt() {
 128         return buffer.getInt();
 129     }
 130 
 131     public long getLong() {
 132         return buffer.getLong();
 133     }
 134 
 135     public ImageStream put(byte byt) {
 136         ensure(1);
 137         buffer.put(byt);
 138 
 139         return this;
 140     }
 141 
 142     public ImageStream put(int byt) {
 143         return put((byte)byt);
 144     }
 145 
 146     public ImageStream put(byte bytes[], int offset, int size) {
 147         ensure(size);
 148         buffer.put(bytes, offset, size);
 149 
 150         return this;
 151     }
 152 
 153     public ImageStream put(ImageStream stream) {
 154         put(stream.buffer.array(), 0, stream.buffer.position());
 155 
 156         return this;
 157     }
 158 
 159     public ImageStream putShort(short value) {
 160         ensure(2);
 161         buffer.putShort(value);
 162 
 163         return this;
 164     }
 165 
 166     public ImageStream putShort(int value) {
 167         return putShort((short)value);
 168     }
 169 
 170     public ImageStream putInt(int value) {
 171         ensure(4);
 172         buffer.putInt(value);
 173 
 174         return this;
 175     }
 176 
 177     public ImageStream putLong(long value) {
 178         ensure(8);
 179         buffer.putLong(value);
 180 
 181         return this;
 182     }
 183 
 184     public ByteBuffer getBuffer() {
 185         return buffer;
 186     }
 187 
 188     public int getPosition() {
 189         return buffer.position();
 190     }
 191 
 192     public int getSize() {
 193         return buffer.position();
 194     }
 195 
 196     public byte[] getBytes() {
 197         return buffer.array();
 198     }
 199 
 200     public void setPosition(int offset) {
 201         buffer.position(offset);
 202     }
 203 
 204     public byte[] toArray() {
 205         return Arrays.copyOf(buffer.array(), buffer.position());
 206     }
 207 }