diff --git a/src/main/java/io/github/eb4j/ebview/dictionary/LingvoDSL.java b/src/main/java/io/github/eb4j/ebview/dictionary/LingvoDSL.java index c4dda08..c3b35d5 100644 --- a/src/main/java/io/github/eb4j/ebview/dictionary/LingvoDSL.java +++ b/src/main/java/io/github/eb4j/ebview/dictionary/LingvoDSL.java @@ -23,11 +23,19 @@ import io.github.eb4j.dsl.visitor.HtmlDslVisitor; import io.github.eb4j.ebview.data.DictionaryEntry; import io.github.eb4j.ebview.data.IDictionary; +import io.github.eb4j.ebview.utils.Platform; +import org.apache.commons.lang3.StringUtils; import java.io.File; import java.io.IOException; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -46,9 +54,7 @@ public boolean isSupportedFile(final File file) { @Override public Set loadDict(final File file) throws Exception { - Set result = new HashSet<>(); - result.add(new LingvoDSLDictionary(file)); - return result; + return Collections.singleton(new LingvoDSLDictionary(file)); } /** @@ -62,10 +68,41 @@ public static class LingvoDSLDictionary implements IDictionary { private final HtmlDslVisitor htmlVisitor; public LingvoDSLDictionary(final File file) throws Exception { - dictionary = DslDictionary.loadDictionary(file); + Path dictPath = Paths.get(file.toURI()); + Path cachePath = getDictCachePath(dictPath); + dictionary = DslDictionary.loadDictionary(dictPath, cachePath, true); htmlVisitor = new HtmlDslVisitor(file.getParent()); } + private Path enforceCachePath(Path cachePath) { + if (!cachePath.getParent().toFile().exists()) { + boolean result = cachePath.getParent().toFile().mkdirs(); + if (!result) { + return null; + } + } + return cachePath; + } + + private Path getDictCachePath(Path dictpath) { + String cacheDir = Platform.getCacheDir(); + if (StringUtils.isEmpty(cacheDir)) { + return null; + } + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + digest.update(dictpath.toString().getBytes(StandardCharsets.UTF_8)); + String hash = String.format("%020x", new BigInteger(1, digest.digest())); + Path filename = dictpath.getFileName(); + if (filename == null) { + return null; + } + return enforceCachePath(Paths.get(cacheDir, hash).resolve(filename + ".idx")); + } catch (NoSuchAlgorithmException ex) { + return null; + } + } + @Override public String getDictionaryName() { return dictionary.getDictionaryName(); diff --git a/src/main/java/io/github/eb4j/ebview/utils/Platform.java b/src/main/java/io/github/eb4j/ebview/utils/Platform.java index 4fa2ab2..a2ec5d4 100644 --- a/src/main/java/io/github/eb4j/ebview/utils/Platform.java +++ b/src/main/java/io/github/eb4j/ebview/utils/Platform.java @@ -19,7 +19,188 @@ package io.github.eb4j.ebview.utils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + public final class Platform { + + static final Logger LOG = LoggerFactory.getLogger(Platform.class.getName()); + /** + * Configuration directory on Windows platforms + */ + private static final String WINDOWS_CONFIG_DIR = "\\ebviewer\\"; + private static final String WINDOWS_CACHE_DIR = "\\wbviewer\\"; + /** + * Configuration directory on UNIX platforms + */ + private static final String UNIX_CONFIG_DIR = "/.config/ebviewer/"; + private static final String UNIX_CACHE_DIR = "/.cache/ebviewer/"; + /** + * Configuration directory on Mac OS X + */ + private static final String OSX_CONFIG_DIR = "/Library/Preferences/ebviewer/"; + private static final String OSX_CACHE_DIR = "/Library/Caches/ebviewer/"; + /** + * Contains the location of the directory containing the configuration + * files. + */ + private static String configDir = null; + /** + * Contains the location of the directory containing caches. + */ + private static String cacheDir = null; + + private final static String NOCACHE = "-no-cache-"; + + /** + * Returns the location of the configuration directory, depending on the + * user's platform. Also creates the configuration directory, if necessary. + * If any problems occur while the location of the configuration directory + * is being determined, an empty string will be returned, resulting in the + * current working directory being used. + * + * + * + * @return The full path of the directory containing the configuration files, including trailing path separator. + */ + public static String getConfigDir() { + // if the configuration directory has already been determined, return it + if (configDir != null) { + return configDir; + } + + OsType os = getOsType(); // name of operating system + String home; // user home directory + + // get os and user home properties + try { + // get the user's home directory + home = System.getProperty("user.home"); + } catch (SecurityException e) { + // access to the os/user home properties is restricted, + // the location of the config dir cannot be determined, + // set the config dir to the current working dir + configDir = new File(".").getAbsolutePath() + File.separator; + + // log the exception, only do this after the config dir + // has been set to the current working dir, otherwise + // the log method will probably fail + LOG.error(e.toString()); + + return configDir; + } + + // if os or user home is null or empty, we cannot reliably determine + // the config dir, so we use the current working dir (= empty string) + if (os == null || StringUtils.isEmpty(home)) { + // set the config dir to the current working dir + configDir = new File(".").getAbsolutePath() + File.separator; + return configDir; + } + + if (isWindows()) { + String appData = new File(home, "AppData\\Roaming").getAbsolutePath(); + if (!StringUtils.isEmpty(appData)) { + configDir = appData + WINDOWS_CONFIG_DIR; + } else { + configDir = home + WINDOWS_CONFIG_DIR; + } + } else if (isLinux() || os == OsType.OTHER) { + configDir = home + UNIX_CONFIG_DIR; + } else if (isMacOSX()) { + configDir = home + OSX_CONFIG_DIR; + } else { + configDir = home + File.separator; + } + + // create the path to the configuration dir, if necessary + if (!configDir.isEmpty()) { + try { + // check if the dir exists + File dir = new File(configDir); + if (!dir.exists()) { + // create the dir + boolean created = dir.mkdirs(); + + // if the dir could not be created, + // set the config dir to the current working dir + if (!created) { + configDir = new File(".").getAbsolutePath() + File.separator; + } + } + } catch (SecurityException e) { + // the system doesn't want us to write where we want to write + // reset the config dir to the current working dir + configDir = new File(".").getAbsolutePath() + File.separator; + + // log the exception, but only after the config dir has been + // reset + LOG.error(e.toString()); + } + } + + // we should have a correct, existing config dir now + return configDir; + } + + public static String getCacheDir() { + // if the configuration directory has already been determined, return it + if (cacheDir != null) { + if (cacheDir.equals(NOCACHE)) { + return null; + } + return cacheDir; + } + + String home; + try { + home = System.getProperty("user.home"); + } catch (SecurityException e) { + // access to the os/user home properties is restricted, + cacheDir = NOCACHE; + return cacheDir; + } + if (isWindows()) { + String appData = new File(home, "AppData\\LocalLow").getAbsolutePath(); + if (!StringUtils.isEmpty(appData)) { + cacheDir = appData + WINDOWS_CACHE_DIR; + } else { + cacheDir = home + WINDOWS_CACHE_DIR; + } + } else if (isLinux() || getOsType() == OsType.OTHER) { + cacheDir = home + UNIX_CACHE_DIR; + } else if (isMacOSX()) { + cacheDir = home + OSX_CACHE_DIR; + } else { + cacheDir = NOCACHE; + } + + if (!cacheDir.equals(NOCACHE)) { + try { + File dir = new File(cacheDir); + if (!dir.exists()) { + boolean created = dir.mkdirs(); + if (!created) { + cacheDir = NOCACHE; + } + } + } catch (SecurityException e) { + cacheDir = NOCACHE; + } + } + return cacheDir; + } + public enum OsType { // os.arch=amd64, os.name=Linux, os.version=3.0.0-12-generic LINUX64, diff --git a/src/main/java/io/github/eb4j/ebview/utils/Preferences.java b/src/main/java/io/github/eb4j/ebview/utils/Preferences.java index 8890ca8..444d406 100644 --- a/src/main/java/io/github/eb4j/ebview/utils/Preferences.java +++ b/src/main/java/io/github/eb4j/ebview/utils/Preferences.java @@ -29,39 +29,13 @@ package io.github.eb4j.ebview.utils; import com.fasterxml.jackson.core.JsonProcessingException; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.File; public final class Preferences { - static final Logger LOG = LoggerFactory.getLogger(Preferences.class.getName()); - - /** - * Configuration directory on Windows platforms - */ - private static final String WINDOWS_CONFIG_DIR = "\\ebviewer\\"; - - /** - * Configuration directory on UNIX platforms - */ - private static final String UNIX_CONFIG_DIR = "/.config/ebviewer/"; - - /** - * Configuration directory on Mac OS X - */ - private static final String OSX_CONFIG_DIR = "/Library/Preferences/ebviewer/"; - public static final String FILE_PREFERENCES = "ebviewer.prefs"; - /** - * Contains the location of the directory containing the configuration - * files. - */ - private static String configDir = null; - /** Private constructor, because this file is singleton */ private Preferences() { } @@ -117,125 +91,15 @@ public static void init() throws JsonProcessingException { } didInit = true; File loadFile = getPreferencesFile(); - File saveFile = new File(getConfigDir(), Preferences.FILE_PREFERENCES); + File saveFile = new File(Platform.getConfigDir(), Preferences.FILE_PREFERENCES); preferences = new PreferencesImpl(loadFile, saveFile); } private static IPreferences preferences; private static volatile boolean didInit = false; - - /** - * Returns the location of the configuration directory, depending on the - * user's platform. Also creates the configuration directory, if necessary. - * If any problems occur while the location of the configuration directory - * is being determined, an empty string will be returned, resulting in the - * current working directory being used. - * - * - * - * @return The full path of the directory containing the configuration files, including trailing path separator. - */ - public static String getConfigDir() { - // if the configuration directory has already been determined, return it - if (configDir != null) { - return configDir; - } - - Platform.OsType os = Platform.getOsType(); // name of operating system - String home; // user home directory - - // get os and user home properties - try { - // get the user's home directory - home = System.getProperty("user.home"); - } catch (SecurityException e) { - // access to the os/user home properties is restricted, - // the location of the config dir cannot be determined, - // set the config dir to the current working dir - configDir = new File(".").getAbsolutePath() + File.separator; - - // log the exception, only do this after the config dir - // has been set to the current working dir, otherwise - // the log method will probably fail - LOG.error(e.toString()); - - return configDir; - } - - // if os or user home is null or empty, we cannot reliably determine - // the config dir, so we use the current working dir (= empty string) - if (os == null || StringUtils.isEmpty(home)) { - // set the config dir to the current working dir - configDir = new File(".").getAbsolutePath() + File.separator; - return configDir; - } - - // check for Windows versions - if (Platform.isWindows()) { - String appData = null; - File appDataFile = new File(home, "AppData\\Roaming"); - if (appDataFile.exists()) { - appData = appDataFile.getAbsolutePath(); - } else { - appDataFile = new File(home, "Application Data"); - if (appDataFile.exists()) { - appData = appDataFile.getAbsolutePath(); - } - } - - if (!StringUtils.isEmpty(appData)) { - configDir = appData + WINDOWS_CONFIG_DIR; - } else { - configDir = home + WINDOWS_CONFIG_DIR; - } - } else if (Platform.isLinux() || os == Platform.OsType.OTHER) { - configDir = home + UNIX_CONFIG_DIR; - } else if (Platform.isMacOSX()) { - configDir = home + OSX_CONFIG_DIR; - } else { - configDir = home + File.separator; - } - - // create the path to the configuration dir, if necessary - if (!configDir.isEmpty()) { - try { - // check if the dir exists - File dir = new File(configDir); - if (!dir.exists()) { - // create the dir - boolean created = dir.mkdirs(); - - // if the dir could not be created, - // set the config dir to the current working dir - if (!created) { - configDir = new File(".").getAbsolutePath() + File.separator; - } - } - } catch (SecurityException e) { - // the system doesn't want us to write where we want to write - // reset the config dir to the current working dir - configDir = new File(".").getAbsolutePath() + File.separator; - - // log the exception, but only after the config dir has been - // reset - LOG.error(e.toString()); - } - } - - // we should have a correct, existing config dir now - return configDir; - } - private static File getPreferencesFile() { - File prefsFile = new File(getConfigDir(), FILE_PREFERENCES); + File prefsFile = new File(Platform.getConfigDir(), FILE_PREFERENCES); if (prefsFile.exists()) { return prefsFile; }