< prev index next >

src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java

Print this page

        

@@ -22,67 +22,92 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
 package jdk.internal.jimage;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.File;
+import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.IntBuffer;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import java.util.Comparator;
+import java.util.stream.IntStream;
 
 public class BasicImageReader {
     private final String imagePath;
-    private final PReader preader;
+    private final ImageSubstrate substrate;
     private final ByteOrder byteOrder;
-    private final ImageHeader header;
-    private final int indexSize;
-    private final IntBuffer redirectBuffer;
-    private final IntBuffer offsetsBuffer;
-    private final ByteBuffer locationsBuffer;
-    private final ByteBuffer stringsBuffer;
-    private final ImageStrings strings;
+    private final ImageStringsReader strings;
 
-    protected BasicImageReader(String imagePath, ByteOrder byteOrder) throws IOException {
+    protected BasicImageReader(String imagePath, ByteOrder byteOrder)
+            throws IOException {
         this.imagePath = imagePath;
-        this.preader = PReader.open(imagePath);
+        this.substrate = openImageSubstrate(imagePath, byteOrder);
         this.byteOrder = byteOrder;
-        this.header = ImageHeader.readFrom(byteOrder, getIntBuffer(0, ImageHeader.getHeaderSize()));
-        this.indexSize = header.getIndexSize();
-        this.redirectBuffer = getIntBuffer(header.getRedirectOffset(), header.getRedirectSize());
-        this.offsetsBuffer = getIntBuffer(header.getOffsetsOffset(), header.getOffsetsSize());
-        this.locationsBuffer = getByteBuffer(header.getLocationsOffset(), header.getLocationsSize());
-        this.stringsBuffer = getByteBuffer(header.getStringsOffset(), header.getStringsSize());
-        this.strings = new ImageStrings(new ImageStream(stringsBuffer));
+        this.strings = new ImageStringsReader(this);
     }
 
     protected BasicImageReader(String imagePath) throws IOException {
         this(imagePath, ByteOrder.nativeOrder());
     }
 
+    private static ImageSubstrate openImageSubstrate(String imagePath, ByteOrder byteOrder)
+            throws IOException {
+        ImageSubstrate substrate;
+
+        try {
+            substrate = ImageNativeSubstrate.openImage(imagePath, byteOrder);
+        } catch (UnsatisfiedLinkError ex) {
+            substrate = ImageJavaSubstrate.openImage(imagePath, byteOrder);
+        }
+
+        return substrate;
+    }
+
     public static BasicImageReader open(String imagePath) throws IOException {
         return new BasicImageReader(imagePath, ByteOrder.nativeOrder());
     }
 
+    public static void releaseByteBuffer(ByteBuffer buffer) {
+        ImageBufferCache.releaseBuffer(buffer);
+    }
+
+    public ByteOrder getByteOrder() {
+        return byteOrder;
+    }
+
     public String imagePath() {
         return imagePath;
     }
 
+    public String imagePathName() {
+        int slash = imagePath().lastIndexOf(File.separator);
+
+        if (slash != -1) {
+            return imagePath().substring(slash + 1);
+        }
+
+        return imagePath();
+    }
+
     public boolean isOpen() {
-        return preader.isOpen();
+        return true;
     }
 
     public void close() throws IOException {
-        preader.close();
+        substrate.close();
+    }
+
+    public ImageHeader getHeader() throws IOException {
+        return ImageHeader.readFrom(
+                getIndexIntBuffer(0, ImageHeader.getHeaderSize()));
     }
 
-    public ImageHeader getHeader() {
-        return header;
+    public ImageStringsReader getStrings() {
+        return strings;
     }
 
     public ImageLocation findLocation(String name) {
         return findLocation(new UTF8String(name));
     }

@@ -90,150 +115,149 @@
     public ImageLocation findLocation(byte[] name) {
         return findLocation(new UTF8String(name));
     }
 
     public synchronized ImageLocation findLocation(UTF8String name) {
-        int count = header.getLocationCount();
-        int hash = name.hashCode() % count;
-        int redirect = getRedirect(hash);
-
-        if (redirect == 0) {
-            return null;
+        return substrate.findLocation(name, strings);
         }
 
-        int index;
-
-        if (redirect < 0) {
-            // If no collision.
-            index = -redirect - 1;
-        } else {
-            // If collision, recompute hash code.
-            index = name.hashCode(redirect) % count;
+    public String[] getEntryNames() {
+        return IntStream.of(substrate.attributeOffsets())
+                        .filter(o -> o != 0)
+                        .mapToObj(o -> ImageLocation.readFrom(this, o).getFullNameString())
+                        .sorted()
+                        .toArray(String[]::new);
         }
 
-        int offset = getOffset(index);
-
-        if (offset == 0) {
-            return null;
+    protected ImageLocation[] getAllLocations(boolean sorted) {
+        return IntStream.of(substrate.attributeOffsets())
+                        .filter(o -> o != 0)
+                        .mapToObj(o -> ImageLocation.readFrom(this, o))
+                        .sorted(Comparator.comparing(ImageLocation::getFullNameString))
+                        .toArray(ImageLocation[]::new);
         }
 
-        ImageLocation location = getLocation(offset);
+    private IntBuffer getIndexIntBuffer(long offset, long size)
+            throws IOException {
+        ByteBuffer buffer = substrate.getIndexBuffer(offset, size);
+        buffer.order(byteOrder);
 
-        return location.verify(name) ? location : null;
+        return buffer.asIntBuffer();
     }
 
-    public String[] getEntryNames() {
-        return getEntryNames(true);
+    ImageLocation getLocation(int offset) {
+        return ImageLocation.readFrom(this, offset);
     }
 
-    public String[] getEntryNames(boolean sorted) {
-        int count = header.getLocationCount();
-        List<String> list = new ArrayList<>();
-
-        for (int i = 0; i < count; i++) {
-            int offset = getOffset(i);
-
-            if (offset != 0) {
-                ImageLocation location = ImageLocation.readFrom(locationsBuffer, offset, strings);
-                list.add(location.getFullnameString());
-            }
+    public long[] getAttributes(int offset) {
+        return substrate.getAttributes(offset);
         }
 
-        String[] array = list.toArray(new String[0]);
-
-        if (sorted) {
-            Arrays.sort(array);
+    public String getString(int offset) {
+        return getUTF8String(offset).toString();
         }
 
-        return array;
+    public UTF8String getUTF8String(int offset) {
+        return new UTF8String(substrate.getStringBytes(offset));
     }
 
-    protected ImageLocation[] getAllLocations(boolean sorted) {
-        int count = header.getLocationCount();
-        List<ImageLocation> list = new ArrayList<>();
-
-        for (int i = 0; i < count; i++) {
-            int offset = getOffset(i);
+    private byte[] getBufferBytes(ByteBuffer buffer, long size) {
+        assert size < Integer.MAX_VALUE;
+        byte[] bytes = new byte[(int)size];
+        buffer.get(bytes);
 
-            if (offset != 0) {
-                ImageLocation location = ImageLocation.readFrom(locationsBuffer, offset, strings);
-                list.add(location);
-            }
+        return bytes;
         }
 
-        ImageLocation[] array = list.toArray(new ImageLocation[0]);
+    private byte[] getBufferBytes(long offset, long size) {
+        ByteBuffer buffer = substrate.getDataBuffer(offset, size);
 
-        if (sorted) {
-            Arrays.sort(array, (ImageLocation loc1, ImageLocation loc2) ->
-                    loc1.getFullnameString().compareTo(loc2.getFullnameString()));
+        return getBufferBytes(buffer, size);
         }
 
-        return array;
+    public byte[] getResource(ImageLocation loc) {
+        long offset = loc.getContentOffset();
+        long compressedSize = loc.getCompressedSize();
+        long uncompressedSize = loc.getUncompressedSize();
+        assert compressedSize < Integer.MAX_VALUE;
+        assert uncompressedSize < Integer.MAX_VALUE;
+
+        if (substrate.supportsDataBuffer() && compressedSize == 0) {
+            return getBufferBytes(offset, uncompressedSize);
     }
 
-    private IntBuffer getIntBuffer(long offset, long size) throws IOException {
-        MappedByteBuffer buffer = preader.channel().map(FileChannel.MapMode.READ_ONLY, offset, size);
-        buffer.order(byteOrder);
+        ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize);
+        boolean isRead;
 
-        return buffer.asIntBuffer();
+        if (compressedSize != 0) {
+            ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize);
+            isRead = substrate.read(offset, compressedBuffer, compressedSize,
+                                          uncompressedBuffer, uncompressedSize);
+            ImageBufferCache.releaseBuffer(compressedBuffer);
+        } else {
+            isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize);
     }
 
-    private ByteBuffer getByteBuffer(long offset, long size) throws IOException {
-        MappedByteBuffer buffer = preader.channel().map(FileChannel.MapMode.READ_ONLY, offset, size);
-        // order is not copied into the readonly copy.
-        ByteBuffer readOnly = buffer.asReadOnlyBuffer();
-        readOnly.order(byteOrder);
-        return readOnly;
-    }
+        byte[] bytes = isRead ? getBufferBytes(uncompressedBuffer,
+                                               uncompressedSize) : null;
 
-    private int getRedirect(int index) {
-        return redirectBuffer.get(index);
-    }
+        ImageBufferCache.releaseBuffer(uncompressedBuffer);
 
-    private int getOffset(int index) {
-        return offsetsBuffer.get(index);
+        return bytes;
     }
 
-    private ImageLocation getLocation(int offset) {
-        return ImageLocation.readFrom(locationsBuffer, offset, strings);
-    }
+    public byte[] getResource(String name) {
+        ImageLocation location = findLocation(name);
 
-    public String getString(int offset) {
-        return strings.get(offset).toString();
+        return location != null ? getResource(location) : null;
     }
 
-    public byte[] getResource(ImageLocation loc) throws IOException {
+    public ByteBuffer getResourceBuffer(ImageLocation loc) {
+        long offset = loc.getContentOffset();
         long compressedSize = loc.getCompressedSize();
+        long uncompressedSize = loc.getUncompressedSize();
         assert compressedSize < Integer.MAX_VALUE;
+        assert uncompressedSize < Integer.MAX_VALUE;
 
-        if (compressedSize == 0) {
-            return preader.read((int)loc.getUncompressedSize(),
-                                indexSize + loc.getContentOffset());
-        } else {
-            byte[] buf = preader.read((int)compressedSize,
-                                      indexSize + loc.getContentOffset());
-            return ImageFile.Compressor.decompress(buf);
+        if (substrate.supportsDataBuffer() && compressedSize == 0) {
+            return substrate.getDataBuffer(offset, uncompressedSize);
         }
+
+        ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize);
+        boolean isRead;
+
+        if (compressedSize != 0) {
+            ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize);
+            isRead = substrate.read(offset, compressedBuffer, compressedSize,
+                                          uncompressedBuffer, uncompressedSize);
+            ImageBufferCache.releaseBuffer(compressedBuffer);
+        } else {
+            isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize);
     }
 
-    public byte[] getResource(String name) throws IOException {
-        ImageLocation location = findLocation(name);
+        if (isRead) {
+            return uncompressedBuffer;
+        } else {
+            ImageBufferCache.releaseBuffer(uncompressedBuffer);
 
-        return location != null ? getResource(location) : null;
+            return null;
+        }
     }
 
-    public List<String> getNames(String name) throws IOException {
-        return getNames(getResource(name));
+    public ByteBuffer getResourceBuffer(String name) {
+        ImageLocation location = findLocation(name);
+
+        return location != null ? getResourceBuffer(location) : null;
     }
 
-    public List<String> getNames(byte[] bytes) {
-        IntBuffer buffer = ByteBuffer.wrap(bytes).asIntBuffer();
-        List<String> names = new ArrayList<>();
+    public InputStream getResourceStream(ImageLocation loc) {
+        byte[] bytes = getResource(loc);
 
-        while (buffer.hasRemaining()) {
-            int offset = buffer.get();
-            names.add(getString(offset));
+        return new ByteArrayInputStream(bytes);
         }
 
-        return names;
+    public InputStream getResourceStream(String name) {
+        ImageLocation location = findLocation(name);
+
+        return location != null ? getResourceStream(location) : null;
     }
 }
< prev index next >