1 /*
   2  * Copyright (c) 2015, 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 jdk.internal.jimage.decompressor.CompressedResourceHeader;
  28 import java.nio.ByteBuffer;
  29 import java.nio.ByteOrder;
  30 import java.util.Collection;
  31 import java.util.Map;
  32 import java.util.Objects;
  33 import java.util.Set;
  34 
  35 /**
  36  * Pool of resources. This class contain the content of a jimage file in the
  37  * matter of Resource.
  38  */
  39 public interface ResourcePool {
  40 
  41     /**
  42      * Resources visitor
  43      */
  44     public interface Visitor {
  45 
  46         /**
  47          * Called for each visited Resource.
  48          *
  49          * @param resource The resource to deal with.
  50          * @param order Byte order
  51          * @param strings
  52          * @return A resource or null if the passed resource is to be removed
  53          * from the jimage.
  54          * @throws Exception
  55          */
  56         public Resource visit(Resource resource, ByteOrder order,
  57                 StringTable strings) throws Exception;
  58     }
  59 
  60     /**
  61      * A JImage Resource. Fully identified by its path.
  62      */
  63     public static class Resource {
  64 
  65         private final String path;
  66         private final ByteBuffer content;
  67 
  68         private final String module;
  69 
  70         public Resource(String path, ByteBuffer content) {
  71             Objects.requireNonNull(path);
  72             Objects.requireNonNull(content);
  73             this.path = path;
  74             this.content = content.asReadOnlyBuffer();
  75             String[] split = ImageFileCreator.splitPath(path);
  76             module = split[0];
  77         }
  78 
  79         public String getPath() {
  80             return path;
  81         }
  82 
  83         public String getModule() {
  84             return module;
  85         }
  86 
  87         /**
  88          * The resource content.
  89          *
  90          * @return A read only buffer.
  91          */
  92         public ByteBuffer getContent() {
  93             return content;
  94         }
  95 
  96         public int getLength() {
  97             return content.limit();
  98         }
  99 
 100         public byte[] getByteArray() {
 101             content.rewind();
 102             byte[] array = new byte[content.remaining()];
 103             content.get(array);
 104             return array;
 105         }
 106 
 107         @Override
 108         public String toString() {
 109             return getPath();
 110         }
 111 
 112         @Override
 113         public boolean equals(Object obj) {
 114             if (!(obj instanceof Resource)) {
 115                 return false;
 116             }
 117             Resource res = (Resource) obj;
 118             return res.path.equals(path);
 119         }
 120 
 121         @Override
 122         public int hashCode() {
 123             int hash = 7;
 124             hash = 53 * hash + Objects.hashCode(this.path);
 125             return hash;
 126         }
 127     }
 128 
 129     /**
 130      * A resource that has been compressed.
 131      */
 132     public static final class CompressedResource extends Resource {
 133 
 134         private final long uncompressed_size;
 135 
 136         private CompressedResource(String path, ByteBuffer content,
 137                 long uncompressed_size) {
 138             super(path, content);
 139             this.uncompressed_size = uncompressed_size;
 140         }
 141 
 142         public long getUncompressedSize() {
 143             return uncompressed_size;
 144         }
 145 
 146         public static CompressedResource newCompressedResource(Resource original,
 147                 ByteBuffer compressed,
 148                 String plugin, String pluginConfig, StringTable strings,
 149                 ByteOrder order) throws Exception {
 150             Objects.requireNonNull(original);
 151             Objects.requireNonNull(compressed);
 152             Objects.requireNonNull(plugin);
 153 
 154             boolean isTerminal = !(original instanceof CompressedResource);
 155             long uncompressed_size = original.getLength();
 156             if (original instanceof CompressedResource) {
 157                 CompressedResource comp = (CompressedResource) original;
 158                 uncompressed_size = comp.getUncompressedSize();
 159             }
 160             int nameOffset = strings.addString(plugin);
 161             int configOffset = -1;
 162             if (pluginConfig != null) {
 163                 configOffset = strings.addString(plugin);
 164             }
 165             CompressedResourceHeader rh =
 166                     new CompressedResourceHeader(compressed.limit(), original.getLength(),
 167                     nameOffset, configOffset, isTerminal);
 168             // Merge header with content;
 169             byte[] h = rh.getBytes(order);
 170             ByteBuffer bb = ByteBuffer.allocate(compressed.limit() + h.length);
 171             bb.order(order);
 172             bb.put(h);
 173             bb.put(compressed);
 174             ByteBuffer contentWithHeader = ByteBuffer.wrap(bb.array());
 175 
 176             CompressedResource compressedResource =
 177                     new CompressedResource(original.getPath(),
 178                     contentWithHeader, uncompressed_size);
 179             return compressedResource;
 180         }
 181     }
 182 
 183     /**
 184      * Read only state.
 185      *
 186      * @return true if readonly false otherwise.
 187      */
 188     public boolean isReadOnly();
 189 
 190     /**
 191      * The byte order
 192      *
 193      * @return
 194      */
 195     public ByteOrder getByteOrder();
 196 
 197     /**
 198      * Add a resource.
 199      *
 200      * @param resource The Resource to add.
 201      * @throws java.lang.Exception If the pool is read only.
 202      */
 203     public void addResource(Resource resource) throws Exception;
 204 
 205     /**
 206      * Check if a resource is contained in the pool.
 207      *
 208      * @param res The resource to check.
 209      * @return true if res is contained, false otherwise.
 210      */
 211     public boolean contains(Resource res);
 212 
 213     /**
 214      * Get all resources contained in this pool instance.
 215      *
 216      * @return The collection of resources;
 217      */
 218     public Collection<Resource> getResources();
 219 
 220     /**
 221      * Get the resource for the passed path.
 222      *
 223      * @param path A resource path
 224      * @return A Resource instance or null if the resource is not found
 225      */
 226     public Resource getResource(String path);
 227 
 228     /**
 229      * The Image modules. It is computed based on the resources contained by
 230      * this ResourcePool instance.
 231      *
 232      * @return The Image Modules.
 233      */
 234     public Map<String, Set<String>> getModulePackages();
 235 
 236     /**
 237      * Check if this pool contains some resources.
 238      *
 239      * @return True if contains some resources.
 240      */
 241     public boolean isEmpty();
 242 
 243     /**
 244      * Visit the resources contained in this ResourcePool.
 245      *
 246      * @param visitor The visitor
 247      * @param output The pool to store resources.
 248      * @param strings
 249      * @throws Exception
 250      */
 251     public void visit(Visitor visitor, ResourcePool output, StringTable strings)
 252             throws Exception;
 253 
 254     public void addTransformedResource(Resource original, ByteBuffer transformed)
 255             throws Exception;
 256 }