Major update (UNSTABLE)

- Added preliminary support for loading data from compressed files
  - Added zip entry scanning system
  - Added direct, single-zip-entry language creation
  - Added safe parsing of zip files
This commit is contained in:
Gabriel Tofvesson 2017-01-02 23:31:36 +01:00
parent 3bc6405458
commit 76ebe9f627
3 changed files with 135 additions and 28 deletions

15
.idea/misc.xml generated
View File

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="MavenImportPreferences">
<option name="generalSettings">
<MavenGeneralSettings>
@ -10,17 +7,7 @@
</MavenGeneralSettings>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@ -6,24 +6,50 @@ import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@SuppressWarnings({"WeakerAccess", "unused"})
@SuppressWarnings({"WeakerAccess", "unused", "ConstantConditions", "SameParameterValue"})
public class Language {
private final String language, languageID;
private final String language, languageID, entry;
private Map<String, String> data = new HashMap<>();
private final File f;
private final ZipFile zip;
private Language(ZipFile zip, String entry, String language, String languageID){
this.zip = zip;
this.entry = entry;
this.language = language;
this.languageID = languageID;
this.f = null;
}
private Language(File f, String language, String languageID){
this.f = f;
this.language = language;
this.languageID = languageID;
entry = null;
zip = null;
}
private Language(){
f = null;
language="";
languageID="";
entry = "";
zip = null;
}
private Language(File f, String language, String languageID){ this.f = f; this.language = language; this.languageID = languageID; }
private Language(){ f = null; language=""; languageID=""; }
public String getLanguage(){ return language; }
public String getLanguageIdentifier(){ return languageID; }
public String get(String key) {
if(f==null) return "";
if(f==null && zip==null && (entry==null || (entry!=null && entry.equals("")))) return "";
if(data.containsKey(key) || !f.isFile()) return data.get(key);
try {
InputStream i = new FileInputStream(f);
InputStream i = f!=null?new FileInputStream(f):zip.getInputStream(zip.getEntry(entry));
readLine(i);
String s, s1="";
while(i.available()>0){
@ -70,6 +96,26 @@ public class Language {
!s.equals("0"))?defaultValue:(s.equalsIgnoreCase("true")||s.equals("1"))&&(!s.equalsIgnoreCase("false")||!s.equals("0"));
}
/**
* Parses data aggressively from zip.
* @param zip Zip file to load language data from.
* @param entry Entry in zip file.
* @return Language or null.
*/
public static @Nullable Language safeParse(ZipFile zip, String entry){ return safeParse(zip, entry, true); }
/**
* A safe version of {@link #parse(ZipFile, String, boolean)} that will simply return <b>null</b> if given file isn't a valid language file.
* @param zip Zip file to load language data from.
* @param entry Entry in zip file.
* @param aggressiveLoading Whether or not to aggressively load and handle data.
* @return Language or null.
*/
public static @Nullable Language safeParse(ZipFile zip, String entry, boolean aggressiveLoading){
try{ return parse(zip, entry, aggressiveLoading); }catch(Exception ignored){}
return null;
}
/**
* Parses data aggressively.
* @param f File to read from.
@ -90,11 +136,38 @@ public class Language {
return null;
}
/**
* Parses the given zip entry into a usable language very aggressively.
* @param zip Zip file to load language data from.
* @param entry Entry in zip file.
* @return Language.
* @throws NotALanguageFileException if Zip data isn't a real zip file or entry.
* @throws IOException if data can't be read.
* @throws MalformedLanguageException if language file isn't specified correctly.
*/
public static Language parse(ZipFile zip, String entry) throws NotALanguageFileException, IOException, MalformedLanguageException { return parse(zip, entry, true); }
/**
* Parses the given zip entry into a usable language.
* @param zip Zip file to load language data from.
* @param entry Entry in zip file.
* @param aggressiveParsing Whether or not to aggressively load and handle data.
* @return Language.
* @throws NotALanguageFileException Thrown if file isn't a valid language file.
* @throws IOException if data can't be read.
* @throws MalformedLanguageException if language file isn't specified correctly.
*/
public static Language parse(ZipFile zip, String entry, boolean aggressiveParsing) throws NotALanguageFileException, IOException, MalformedLanguageException {
return parse(zip, entry, null, aggressiveParsing);
}
/**
* Parses the given file into a usable language very aggressively.
* @param f File to parse.
* @return Language.
* @throws NotALanguageFileException Thrown if file isn't a valid language file.
* @throws IOException if data can't be read.
* @throws MalformedLanguageException if language file isn't specified correctly.
*/
public static Language parse(File f) throws NotALanguageFileException, IOException, MalformedLanguageException {
return parse(f, true);
@ -106,17 +179,34 @@ public class Language {
* @param aggressiveParsing Whether or not to aggressively load and handle data.
* @return Language.
* @throws NotALanguageFileException Thrown if file isn't a valid language file.
* @throws IOException if data can't be read.
* @throws MalformedLanguageException if language file isn't specified correctly.
*/
public static Language parse(File f, boolean aggressiveParsing) throws NotALanguageFileException, MalformedLanguageException, IOException {
String s;
public static Language parse(File f, boolean aggressiveParsing) throws NotALanguageFileException, IOException, MalformedLanguageException {
// Is file existent?
if(!f.isFile()) throw new FileNotFoundException("File "+f.getAbsolutePath()+" isn't a file!");
return parse(null, "", f, aggressiveParsing);
}
/**
* Parses the given file or zip entry data into a usable language.
* @param zip Zip file to load language data from.
* @param entry Entry in zip file.
* @param f File to parse.
* @param aggressiveParsing Whether or not to aggressively load and handle data.
* @return Language.
* @throws NotALanguageFileException Thrown if file isn't a valid language file.
* @throws IOException if data can't be read.
* @throws MalformedLanguageException if language file isn't specified correctly.
*/
private static Language parse(ZipFile zip, String entry, File f, boolean aggressiveParsing) throws NotALanguageFileException, MalformedLanguageException, IOException {
String s;
ZipEntry z = zip==null?null:zip.getEntry(entry);
if(z==null && zip!=null) throw new NotALanguageFileException("File "+zip.getName()+":/"+entry+" isn't a file!");
InputStream i = zip==null?new FileInputStream(f):zip.getInputStream(zip.getEntry(entry));
// Does file meet preliminary requirements?
InputStream i = new FileInputStream(f);
s = ignoreSpaces(readLine(i));
i.close();
for(int j=0; j<s.length(); ++j)
@ -131,11 +221,12 @@ public class Language {
if(start==-1 || end==-1 || start>=end) throw new NotALanguageFileException("Malformed language name definition: \""+s+"\"");
Language l = new Language(f, s.substring(start, end), f.getName().substring(0, f.getName().lastIndexOf('.')));
Language l = zip==null ? new Language(f, s.substring(start, end), f.getName().substring(0, f.getName().lastIndexOf('.')))
: new Language(zip, entry, s.substring(start, end), f.getName().substring(0, f.getName().lastIndexOf('.')));
// Check language integrity
ArrayList<String> keys = new ArrayList<>();
i = new FileInputStream(f);
i = zip==null?new FileInputStream(f):zip.getInputStream(zip.getEntry(entry));
String subVerify;
boolean firstLine = true;
char read;
@ -161,7 +252,7 @@ public class Language {
if(subVerify.length()==0 || subVerify.toCharArray().length==0 || subVerify.toCharArray()[0]=='\n') continue;
++lineCount;
if(!isValidKVPair(subVerify)) throw new MalformedLanguageException("Error found at line "+lineCount
+" of "+f.getAbsolutePath()+". Invalid key-value pair detected! Note that ':' in the keys or values must be escaped with '\'");
+" of "+f.getAbsolutePath()+". Invalid key-value pair detected! Note that ':' in the keys or values must be escaped with '\'");
String s1 = getKey(subVerify);
if(keys.contains(s1)) throw new MalformedLanguageException("Error found at line "+lineCount+" : "
+subVerify+"\nDuplicate key detected!");

View File

@ -3,8 +3,11 @@ package com.tofvesson.joe;
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@SuppressWarnings({"WeakerAccess", "unused"})
public class Localization {
@ -12,6 +15,32 @@ public class Localization {
private Language defaultLang;
private List<Language> all = new ArrayList<>();
public Localization(ZipFile zip, String folder, String regexNamingPattern){ this(zip, folder, regexNamingPattern, true); }
public Localization(ZipFile zip, String folder){ this(zip, folder, true); }
public Localization(ZipFile zip, String folder, boolean aggressiveLoading){ this(zip, folder, "(.*)", aggressiveLoading); }
public Localization(ZipFile zip, String folder, String regexNamingPattern, boolean aggressiveLoading){
Pattern p = Pattern.compile(regexNamingPattern);
ArrayList<String> files = new ArrayList<>();
Enumeration<? extends ZipEntry> e = zip.entries();
ZipEntry tmp;
while(e.hasMoreElements())
if((tmp=e.nextElement()).getName().startsWith(folder) && p.matcher(tmp.getName()).find())
files.add(tmp.getName());
if(files.size()==0){
fixFail();
return;
}
try {
for (String s : files) {
if(defaultLang==null){
defaultLang = Language.parse(zip, s, aggressiveLoading);
all.add(defaultLang);
}else all.add(Language.parse(zip, s, aggressiveLoading));
}
}catch(Exception ignored){}
}
public Localization(File folder, String regexNamingPattern){ this(folder, regexNamingPattern, true); }
public Localization(File folder){ this(folder, true); }
public Localization(File folder, boolean aggressiveLoading){ this(folder, "(.*)", aggressiveLoading); }