1 /* 2 * Copyright (c) 2014, 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 package jdk.internal.jimage; 26 27 import java.io.ByteArrayInputStream; 28 import java.io.IOException; 29 import java.io.File; 30 import java.io.InputStream; 31 import java.nio.ByteBuffer; 32 import java.nio.ByteOrder; 33 import java.nio.IntBuffer; 34 import java.util.Comparator; 35 import java.util.stream.IntStream; 36 37 public class BasicImageReader { 38 private final String imagePath; 39 private final ImageSubstrate substrate; 40 private final ByteOrder byteOrder; 41 private final ImageStringsReader strings; 42 43 protected BasicImageReader(String imagePath, ByteOrder byteOrder) 44 throws IOException { 45 this.imagePath = imagePath; 46 this.substrate = openImageSubstrate(imagePath, byteOrder); 47 this.byteOrder = byteOrder; 48 this.strings = new ImageStringsReader(this); 49 } 50 51 protected BasicImageReader(String imagePath) throws IOException { 52 this(imagePath, ByteOrder.nativeOrder()); 53 } 54 55 private static ImageSubstrate openImageSubstrate(String imagePath, ByteOrder byteOrder) 56 throws IOException { 57 ImageSubstrate substrate; 58 59 try { 60 substrate = ImageNativeSubstrate.openImage(imagePath, byteOrder); 61 } catch (UnsatisfiedLinkError ex) { 62 substrate = ImageJavaSubstrate.openImage(imagePath, byteOrder); 63 } 64 65 return substrate; 66 } 67 68 public static BasicImageReader open(String imagePath) throws IOException { 69 return new BasicImageReader(imagePath, ByteOrder.nativeOrder()); 70 } 71 72 public static void releaseByteBuffer(ByteBuffer buffer) { 73 ImageBufferCache.releaseBuffer(buffer); 74 } 75 76 public ByteOrder getByteOrder() { 77 return byteOrder; 78 } 79 80 public String imagePath() { 81 return imagePath; 82 } 83 84 public String imagePathName() { 85 int slash = imagePath().lastIndexOf(File.separator); 86 87 if (slash != -1) { 88 return imagePath().substring(slash + 1); 89 } 90 91 return imagePath(); 92 } 93 94 public boolean isOpen() { 95 return true; 96 } 97 98 public void close() throws IOException { 99 substrate.close(); 100 } 101 102 public ImageHeader getHeader() throws IOException { 103 return ImageHeader.readFrom( 104 getIndexIntBuffer(0, ImageHeader.getHeaderSize())); 105 } 106 107 public ImageStringsReader getStrings() { 108 return strings; 109 } 110 111 public ImageLocation findLocation(String name) { 112 return findLocation(new UTF8String(name)); 113 } 114 115 public ImageLocation findLocation(byte[] name) { 116 return findLocation(new UTF8String(name)); 117 } 118 119 public synchronized ImageLocation findLocation(UTF8String name) { 120 return substrate.findLocation(name, strings); 121 } 122 123 public String[] getEntryNames() { 124 return IntStream.of(substrate.attributeOffsets()) 125 .filter(o -> o != 0) 126 .mapToObj(o -> ImageLocation.readFrom(this, o).getFullNameString()) 127 .sorted() 128 .toArray(String[]::new); 129 } 130 131 protected ImageLocation[] getAllLocations(boolean sorted) { 132 return IntStream.of(substrate.attributeOffsets()) 133 .filter(o -> o != 0) 134 .mapToObj(o -> ImageLocation.readFrom(this, o)) 135 .sorted(Comparator.comparing(ImageLocation::getFullNameString)) 136 .toArray(ImageLocation[]::new); 137 } 138 139 private IntBuffer getIndexIntBuffer(long offset, long size) 140 throws IOException { 141 ByteBuffer buffer = substrate.getIndexBuffer(offset, size); 142 buffer.order(byteOrder); 143 144 return buffer.asIntBuffer(); 145 } 146 147 ImageLocation getLocation(int offset) { 148 return ImageLocation.readFrom(this, offset); 149 } 150 151 public long[] getAttributes(int offset) { 152 return substrate.getAttributes(offset); 153 } 154 155 public String getString(int offset) { 156 return getUTF8String(offset).toString(); 157 } 158 159 public UTF8String getUTF8String(int offset) { 160 return new UTF8String(substrate.getStringBytes(offset)); 161 } 162 163 private byte[] getBufferBytes(ByteBuffer buffer, long size) { 164 assert size < Integer.MAX_VALUE; 165 byte[] bytes = new byte[(int)size]; 166 buffer.get(bytes); 167 168 return bytes; 169 } 170 171 private byte[] getBufferBytes(long offset, long size) { 172 ByteBuffer buffer = substrate.getDataBuffer(offset, size); 173 174 return getBufferBytes(buffer, size); 175 } 176 177 public byte[] getResource(ImageLocation loc) { 178 long offset = loc.getContentOffset(); 179 long compressedSize = loc.getCompressedSize(); 180 long uncompressedSize = loc.getUncompressedSize(); 181 assert compressedSize < Integer.MAX_VALUE; 182 assert uncompressedSize < Integer.MAX_VALUE; 183 184 if (substrate.supportsDataBuffer() && compressedSize == 0) { 185 return getBufferBytes(offset, uncompressedSize); 186 } 187 188 ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize); 189 boolean isRead; 190 191 if (compressedSize != 0) { 192 ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize); 193 isRead = substrate.read(offset, compressedBuffer, compressedSize, 194 uncompressedBuffer, uncompressedSize); 195 ImageBufferCache.releaseBuffer(compressedBuffer); 196 } else { 197 isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize); 198 } 199 200 byte[] bytes = isRead ? getBufferBytes(uncompressedBuffer, 201 uncompressedSize) : null; 202 203 ImageBufferCache.releaseBuffer(uncompressedBuffer); 204 205 return bytes; 206 } 207 208 public byte[] getResource(String name) { 209 ImageLocation location = findLocation(name); 210 211 return location != null ? getResource(location) : null; 212 } 213 214 public ByteBuffer getResourceBuffer(ImageLocation loc) { 215 long offset = loc.getContentOffset(); 216 long compressedSize = loc.getCompressedSize(); 217 long uncompressedSize = loc.getUncompressedSize(); 218 assert compressedSize < Integer.MAX_VALUE; 219 assert uncompressedSize < Integer.MAX_VALUE; 220 221 if (substrate.supportsDataBuffer() && compressedSize == 0) { 222 return substrate.getDataBuffer(offset, uncompressedSize); 223 } 224 225 ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize); 226 boolean isRead; 227 228 if (compressedSize != 0) { 229 ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize); 230 isRead = substrate.read(offset, compressedBuffer, compressedSize, 231 uncompressedBuffer, uncompressedSize); 232 ImageBufferCache.releaseBuffer(compressedBuffer); 233 } else { 234 isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize); 235 } 236 237 if (isRead) { 238 return uncompressedBuffer; 239 } else { 240 ImageBufferCache.releaseBuffer(uncompressedBuffer); 241 242 return null; 243 } 244 } 245 246 public ByteBuffer getResourceBuffer(String name) { 247 ImageLocation location = findLocation(name); 248 249 return location != null ? getResourceBuffer(location) : null; 250 } 251 252 public InputStream getResourceStream(ImageLocation loc) { 253 byte[] bytes = getResource(loc); 254 255 return new ByteArrayInputStream(bytes); 256 } 257 258 public InputStream getResourceStream(String name) { 259 ImageLocation location = findLocation(name); 260 261 return location != null ? getResourceStream(location) : null; 262 } 263 }