1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.inputmethod.keyboard.tools;
18
19import java.io.Closeable;
20import java.io.IOException;
21import java.io.InputStream;
22import java.io.UnsupportedEncodingException;
23import java.net.URL;
24import java.net.URLDecoder;
25import java.util.ArrayList;
26import java.util.Enumeration;
27import java.util.Locale;
28import java.util.jar.JarEntry;
29import java.util.jar.JarFile;
30
31public final class JarUtils {
32    private JarUtils() {
33        // This utility class is not publicly instantiable.
34    }
35
36    public static JarFile getJarFile(final Class<?> mainClass) {
37        final String mainClassPath = "/" + mainClass.getName().replace('.', '/') + ".class";
38        final URL resUrl = mainClass.getResource(mainClassPath);
39        if (!resUrl.getProtocol().equals("jar")) {
40            throw new RuntimeException("Should run as jar");
41        }
42        final String path = resUrl.getPath();
43        if (!path.startsWith("file:")) {
44            throw new RuntimeException("Unknown jar path: " + path);
45        }
46        final String jarPath = path.substring("file:".length(), path.indexOf('!'));
47        try {
48            return new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
49        } catch (UnsupportedEncodingException e) {
50        } catch (IOException e) {
51        }
52        return null;
53    }
54
55    public static InputStream openResource(final String name) {
56        return JarUtils.class.getResourceAsStream("/" + name);
57    }
58
59    public interface JarFilter {
60        public boolean accept(String dirName, String name);
61    }
62
63    public static ArrayList<String> getEntryNameListing(final JarFile jar, final JarFilter filter) {
64        final ArrayList<String> result = new ArrayList<>();
65        final Enumeration<JarEntry> entries = jar.entries();
66        while (entries.hasMoreElements()) {
67            final JarEntry entry = entries.nextElement();
68            final String path = entry.getName();
69            final int pos = path.lastIndexOf('/');
70            final String dirName = (pos >= 0) ? path.substring(0, pos) : "";
71            final String name = (pos >= 0) ? path.substring(pos + 1) : path;
72            if (filter.accept(dirName, name)) {
73                result.add(path);
74            }
75        }
76        return result;
77    }
78
79    public static ArrayList<String> getEntryNameListing(final JarFile jar,
80            final String filterName) {
81        return getEntryNameListing(jar, new JarFilter() {
82            @Override
83            public boolean accept(final String dirName, final String name) {
84                return name.equals(filterName);
85            }
86        });
87    }
88
89    // The locale is taken from string resource jar entry name (values-<locale>/)
90    // or {@link LocaleUtils#DEFAULT_LOCALE} for the default string resource
91    // directory (values/).
92    public static Locale getLocaleFromEntryName(final String jarEntryName) {
93        final String dirName = jarEntryName.substring(0, jarEntryName.lastIndexOf('/'));
94        final int pos = dirName.lastIndexOf('/');
95        final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName;
96        final int localePos = parentName.indexOf('-');
97        if (localePos < 0) {
98            // Default resource name.
99            return LocaleUtils.DEFAULT_LOCALE;
100        }
101        final String localeStr = parentName.substring(localePos + 1);
102        final int regionPos = localeStr.indexOf("-r");
103        if (regionPos < 0) {
104            return LocaleUtils.constructLocaleFromString(localeStr);
105        }
106        return LocaleUtils.constructLocaleFromString(localeStr.replace("-r", "_"));
107    }
108
109    public static void close(final Closeable stream) {
110        try {
111            if (stream != null) {
112                stream.close();
113            }
114        } catch (IOException e) {
115        }
116    }
117}
118