1 /*
   2  * Copyright (c) 2009, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 package com.sun.classanalyzer;
  25 
  26 import java.io.BufferedReader;
  27 import java.io.File;
  28 import java.io.IOException;
  29 import java.io.InputStream;
  30 import java.io.InputStreamReader;
  31 import java.util.ArrayList;
  32 import java.util.Collections;
  33 import java.util.List;
  34 import java.util.Set;
  35 import java.util.TreeSet;
  36 
  37 /**
  38  *
  39  */
  40 public class ResourceFile implements Comparable<ResourceFile> {
  41     private final String pathname;
  42     private final long filesize;
  43     protected final String name;
  44     private Module module;
  45 
  46     ResourceFile(String fname) {
  47         this(fname, 0);
  48     }
  49 
  50     ResourceFile(String fname, long size) {
  51         this.pathname = fname.replace('/', File.separatorChar);
  52         this.name = fname.replace(File.separatorChar, '/');
  53         this.filesize = size;
  54     }
  55 
  56     Module getModule() {
  57         return module;
  58     }
  59 
  60     void setModule(Module m) {
  61         if (module != null) {
  62             throw new RuntimeException("Module for " + this + " already set");
  63         }
  64         this.module = m;
  65     }
  66 
  67     String getName() {
  68         return name;
  69     }
  70 
  71     String getPathname() {
  72         return pathname;
  73     }
  74 
  75     long getFileSize() {
  76         return filesize;
  77     }
  78 




  79     @Override
  80     public String toString() {
  81         return name;
  82     }
  83 
  84     @Override
  85     public int compareTo(ResourceFile o) {
  86         return name.compareTo(o.name);
  87     }
  88 
  89     private static Set<ResourceFile> resources = new TreeSet<ResourceFile>();
  90 
  91     static boolean isResource(String pathname) {
  92         // skip these files
  93         String name = pathname.replace(File.separatorChar, '/');
  94         if (name.endsWith("META-INF/MANIFEST.MF")) {
  95             return false;
  96         }
  97         if (name.contains("META-INF/JCE_RSA.")) {
  98             return false;
  99         }
 100         if (name.contains("META-INF/") &&
 101                 (name.endsWith(".RSA") || name.endsWith(".SF"))) {
 102             return false;
 103         }
 104 
 105         return true;
 106     }
 107 
 108     static ResourceFile addResource(String fname, InputStream in, long size) {
 109         ResourceFile res;
 110         fname = fname.replace(File.separatorChar, '/');
 111         if (fname.startsWith("META-INF/services")) {
 112             res = new ServiceProviderConfigFile(fname, in, size);
 113         } else {
 114             res = new ResourceFile(fname, size);
 115         }





 116         resources.add(res);
 117         return res;
 118     }
 119 

 120     static Set<ResourceFile> getAllResources() {
 121         return Collections.unmodifiableSet(resources);
 122     }
 123 
 124     static class ServiceProviderConfigFile extends ResourceFile {
 125         final List<String> providers = new ArrayList<String>();
 126         final String service;
 127 
 128         ServiceProviderConfigFile(String fname, InputStream in) {
 129             this(fname, in, 0);
 130         }
 131 
 132         ServiceProviderConfigFile(String fname, InputStream in, long size) {
 133             super(fname, size);
 134             readServiceConfiguration(in, providers);
 135             this.service = name.substring("META-INF/services".length() + 1, name.length());
 136         }
 137 





 138         @Override
 139         String getName() {
 140             if (providers.isEmpty()) {
 141                 return service;
 142             } else {
 143                 // just use the first one for matching
 144                 return providers.get(0);
 145             }
 146         }
 147 
 148         @Override
 149         public boolean equals(Object o) {
 150             if (o instanceof ServiceProviderConfigFile) {
 151                 ServiceProviderConfigFile sp = (ServiceProviderConfigFile) o;
 152                 if (service.equals(sp.service) && providers.size() == sp.providers.size()) {
 153                     List<String> tmp = new ArrayList<String>(providers);
 154                     if (tmp.removeAll(sp.providers)) {
 155                         return tmp.size() == 0;
 156                     }
 157                 }
 158             }
 159             return false;
 160         }
 161 
 162         public int hashCode() {
 163             int hash = 7;
 164             hash = 73 * hash + (this.providers != null ? this.providers.hashCode() : 0);
 165             hash = 73 * hash + (this.service != null ? this.service.hashCode() : 0);
 166             return hash;
 167         }
 168 
 169         @Override
 170         public int compareTo(ResourceFile o) {
 171             if (this.equals(o)) {
 172                 return 0;
 173             } else {
 174                 if (getName().compareTo(o.getName()) < 0) {
 175                     return -1;
 176                 } else {
 177                     return 1;
 178                 }
 179             }
 180         }
 181 
 182         @SuppressWarnings("empty-statement")
 183         void readServiceConfiguration(InputStream in, List<String> names) {
 184             BufferedReader br = null;
 185             try {
 186                 if (in != null) {
 187                     // Properties doesn't perserve the order of the input file
 188                     br = new BufferedReader(new InputStreamReader(in, "utf-8"));
 189                     int lc = 1;
 190                     while ((lc = parseLine(br, lc, names)) >= 0);
 191                 }
 192             } catch (IOException ex) {
 193                 throw new RuntimeException(ex);
 194             } finally {
 195                 if (br != null) {
 196                     try {
 197                         br.close();
 198                     } catch (IOException ex) {
 199                         throw new RuntimeException(ex);
 200                     }
 201                 }
 202             }
 203         }
 204 
 205         // Parse a single line from the given configuration file, adding the name
 206         // on the line to the names list.
 207         //
 208         private int parseLine(BufferedReader r, int lc, List<String> names) throws IOException {
 209             String ln = r.readLine();
 210             if (ln == null) {
 211                 return -1;
 212             }
 213             int ci = ln.indexOf('#');
 214             if (ci >= 0) {
 215                 ln = ln.substring(0, ci);
 216             }
 217             ln = ln.trim();
 218             int n = ln.length();
 219             if (n != 0) {
 220                 if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) {
 221                     throw new RuntimeException("Illegal configuration-file syntax");
 222                 }
 223                 int cp = ln.codePointAt(0);
 224                 if (!Character.isJavaIdentifierStart(cp)) {
 225                     throw new RuntimeException("Illegal provider-class name: " + ln);
 226                 }
 227                 for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
 228                     cp = ln.codePointAt(i);
 229                     if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {
 230                         throw new RuntimeException("Illegal provider-class name: " + ln);
 231                     }
 232                 }
 233                 if (!names.contains(ln)) {
 234                     names.add(ln);
 235                 }
 236             }
 237             return lc + 1;
 238         }
 239     }
 240 }
--- EOF ---