JarUtils.java revision 465a2ac534bf5c0dea38608dbe713ed3a9dc84eb
12be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka/*
22be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * Copyright (C) 2012 The Android Open Source Project
32be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka *
42be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
52be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * you may not use this file except in compliance with the License.
62be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * You may obtain a copy of the License at
72be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka *
82be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
92be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka *
102be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
112be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
122be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * See the License for the specific language governing permissions and
142be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * limitations under the License.
152be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka */
162be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
17ca6acfdd6b3400ad6e29d45c29b0ec40ea92a968Tadashi G. Takaokapackage com.android.inputmethod.keyboard.tools;
182be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
19465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaokaimport java.io.Closeable;
202be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.io.IOException;
212be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.io.InputStream;
222be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.io.UnsupportedEncodingException;
232be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.net.URL;
242be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.net.URLDecoder;
252be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.ArrayList;
262be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.Enumeration;
272be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.jar.JarEntry;
282be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.jar.JarFile;
292be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
301e11c44d1b5f9ddf593c5407cb14c458be0056f2Tadashi G. Takaokapublic final class JarUtils {
312be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    private JarUtils() {
322be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        // This utility class is not publicly instantiable.
332be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
342be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
359c9802e6473e5e2e2b792d5f14502139feb49637Tadashi G. Takaoka    public static JarFile getJarFile(final Class<?> mainClass) {
369c9802e6473e5e2e2b792d5f14502139feb49637Tadashi G. Takaoka        final String mainClassPath = "/" + mainClass.getName().replace('.', '/') + ".class";
379c9802e6473e5e2e2b792d5f14502139feb49637Tadashi G. Takaoka        final URL resUrl = mainClass.getResource(mainClassPath);
382be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        if (!resUrl.getProtocol().equals("jar")) {
392be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            throw new RuntimeException("Should run as jar");
402be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        }
412be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        final String path = resUrl.getPath();
422be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        if (!path.startsWith("file:")) {
432be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            throw new RuntimeException("Unknown jar path: " + path);
442be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        }
452be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        final String jarPath = path.substring("file:".length(), path.indexOf('!'));
462be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        try {
472be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            return new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
482be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        } catch (UnsupportedEncodingException e) {
492be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        } catch (IOException e) {
502be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        }
512be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        return null;
522be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
532be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
542be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    public static InputStream openResource(final String name) {
552be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        return JarUtils.class.getResourceAsStream("/" + name);
562be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
572be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
582be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    public interface JarFilter {
592be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        public boolean accept(String dirName, String name);
602be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
612be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
62465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    public static ArrayList<String> getEntryNameListing(final JarFile jar, final JarFilter filter) {
632be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        final ArrayList<String> result = new ArrayList<String>();
642be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        final Enumeration<JarEntry> entries = jar.entries();
652be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        while (entries.hasMoreElements()) {
662be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            final JarEntry entry = entries.nextElement();
672be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            final String path = entry.getName();
682be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            final int pos = path.lastIndexOf('/');
692be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            final String dirName = (pos >= 0) ? path.substring(0, pos) : "";
702be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            final String name = (pos >= 0) ? path.substring(pos + 1) : path;
712be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            if (filter.accept(dirName, name)) {
722be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka                result.add(path);
732be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            }
742be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        }
752be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        return result;
762be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
772be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
78465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    public static ArrayList<String> getEntryNameListing(final JarFile jar,
79465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka            final String filterName) {
80465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        return getEntryNameListing(jar, new JarFilter() {
812be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            @Override
822be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            public boolean accept(final String dirName, final String name) {
832be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka                return name.equals(filterName);
842be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            }
852be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        });
862be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
87465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka
88465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    // The language is taken from string resource jar entry name (values-<language>/)
89465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    // or {@link LocaleUtils#DEFAULT_LANGUAGE_NAME} for the default string resource
90465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    // directory (values/).
91465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    public static String getLanguageFromEntryName(final String jarEntryName) {
92465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        final String dirName = jarEntryName.substring(0, jarEntryName.lastIndexOf('/'));
93465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        final int pos = dirName.lastIndexOf('/');
94465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName;
95465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        final int languagePos = parentName.indexOf('-');
96465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        if (languagePos < 0) {
97465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka            // Default resource name.
98465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka            return LocaleUtils.DEFAULT_LANGUAGE_NAME;
99465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        }
100465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        final String language = parentName.substring(languagePos + 1);
101465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        final int countryPos = language.indexOf("-r");
102465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        if (countryPos < 0) {
103465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka            return language;
104465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        }
105465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        return language.replace("-r", "_");
106465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    }
107465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka
108465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    public static void close(final Closeable stream) {
109465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        try {
110465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka            if (stream != null) {
111465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka                stream.close();
112465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka            }
113465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        } catch (IOException e) {
114465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        }
115465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    }
1162be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka}
117