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;
27d317796207d9c9443669ff94aac63c4193ec0e6fTadashi G. Takaokaimport java.util.Locale;
282be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.jar.JarEntry;
292be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.jar.JarFile;
302be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
311e11c44d1b5f9ddf593c5407cb14c458be0056f2Tadashi G. Takaokapublic final class JarUtils {
322be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    private JarUtils() {
332be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        // This utility class is not publicly instantiable.
342be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
352be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
369c9802e6473e5e2e2b792d5f14502139feb49637Tadashi G. Takaoka    public static JarFile getJarFile(final Class<?> mainClass) {
379c9802e6473e5e2e2b792d5f14502139feb49637Tadashi G. Takaoka        final String mainClassPath = "/" + mainClass.getName().replace('.', '/') + ".class";
389c9802e6473e5e2e2b792d5f14502139feb49637Tadashi G. Takaoka        final URL resUrl = mainClass.getResource(mainClassPath);
392be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        if (!resUrl.getProtocol().equals("jar")) {
402be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            throw new RuntimeException("Should run as jar");
412be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        }
422be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        final String path = resUrl.getPath();
432be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        if (!path.startsWith("file:")) {
442be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            throw new RuntimeException("Unknown jar path: " + path);
452be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        }
462be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        final String jarPath = path.substring("file:".length(), path.indexOf('!'));
472be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        try {
482be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            return new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
492be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        } catch (UnsupportedEncodingException e) {
502be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        } catch (IOException e) {
512be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        }
522be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        return null;
532be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
542be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
552be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    public static InputStream openResource(final String name) {
562be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        return JarUtils.class.getResourceAsStream("/" + name);
572be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
582be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
592be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    public interface JarFilter {
602be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        public boolean accept(String dirName, String name);
612be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
622be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
63465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    public static ArrayList<String> getEntryNameListing(final JarFile jar, final JarFilter filter) {
64a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka        final ArrayList<String> result = new ArrayList<>();
652be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        final Enumeration<JarEntry> entries = jar.entries();
662be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        while (entries.hasMoreElements()) {
672be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            final JarEntry entry = entries.nextElement();
682be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            final String path = entry.getName();
692be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            final int pos = path.lastIndexOf('/');
702be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            final String dirName = (pos >= 0) ? path.substring(0, pos) : "";
712be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            final String name = (pos >= 0) ? path.substring(pos + 1) : path;
722be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            if (filter.accept(dirName, name)) {
732be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka                result.add(path);
742be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            }
752be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        }
762be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        return result;
772be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
782be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka
79465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    public static ArrayList<String> getEntryNameListing(final JarFile jar,
80465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka            final String filterName) {
81465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        return getEntryNameListing(jar, new JarFilter() {
822be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            @Override
832be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            public boolean accept(final String dirName, final String name) {
842be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka                return name.equals(filterName);
852be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka            }
862be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka        });
872be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka    }
88465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka
896bb3556ff7b24a5a38d7cc4276017bda3a9a4bbaTadashi G. Takaoka    // The locale is taken from string resource jar entry name (values-<locale>/)
90d317796207d9c9443669ff94aac63c4193ec0e6fTadashi G. Takaoka    // or {@link LocaleUtils#DEFAULT_LOCALE} for the default string resource
91465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    // directory (values/).
92d317796207d9c9443669ff94aac63c4193ec0e6fTadashi G. Takaoka    public static Locale getLocaleFromEntryName(final String jarEntryName) {
93465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        final String dirName = jarEntryName.substring(0, jarEntryName.lastIndexOf('/'));
94465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        final int pos = dirName.lastIndexOf('/');
95465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName;
966bb3556ff7b24a5a38d7cc4276017bda3a9a4bbaTadashi G. Takaoka        final int localePos = parentName.indexOf('-');
976bb3556ff7b24a5a38d7cc4276017bda3a9a4bbaTadashi G. Takaoka        if (localePos < 0) {
98465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka            // Default resource name.
99d317796207d9c9443669ff94aac63c4193ec0e6fTadashi G. Takaoka            return LocaleUtils.DEFAULT_LOCALE;
100465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        }
101d317796207d9c9443669ff94aac63c4193ec0e6fTadashi G. Takaoka        final String localeStr = parentName.substring(localePos + 1);
102d317796207d9c9443669ff94aac63c4193ec0e6fTadashi G. Takaoka        final int regionPos = localeStr.indexOf("-r");
1036bb3556ff7b24a5a38d7cc4276017bda3a9a4bbaTadashi G. Takaoka        if (regionPos < 0) {
104d317796207d9c9443669ff94aac63c4193ec0e6fTadashi G. Takaoka            return LocaleUtils.constructLocaleFromString(localeStr);
105465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        }
106d317796207d9c9443669ff94aac63c4193ec0e6fTadashi G. Takaoka        return LocaleUtils.constructLocaleFromString(localeStr.replace("-r", "_"));
107465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    }
108465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka
109465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    public static void close(final Closeable stream) {
110465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        try {
111465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka            if (stream != null) {
112465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka                stream.close();
113465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka            }
114465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        } catch (IOException e) {
115465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka        }
116465a2ac534bf5c0dea38608dbe713ed3a9dc84ebTadashi G. Takaoka    }
1172be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka}
118