mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-04-30 14:24:25 +02:00
[XML,JSON] keep original apk file paths, fixes: REAndroid/APKEditor#15
This commit is contained in:
parent
c650910b2b
commit
43f299cc79
@ -39,6 +39,10 @@ public class ApkJsonDecoder {
|
||||
public ApkJsonDecoder(ApkModule apkModule){
|
||||
this(apkModule, false);
|
||||
}
|
||||
public void sanitizeFilePaths(){
|
||||
PathSanitizer sanitizer = new PathSanitizer(apkModule);
|
||||
sanitizer.sanitize();
|
||||
}
|
||||
public File writeToDirectory(File dir) throws IOException {
|
||||
this.decodedPaths.clear();
|
||||
writeUncompressed(dir);
|
||||
@ -48,8 +52,15 @@ public class ApkJsonDecoder {
|
||||
//writePublicXml(dir);
|
||||
writeResources(dir);
|
||||
writeRootFiles(dir);
|
||||
writePathMap(dir);
|
||||
return new File(dir, apkModule.getModuleName());
|
||||
}
|
||||
private void writePathMap(File dir) throws IOException {
|
||||
PathMap pathMap = new PathMap();
|
||||
pathMap.add(apkModule.getApkArchive());
|
||||
File file = toPathMapJsonFile(dir);
|
||||
pathMap.toJson().write(file);
|
||||
}
|
||||
private void writeUncompressed(File dir) throws IOException {
|
||||
File file=toUncompressedJsonFile(dir);
|
||||
UncompressedFiles uncompressedFiles=new UncompressedFiles();
|
||||
@ -77,17 +88,9 @@ public class ApkJsonDecoder {
|
||||
jsonObject.write(file);
|
||||
addDecoded(path);
|
||||
}
|
||||
// TODO: temporary fix
|
||||
private void writeRootFiles(File dir) throws IOException {
|
||||
for(InputSource inputSource:apkModule.getApkArchive().listInputSources()){
|
||||
try{
|
||||
writeRootFile(dir, inputSource);
|
||||
}catch (IOException ex){
|
||||
APKLogger logger = apkModule.getApkLogger();
|
||||
if(logger!=null){
|
||||
logger.logMessage("ERROR: "+ex.getMessage());
|
||||
}
|
||||
}
|
||||
writeRootFile(dir, inputSource);
|
||||
}
|
||||
}
|
||||
private void writeRootFile(File dir, InputSource inputSource) throws IOException {
|
||||
@ -186,6 +189,10 @@ public class ApkJsonDecoder {
|
||||
String name = "public.xml";
|
||||
return new File(file, name);
|
||||
}
|
||||
private File toPathMapJsonFile(File dir){
|
||||
File file = new File(dir, apkModule.getModuleName());
|
||||
return new File(file, PathMap.JSON_FILE);
|
||||
}
|
||||
private File toUncompressedJsonFile(File dir){
|
||||
File file = new File(dir, apkModule.getModuleName());
|
||||
return new File(file, UncompressedFiles.JSON_FILE);
|
||||
|
@ -19,8 +19,11 @@ import com.reandroid.archive.APKArchive;
|
||||
import com.reandroid.archive.FileInputSource;
|
||||
import com.reandroid.arsc.chunk.TableBlock;
|
||||
import com.reandroid.arsc.chunk.xml.AndroidManifestBlock;
|
||||
import com.reandroid.json.JSONArray;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@ -40,8 +43,27 @@ public class ApkJsonEncoder {
|
||||
module.setAPKLogger(apkLogger);
|
||||
loadUncompressed(module, moduleDir);
|
||||
applyResourceId(module, moduleDir);
|
||||
restorePathMap(moduleDir, module);
|
||||
return module;
|
||||
}
|
||||
private void restorePathMap(File dir, ApkModule apkModule){
|
||||
File file = new File(dir, PathMap.JSON_FILE);
|
||||
if(!file.isFile()){
|
||||
return;
|
||||
}
|
||||
logMessage("Restoring file path ...");
|
||||
PathMap pathMap = new PathMap();
|
||||
FileInputStream inputStream = null;
|
||||
try {
|
||||
inputStream = new FileInputStream(file);
|
||||
} catch (FileNotFoundException exception) {
|
||||
logError("Failed to load path-map", exception);
|
||||
return;
|
||||
}
|
||||
JSONArray jsonArray = new JSONArray(inputStream);
|
||||
pathMap.fromJson(jsonArray);
|
||||
pathMap.restore(apkModule);
|
||||
}
|
||||
private void applyResourceId(ApkModule apkModule, File moduleDir) {
|
||||
if(!apkModule.hasTableBlock()){
|
||||
return;
|
||||
|
@ -48,6 +48,10 @@ import java.util.*;
|
||||
this.decodedEntries = new HashMap<>();
|
||||
this.mDecodedPaths = new HashSet<>();
|
||||
}
|
||||
public void sanitizeFilePaths(){
|
||||
PathSanitizer sanitizer = new PathSanitizer(apkModule);
|
||||
sanitizer.sanitize();
|
||||
}
|
||||
public void decodeTo(File outDir)
|
||||
throws IOException, XMLException {
|
||||
this.decodedEntries.clear();
|
||||
@ -74,6 +78,14 @@ import java.util.*;
|
||||
decodeValues(tableBlock, outDir, tableBlock);
|
||||
|
||||
extractRootFiles(outDir);
|
||||
|
||||
writePathMap(outDir);
|
||||
}
|
||||
private void writePathMap(File dir) throws IOException {
|
||||
PathMap pathMap = new PathMap();
|
||||
pathMap.add(apkModule.getApkArchive());
|
||||
File file = new File(dir, PathMap.JSON_FILE);
|
||||
pathMap.toJson().write(file);
|
||||
}
|
||||
private void decodePackageInfo(File outDir, TableBlock tableBlock) throws IOException {
|
||||
for(PackageBlock packageBlock:tableBlock.listPackages()){
|
||||
@ -103,22 +115,21 @@ import java.util.*;
|
||||
}
|
||||
private void decodeResRaw(File outDir, ResFile resFile)
|
||||
throws IOException {
|
||||
Entry entry =resFile.pickOne();
|
||||
Entry entry = resFile.pickOne();
|
||||
PackageBlock packageBlock= entry.getPackageBlock();
|
||||
|
||||
File pkgDir=new File(outDir, getPackageDirName(packageBlock));
|
||||
File resDir=new File(pkgDir, ApkUtil.RES_DIR_NAME);
|
||||
String path=resFile.buildPath();
|
||||
path=path.replace('/', File.separatorChar);
|
||||
File file=new File(resDir, path);
|
||||
String alias = resFile.buildPath(ApkUtil.RES_DIR_NAME);
|
||||
String path = alias.replace('/', File.separatorChar);
|
||||
File file=new File(pkgDir, path);
|
||||
File dir=file.getParentFile();
|
||||
if(!dir.exists()){
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
FileOutputStream outputStream=new FileOutputStream(file);
|
||||
resFile.getInputSource().write(outputStream);
|
||||
outputStream.close();
|
||||
resFile.setFilePath(alias);
|
||||
|
||||
addDecodedEntry(entry);
|
||||
}
|
||||
@ -130,10 +141,10 @@ import java.util.*;
|
||||
resFile.getInputSource().getName());
|
||||
|
||||
File pkgDir=new File(outDir, getPackageDirName(packageBlock));
|
||||
File resDir=new File(pkgDir, ApkUtil.RES_DIR_NAME);
|
||||
String path=resFile.buildPath();
|
||||
String alias = resFile.buildPath(ApkUtil.RES_DIR_NAME);
|
||||
String path = alias.replace('/', File.separatorChar);
|
||||
path=path.replace('/', File.separatorChar);
|
||||
File file=new File(resDir, path);
|
||||
File file=new File(pkgDir, path);
|
||||
|
||||
logVerbose("Decoding: "+path);
|
||||
XMLNamespaceValidator namespaceValidator=new XMLNamespaceValidator(resXmlDocument);
|
||||
@ -141,6 +152,8 @@ import java.util.*;
|
||||
XMLDocument xmlDocument= resXmlDocument.decodeToXml(entryStore, packageBlock.getId());
|
||||
xmlDocument.save(file, true);
|
||||
|
||||
resFile.setFilePath(alias);
|
||||
|
||||
addDecodedEntry(resFile.pickOne());
|
||||
}
|
||||
private void decodePublicXml(TableBlock tableBlock, File outDir)
|
||||
@ -304,14 +317,9 @@ import java.util.*;
|
||||
if(!dir.exists()){
|
||||
dir.mkdirs();
|
||||
}
|
||||
// TODO:Temporary fix
|
||||
try{
|
||||
FileOutputStream outputStream=new FileOutputStream(file);
|
||||
inputSource.write(outputStream);
|
||||
outputStream.close();
|
||||
}catch (IOException ex){
|
||||
logMessage("ERROR: "+ex.getMessage());
|
||||
}
|
||||
FileOutputStream outputStream=new FileOutputStream(file);
|
||||
inputSource.write(outputStream);
|
||||
outputStream.close();
|
||||
}
|
||||
private boolean containsDecodedPath(String path){
|
||||
return mDecodedPaths.contains(path);
|
||||
|
@ -19,9 +19,11 @@ package com.reandroid.apk;
|
||||
import com.reandroid.archive.FileInputSource;
|
||||
import com.reandroid.apk.xmlencoder.RESEncoder;
|
||||
import com.reandroid.arsc.chunk.TableBlock;
|
||||
import com.reandroid.json.JSONArray;
|
||||
import com.reandroid.xml.XMLException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@ -38,6 +40,18 @@ package com.reandroid.apk;
|
||||
resEncoder.scanDirectory(mainDirectory);
|
||||
File rootDir=new File(mainDirectory, "root");
|
||||
scanRootDir(rootDir);
|
||||
restorePathMap(mainDirectory);
|
||||
}
|
||||
private void restorePathMap(File dir) throws IOException{
|
||||
File file = new File(dir, PathMap.JSON_FILE);
|
||||
if(!file.isFile()){
|
||||
return;
|
||||
}
|
||||
PathMap pathMap = new PathMap();
|
||||
FileInputStream inputStream = new FileInputStream(file);
|
||||
JSONArray jsonArray = new JSONArray(inputStream);
|
||||
pathMap.fromJson(jsonArray);
|
||||
pathMap.restore(getApkModule());
|
||||
}
|
||||
public ApkModule getApkModule(){
|
||||
return resEncoder.getApkModule();
|
||||
|
206
src/main/java/com/reandroid/apk/PathMap.java
Normal file
206
src/main/java/com/reandroid/apk/PathMap.java
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.apk;
|
||||
|
||||
import com.reandroid.archive.InputSource;
|
||||
import com.reandroid.archive.ZipArchive;
|
||||
import com.reandroid.json.JSONArray;
|
||||
import com.reandroid.json.JSONConvert;
|
||||
import com.reandroid.json.JSONObject;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class PathMap implements JSONConvert<JSONArray> {
|
||||
private final Object mLock = new Object();
|
||||
private final Map<String, String> mNameAliasMap;
|
||||
private final Map<String, String> mAliasNameMap;
|
||||
|
||||
public PathMap(){
|
||||
this.mNameAliasMap = new HashMap<>();
|
||||
this.mAliasNameMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public void restore(ApkModule apkModule){
|
||||
restoreResFile(apkModule.listResFiles());
|
||||
restore(apkModule.getApkArchive().listInputSources());
|
||||
}
|
||||
public List<String> restoreResFile(Collection<ResFile> files){
|
||||
List<String> results = new ArrayList<>();
|
||||
if(files == null){
|
||||
return results;
|
||||
}
|
||||
for(ResFile resFile:files){
|
||||
String alias = restoreResFile(resFile);
|
||||
if(alias==null){
|
||||
continue;
|
||||
}
|
||||
results.add(alias);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
public String restoreResFile(ResFile resFile){
|
||||
InputSource inputSource = resFile.getInputSource();
|
||||
String alias = restore(inputSource);
|
||||
if(alias==null){
|
||||
return null;
|
||||
}
|
||||
resFile.setFilePath(alias);
|
||||
return alias;
|
||||
}
|
||||
public List<String> restore(Collection<InputSource> sources){
|
||||
List<String> results = new ArrayList<>();
|
||||
if(sources == null){
|
||||
return results;
|
||||
}
|
||||
for(InputSource inputSource:sources){
|
||||
String alias = restore(inputSource);
|
||||
if(alias==null){
|
||||
continue;
|
||||
}
|
||||
results.add(alias);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
public String restore(InputSource inputSource){
|
||||
if(inputSource==null){
|
||||
return null;
|
||||
}
|
||||
String name = inputSource.getName();
|
||||
String alias = getName(name);
|
||||
if(alias==null){
|
||||
name = inputSource.getAlias();
|
||||
alias = getName(name);
|
||||
}
|
||||
if(alias==null || alias.equals(inputSource.getAlias())){
|
||||
return null;
|
||||
}
|
||||
inputSource.setAlias(alias);
|
||||
return alias;
|
||||
}
|
||||
|
||||
public String getAlias(String name){
|
||||
synchronized (mLock){
|
||||
return mNameAliasMap.get(name);
|
||||
}
|
||||
}
|
||||
public String getName(String alias){
|
||||
synchronized (mLock){
|
||||
return mAliasNameMap.get(alias);
|
||||
}
|
||||
}
|
||||
public int size(){
|
||||
synchronized (mLock){
|
||||
return mNameAliasMap.size();
|
||||
}
|
||||
}
|
||||
public void clear(){
|
||||
synchronized (mLock){
|
||||
mNameAliasMap.clear();
|
||||
mAliasNameMap.clear();
|
||||
}
|
||||
}
|
||||
public void add(ZipArchive archive){
|
||||
if(archive == null){
|
||||
return;
|
||||
}
|
||||
add(archive.listInputSources());
|
||||
}
|
||||
public void add(Collection<InputSource> sources){
|
||||
if(sources==null){
|
||||
return;
|
||||
}
|
||||
for(InputSource inputSource:sources){
|
||||
add(inputSource);
|
||||
}
|
||||
}
|
||||
public void add(InputSource inputSource){
|
||||
if(inputSource==null){
|
||||
return;
|
||||
}
|
||||
add(inputSource.getName(), inputSource.getAlias());
|
||||
}
|
||||
public void add(String name, String alias){
|
||||
if(name==null || alias==null){
|
||||
return;
|
||||
}
|
||||
if(name.equals(alias)){
|
||||
return;
|
||||
}
|
||||
synchronized (mLock){
|
||||
mNameAliasMap.remove(name);
|
||||
mNameAliasMap.put(name, alias);
|
||||
mAliasNameMap.remove(alias);
|
||||
mAliasNameMap.put(alias, name);
|
||||
}
|
||||
}
|
||||
|
||||
private void add(JSONObject json){
|
||||
if(json==null){
|
||||
return;
|
||||
}
|
||||
add(json.optString(NAME_name), json.optString(NAME_alias));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray toJson() {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
Map<String, String> nameMap = this.mNameAliasMap;
|
||||
List<String> nameList = toSortedList(nameMap.keySet());
|
||||
for(String name:nameList){
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put(NAME_name, name);
|
||||
jsonObject.put(NAME_alias, nameMap.get(name));
|
||||
jsonArray.put(jsonObject);
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
@Override
|
||||
public void fromJson(JSONArray json) {
|
||||
clear();
|
||||
if(json==null){
|
||||
return;
|
||||
}
|
||||
int length = json.length();
|
||||
for(int i=0;i<length;i++){
|
||||
add(json.optJSONObject(i));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
return "PathMap size="+size();
|
||||
}
|
||||
|
||||
private static List<String> toSortedList(Collection<String> stringCollection){
|
||||
List<String> results;
|
||||
if(stringCollection instanceof List){
|
||||
results = (List<String>) stringCollection;
|
||||
}else {
|
||||
results = new ArrayList<>(stringCollection);
|
||||
}
|
||||
Comparator<String> cmp = new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String s1, String s2) {
|
||||
return s1.compareTo(s2);
|
||||
}
|
||||
};
|
||||
results.sort(cmp);
|
||||
return results;
|
||||
}
|
||||
|
||||
public static final String NAME_name = "name";
|
||||
public static final String NAME_alias = "alias";
|
||||
public static final String JSON_FILE = "path-map.json";
|
||||
}
|
183
src/main/java/com/reandroid/apk/PathSanitizer.java
Normal file
183
src/main/java/com/reandroid/apk/PathSanitizer.java
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.apk;
|
||||
|
||||
import com.reandroid.archive.InputSource;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class PathSanitizer {
|
||||
private final ApkModule apkModule;
|
||||
private APKLogger apkLogger;
|
||||
private final Set<String> mSanitizedPaths;
|
||||
public PathSanitizer(ApkModule apkModule){
|
||||
this.apkModule = apkModule;
|
||||
this.apkLogger = apkModule.getApkLogger();
|
||||
this.mSanitizedPaths = new HashSet<>();
|
||||
}
|
||||
public void sanitize(){
|
||||
mSanitizedPaths.clear();
|
||||
logMessage("Sanitizing paths ...");
|
||||
List<ResFile> resFileList = apkModule.listResFiles();
|
||||
for(ResFile resFile:resFileList){
|
||||
sanitize(resFile);
|
||||
}
|
||||
List<InputSource> sourceList = apkModule.getApkArchive().listInputSources();
|
||||
for(InputSource inputSource:sourceList){
|
||||
sanitize(inputSource, 1, false);
|
||||
}
|
||||
logMessage("DONE = "+mSanitizedPaths.size());
|
||||
}
|
||||
private void sanitize(ResFile resFile){
|
||||
InputSource inputSource = resFile.getInputSource();
|
||||
String replace = sanitize(inputSource, 3, true);
|
||||
if(replace==null){
|
||||
return;
|
||||
}
|
||||
resFile.setFilePath(replace);
|
||||
}
|
||||
private String sanitize(InputSource inputSource, int depth, boolean fixedDepth){
|
||||
String name = inputSource.getName();
|
||||
if(mSanitizedPaths.contains(name)){
|
||||
return null;
|
||||
}
|
||||
mSanitizedPaths.add(name);
|
||||
String alias = inputSource.getAlias();
|
||||
String replace = sanitize(alias, depth, fixedDepth);
|
||||
if(alias.equals(replace)){
|
||||
return null;
|
||||
}
|
||||
inputSource.setAlias(replace);
|
||||
logVerbose("REN: '"+alias+"' -> '"+replace+"'");
|
||||
return replace;
|
||||
}
|
||||
|
||||
private String sanitize(String name, int depth, boolean fixedDepth){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String[] nameSplit = name.split("/");
|
||||
|
||||
boolean pathIsLong = name.length() >= MAX_PATH_LENGTH;
|
||||
int length = nameSplit.length;
|
||||
for(int i=0;i<length;i++){
|
||||
String split = nameSplit[i];
|
||||
boolean good = isGoodSimpleName(split);
|
||||
if(!good || (pathIsLong && i>=depth)){
|
||||
split = createUniqueName(name);
|
||||
appendPathName(builder, split);
|
||||
break;
|
||||
}
|
||||
if(fixedDepth && i>=(depth-1)){
|
||||
if(i < length-1){
|
||||
split = createUniqueName(name);
|
||||
}
|
||||
appendPathName(builder, split);
|
||||
break;
|
||||
}
|
||||
appendPathName(builder, split);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public void setApkLogger(APKLogger apkLogger) {
|
||||
this.apkLogger = apkLogger;
|
||||
}
|
||||
private String getLogTag(){
|
||||
return "[SANITIZE]: ";
|
||||
}
|
||||
private void logMessage(String msg){
|
||||
APKLogger logger = this.apkLogger;
|
||||
if(logger!=null){
|
||||
logger.logMessage(getLogTag()+msg);
|
||||
}
|
||||
}
|
||||
private void logVerbose(String msg){
|
||||
APKLogger logger = this.apkLogger;
|
||||
if(logger!=null){
|
||||
logger.logVerbose(getLogTag()+msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendPathName(StringBuilder builder, String name){
|
||||
if(builder.length()>0){
|
||||
builder.append('/');
|
||||
}
|
||||
builder.append(name);
|
||||
}
|
||||
private static String createUniqueName(String name){
|
||||
int hash = name.hashCode();
|
||||
return String.format("alias_%08x", hash).toLowerCase();
|
||||
}
|
||||
private static boolean isGoodSimpleName(String name){
|
||||
if(name==null){
|
||||
return false;
|
||||
}
|
||||
String alias = sanitizeSimpleName(name);
|
||||
return name.equals(alias);
|
||||
}
|
||||
public static String sanitizeSimpleName(String name){
|
||||
if(name==null){
|
||||
return null;
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
char[] chars = name.toCharArray();
|
||||
boolean skipNext = true;
|
||||
int length = 0;
|
||||
int lengthMax = MAX_NAME_LENGTH;
|
||||
for(int i=0;i<chars.length;i++){
|
||||
if(length>=lengthMax){
|
||||
break;
|
||||
}
|
||||
char ch = chars[i];
|
||||
if(isGoodFileNameSymbol(ch)){
|
||||
if(!skipNext){
|
||||
builder.append(ch);
|
||||
length++;
|
||||
}
|
||||
skipNext=true;
|
||||
continue;
|
||||
}
|
||||
if(!isGoodFileNameChar(ch)){
|
||||
skipNext = true;
|
||||
continue;
|
||||
}
|
||||
builder.append(ch);
|
||||
length++;
|
||||
skipNext=false;
|
||||
}
|
||||
if(length==0){
|
||||
return null;
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static boolean isGoodFileNameSymbol(char ch){
|
||||
return ch == '.'
|
||||
|| ch == '+'
|
||||
|| ch == '-'
|
||||
|| ch == '_'
|
||||
|| ch == '#';
|
||||
}
|
||||
private static boolean isGoodFileNameChar(char ch){
|
||||
return (ch >= '0' && ch <= '9')
|
||||
|| (ch >= 'A' && ch <= 'Z')
|
||||
|| (ch >= 'a' && ch <= 'z');
|
||||
}
|
||||
|
||||
private static final int MAX_NAME_LENGTH = 50;
|
||||
private static final int MAX_PATH_LENGTH = 100;
|
||||
}
|
@ -135,14 +135,23 @@ public class ResFile {
|
||||
return new File(dir, path);
|
||||
}
|
||||
public String buildPath(){
|
||||
Entry entry =pickOne();
|
||||
TypeBlock typeBlock= entry.getTypeBlock();
|
||||
StringBuilder builder=new StringBuilder();
|
||||
return buildPath(null);
|
||||
}
|
||||
public String buildPath(String parent){
|
||||
Entry entry = pickOne();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if(parent!=null){
|
||||
builder.append(parent);
|
||||
if(!parent.endsWith("/")){
|
||||
builder.append('/');
|
||||
}
|
||||
}
|
||||
TypeBlock typeBlock = entry.getTypeBlock();
|
||||
builder.append(typeBlock.getTypeName());
|
||||
builder.append(typeBlock.getQualifiers());
|
||||
builder.append('/');
|
||||
builder.append(entry.getName());
|
||||
String ext=getFileExtension();
|
||||
String ext = getFileExtension();
|
||||
if(ext!=null){
|
||||
builder.append(ext);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user