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.IOException; 28 import java.nio.ByteBuffer; 29 import java.nio.ByteOrder; 30 import java.nio.IntBuffer; 31 import java.nio.MappedByteBuffer; 32 import java.nio.channels.FileChannel; 33 import java.util.ArrayList; 34 import java.util.Arrays; 35 import java.util.List; 36 37 public class BasicImageReader { 38 private final String imagePath; 39 private final PReader preader; 40 private final ByteOrder byteOrder; 41 private final ImageHeader header; 42 private final int indexSize; 43 private final IntBuffer redirectBuffer; 44 private final IntBuffer offsetsBuffer; 45 private final ByteBuffer locationsBuffer; 46 private final ByteBuffer stringsBuffer; 47 private final ImageStrings strings; 48 49 protected BasicImageReader(String imagePath, ByteOrder byteOrder) throws IOException { 50 this.imagePath = imagePath; 51 this.preader = PReader.open(imagePath); 52 this.byteOrder = byteOrder; 53 this.header = ImageHeader.readFrom(byteOrder, getIntBuffer(0, ImageHeader.getHeaderSize())); 54 this.indexSize = header.getIndexSize(); 55 this.redirectBuffer = getIntBuffer(header.getRedirectOffset(), header.getRedirectSize()); 56 this.offsetsBuffer = getIntBuffer(header.getOffsetsOffset(), header.getOffsetsSize()); 57 this.locationsBuffer = getByteBuffer(header.getLocationsOffset(), header.getLocationsSize()); 58 this.stringsBuffer = getByteBuffer(header.getStringsOffset(), header.getStringsSize()); 59 this.strings = new ImageStrings(new ImageStream(stringsBuffer)); 60 } 61 62 protected BasicImageReader(String imagePath) throws IOException { 63 this(imagePath, ByteOrder.nativeOrder()); 64 } 65 66 public static BasicImageReader open(String imagePath) throws IOException { 67 return new BasicImageReader(imagePath, ByteOrder.nativeOrder()); 68 } 69 70 public String imagePath() { 71 return imagePath; 72 } 73 74 public boolean isOpen() { 75 return preader.isOpen(); 76 } 77 78 public void close() throws IOException { 79 preader.close(); 80 } 81 82 public ImageHeader getHeader() { 83 return header; 84 } 85 86 public ImageLocation findLocation(String name) { 87 return findLocation(new UTF8String(name)); 88 } 89 90 public ImageLocation findLocation(byte[] name) { 91 return findLocation(new UTF8String(name)); 92 } 93 94 public synchronized ImageLocation findLocation(UTF8String name) { 95 int count = header.getLocationCount(); 96 int hash = name.hashCode() % count; 97 int redirect = getRedirect(hash); 98 99 if (redirect == 0) { 100 return null; 101 } 102 103 int index; 104 105 if (redirect < 0) { 106 // If no collision. 107 index = -redirect - 1; 108 } else { 109 // If collision, recompute hash code. 110 index = name.hashCode(redirect) % count; 111 } 112 113 int offset = getOffset(index); 114 115 if (offset == 0) { 116 return null; 117 } 118 119 ImageLocation location = getLocation(offset); 120 121 return location.verify(name) ? location : null; 122 } 123 124 public String[] getEntryNames() { 125 return getEntryNames(true); 126 } 127 128 public String[] getEntryNames(boolean sorted) { 129 int count = header.getLocationCount(); 130 List<String> list = new ArrayList<>(); 131 132 for (int i = 0; i < count; i++) { 133 int offset = getOffset(i); 134 135 if (offset != 0) { 136 ImageLocation location = ImageLocation.readFrom(locationsBuffer, offset, strings); 137 list.add(location.getFullnameString()); 138 } 139 } 140 141 String[] array = list.toArray(new String[0]); 142 143 if (sorted) { 144 Arrays.sort(array); 145 } 146 147 return array; 148 } 149 150 protected ImageLocation[] getAllLocations(boolean sorted) { 151 int count = header.getLocationCount(); 152 List<ImageLocation> list = new ArrayList<>(); 153 154 for (int i = 0; i < count; i++) { 155 int offset = getOffset(i); 156 157 if (offset != 0) { 158 ImageLocation location = ImageLocation.readFrom(locationsBuffer, offset, strings); 159 list.add(location); 160 } 161 } 162 163 ImageLocation[] array = list.toArray(new ImageLocation[0]); 164 165 if (sorted) { 166 Arrays.sort(array, (ImageLocation loc1, ImageLocation loc2) -> 167 loc1.getFullnameString().compareTo(loc2.getFullnameString())); 168 } 169 170 return array; 171 } 172 173 private IntBuffer getIntBuffer(long offset, long size) throws IOException { 174 MappedByteBuffer buffer = preader.channel().map(FileChannel.MapMode.READ_ONLY, offset, size); 175 buffer.order(byteOrder); 176 177 return buffer.asIntBuffer(); 178 } 179 180 private ByteBuffer getByteBuffer(long offset, long size) throws IOException { 181 MappedByteBuffer buffer = preader.channel().map(FileChannel.MapMode.READ_ONLY, offset, size); 182 // order is not copied into the readonly copy. 183 ByteBuffer readOnly = buffer.asReadOnlyBuffer(); 184 readOnly.order(byteOrder); 185 return readOnly; 186 } 187 188 private int getRedirect(int index) { 189 return redirectBuffer.get(index); 190 } 191 192 private int getOffset(int index) { 193 return offsetsBuffer.get(index); 194 } 195 196 private ImageLocation getLocation(int offset) { 197 return ImageLocation.readFrom(locationsBuffer, offset, strings); 198 } 199 200 public String getString(int offset) { 201 return strings.get(offset).toString(); 202 } 203 204 public byte[] getResource(ImageLocation loc) throws IOException { 205 long compressedSize = loc.getCompressedSize(); 206 assert compressedSize < Integer.MAX_VALUE; 207 208 if (compressedSize == 0) { 209 return preader.read((int)loc.getUncompressedSize(), 210 indexSize + loc.getContentOffset()); 211 } else { 212 byte[] buf = preader.read((int)compressedSize, 213 indexSize + loc.getContentOffset()); 214 return ImageFile.Compressor.decompress(buf); 215 } 216 } 217 218 public byte[] getResource(String name) throws IOException { 219 ImageLocation location = findLocation(name); 220 221 return location != null ? getResource(location) : null; 222 } 223 224 public List<String> getNames(String name) throws IOException { 225 return getNames(getResource(name)); 226 } 227 228 public List<String> getNames(byte[] bytes) { 229 IntBuffer buffer = ByteBuffer.wrap(bytes).asIntBuffer(); 230 List<String> names = new ArrayList<>(); 231 232 while (buffer.hasRemaining()) { 233 int offset = buffer.get(); 234 names.add(getString(offset)); 235 } 236 237 return names; 238 } 239 } | 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 } |