mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-04-30 22:34:24 +02:00
improve XML encoding speed
This commit is contained in:
parent
3eda5edaf6
commit
50753ca54c
@ -19,6 +19,7 @@ import com.reandroid.lib.arsc.chunk.PackageBlock;
|
|||||||
import com.reandroid.lib.arsc.chunk.TableBlock;
|
import com.reandroid.lib.arsc.chunk.TableBlock;
|
||||||
import com.reandroid.lib.arsc.group.EntryGroup;
|
import com.reandroid.lib.arsc.group.EntryGroup;
|
||||||
import com.reandroid.lib.arsc.pool.SpecStringPool;
|
import com.reandroid.lib.arsc.pool.SpecStringPool;
|
||||||
|
import com.reandroid.lib.arsc.util.ResNameMap;
|
||||||
import com.reandroid.lib.json.JSONArray;
|
import com.reandroid.lib.json.JSONArray;
|
||||||
import com.reandroid.lib.json.JSONObject;
|
import com.reandroid.lib.json.JSONObject;
|
||||||
import com.reandroid.xml.*;
|
import com.reandroid.xml.*;
|
||||||
@ -244,9 +245,23 @@ import java.util.*;
|
|||||||
public final byte id;
|
public final byte id;
|
||||||
public String name;
|
public String name;
|
||||||
public final Map<Byte, Type> typeMap;
|
public final Map<Byte, Type> typeMap;
|
||||||
|
private final ResNameMap<Integer> mEntryNameMap;
|
||||||
public Package(byte id){
|
public Package(byte id){
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.typeMap = new HashMap<>();
|
this.typeMap = new HashMap<>();
|
||||||
|
this.mEntryNameMap = new ResNameMap<>();
|
||||||
|
}
|
||||||
|
public void loadEntryMap(){
|
||||||
|
mEntryNameMap.clear();
|
||||||
|
for(Type type:typeMap.values()){
|
||||||
|
String typeName=type.getName();
|
||||||
|
for(Type.Entry entry: type.entryMap.values()){
|
||||||
|
mEntryNameMap.add(typeName, entry.getName(), entry.getResourceId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Integer getResourceId(String typeName, String name){
|
||||||
|
return mEntryNameMap.get(typeName, name);
|
||||||
}
|
}
|
||||||
public Type.Entry getEntry(String typeName, String name){
|
public Type.Entry getEntry(String typeName, String name){
|
||||||
Type type=getType(typeName);
|
Type type=getType(typeName);
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
import com.reandroid.lib.arsc.group.EntryGroup;
|
import com.reandroid.lib.arsc.group.EntryGroup;
|
||||||
import com.reandroid.lib.arsc.item.SpecString;
|
import com.reandroid.lib.arsc.item.SpecString;
|
||||||
import com.reandroid.lib.arsc.util.FrameworkTable;
|
import com.reandroid.lib.arsc.util.FrameworkTable;
|
||||||
|
import com.reandroid.lib.arsc.util.ResNameMap;
|
||||||
import com.reandroid.lib.arsc.value.EntryBlock;
|
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||||
import com.reandroid.lib.common.Frameworks;
|
import com.reandroid.lib.common.Frameworks;
|
||||||
import com.reandroid.lib.common.ResourceResolver;
|
import com.reandroid.lib.common.ResourceResolver;
|
||||||
@ -41,6 +42,7 @@
|
|||||||
private APKLogger apkLogger;
|
private APKLogger apkLogger;
|
||||||
private boolean mForceCreateNamespaces = true;
|
private boolean mForceCreateNamespaces = true;
|
||||||
private Set<String> mFrameworkPackageNames;
|
private Set<String> mFrameworkPackageNames;
|
||||||
|
private final ResNameMap<EntryBlock> mLocalResNameMap = new ResNameMap<>();
|
||||||
public EncodeMaterials(){
|
public EncodeMaterials(){
|
||||||
}
|
}
|
||||||
public SpecString getSpecString(String name){
|
public SpecString getSpecString(String name){
|
||||||
@ -48,29 +50,6 @@
|
|||||||
.get(name)
|
.get(name)
|
||||||
.get(0);
|
.get(0);
|
||||||
}
|
}
|
||||||
public void addTableStringPool(Collection<String> stringList){
|
|
||||||
getCurrentPackage()
|
|
||||||
.getTableBlock()
|
|
||||||
.getTableStringPool()
|
|
||||||
.addStrings(stringList);
|
|
||||||
}
|
|
||||||
public int resolveAttributeNameReference(String refString){
|
|
||||||
String packageName = null;
|
|
||||||
String type = "attr";
|
|
||||||
String name = refString;
|
|
||||||
int i=refString.lastIndexOf(':');
|
|
||||||
if(i>=0){
|
|
||||||
packageName=refString.substring(0, i);
|
|
||||||
name=refString.substring(i+1);
|
|
||||||
}
|
|
||||||
if(EncodeUtil.isEmpty(packageName)
|
|
||||||
|| packageName.equals(getCurrentPackageName())
|
|
||||||
|| !isFrameworkPackageName(packageName)){
|
|
||||||
|
|
||||||
return resolveLocalResourceId(type, name);
|
|
||||||
}
|
|
||||||
return resolveFrameworkResourceId(packageName, type, name);
|
|
||||||
}
|
|
||||||
public EntryBlock getAttributeBlock(String refString){
|
public EntryBlock getAttributeBlock(String refString){
|
||||||
String packageName = null;
|
String packageName = null;
|
||||||
String type = "attr";
|
String type = "attr";
|
||||||
@ -111,34 +90,11 @@
|
|||||||
}
|
}
|
||||||
return resolveFrameworkResourceId(packageName, type, name);
|
return resolveFrameworkResourceId(packageName, type, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntryBlock resolveEntryReference(String refString){
|
|
||||||
if("@null".equals(refString)){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Matcher matcher = ValueDecoder.PATTERN_REFERENCE.matcher(refString);
|
|
||||||
if(!matcher.find()){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String prefix=matcher.group(1);
|
|
||||||
String packageName = matcher.group(2);
|
|
||||||
if(packageName!=null && packageName.endsWith(":")){
|
|
||||||
packageName=packageName.substring(0, packageName.length()-1);
|
|
||||||
}
|
|
||||||
String type = matcher.group(4);
|
|
||||||
String name = matcher.group(5);
|
|
||||||
if(EncodeUtil.isEmpty(packageName)
|
|
||||||
|| packageName.equals(getCurrentPackageName())
|
|
||||||
|| !isFrameworkPackageName(packageName)){
|
|
||||||
return getLocalEntryBlock(type, name);
|
|
||||||
}
|
|
||||||
return getFrameworkEntry(packageName, type, name);
|
|
||||||
}
|
|
||||||
public int resolveLocalResourceId(String type, String name){
|
public int resolveLocalResourceId(String type, String name){
|
||||||
for(ResourceIds.Table.Package pkg:packageIdSet){
|
for(ResourceIds.Table.Package pkg:packageIdSet){
|
||||||
ResourceIds.Table.Package.Type.Entry entry = pkg.getEntry(type, name);
|
Integer resId = pkg.getResourceId(type, name);
|
||||||
if(entry!=null){
|
if(resId!=null){
|
||||||
return entry.getResourceId();
|
return resId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EntryGroup entryGroup=getLocalEntryGroup(type, name);
|
EntryGroup entryGroup=getLocalEntryGroup(type, name);
|
||||||
@ -149,15 +105,6 @@
|
|||||||
"type="+type+
|
"type="+type+
|
||||||
", name="+name);
|
", name="+name);
|
||||||
}
|
}
|
||||||
public int resolveFrameworkResourceId(String type, String name){
|
|
||||||
EntryBlock entryBlock = getFrameworkEntry(type, name);
|
|
||||||
if(entryBlock!=null){
|
|
||||||
return entryBlock.getResourceId();
|
|
||||||
}
|
|
||||||
throw new EncodeException("Framework entry not found: " +
|
|
||||||
"type="+type+
|
|
||||||
", name="+name);
|
|
||||||
}
|
|
||||||
public int resolveFrameworkResourceId(String packageName, String type, String name){
|
public int resolveFrameworkResourceId(String packageName, String type, String name){
|
||||||
EntryBlock entryBlock = getFrameworkEntry(packageName, type, name);
|
EntryBlock entryBlock = getFrameworkEntry(packageName, type, name);
|
||||||
if(entryBlock!=null){
|
if(entryBlock!=null){
|
||||||
@ -196,6 +143,22 @@
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public EntryBlock getLocalEntryBlock(String type, String name){
|
public EntryBlock getLocalEntryBlock(String type, String name){
|
||||||
|
EntryBlock entryBlock=mLocalResNameMap.get(type, name);
|
||||||
|
if(entryBlock!=null){
|
||||||
|
return entryBlock;
|
||||||
|
}
|
||||||
|
loadLocalEntryBlockMap(type);
|
||||||
|
entryBlock=mLocalResNameMap.get(type, name);
|
||||||
|
if(entryBlock!=null){
|
||||||
|
return entryBlock;
|
||||||
|
}
|
||||||
|
entryBlock= searchLocalEntryBlock(type, name);
|
||||||
|
if(entryBlock!=null){
|
||||||
|
mLocalResNameMap.add(type, name, entryBlock);
|
||||||
|
}
|
||||||
|
return entryBlock;
|
||||||
|
}
|
||||||
|
private EntryBlock searchLocalEntryBlock(String type, String name){
|
||||||
for(EntryGroup entryGroup : currentPackage.listEntryGroup()){
|
for(EntryGroup entryGroup : currentPackage.listEntryGroup()){
|
||||||
if(type.equals(entryGroup.getTypeName()) &&
|
if(type.equals(entryGroup.getTypeName()) &&
|
||||||
name.equals(entryGroup.getSpecName())){
|
name.equals(entryGroup.getSpecName())){
|
||||||
@ -205,7 +168,7 @@
|
|||||||
SpecTypePair specTypePair=currentPackage.searchByTypeName(type);
|
SpecTypePair specTypePair=currentPackage.searchByTypeName(type);
|
||||||
if(specTypePair!=null){
|
if(specTypePair!=null){
|
||||||
for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){
|
for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){
|
||||||
for(EntryBlock entryBlock:typeBlock.listEntries()){
|
for(EntryBlock entryBlock:typeBlock.listEntries(true)){
|
||||||
if(name.equals(entryBlock.getName())){
|
if(name.equals(entryBlock.getName())){
|
||||||
return entryBlock;
|
return entryBlock;
|
||||||
}
|
}
|
||||||
@ -220,7 +183,7 @@
|
|||||||
specTypePair=packageBlock.searchByTypeName(type);
|
specTypePair=packageBlock.searchByTypeName(type);
|
||||||
if(specTypePair!=null){
|
if(specTypePair!=null){
|
||||||
for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){
|
for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){
|
||||||
for(EntryBlock entryBlock:typeBlock.listEntries()){
|
for(EntryBlock entryBlock:typeBlock.listEntries(true)){
|
||||||
if(name.equals(entryBlock.getName())){
|
if(name.equals(entryBlock.getName())){
|
||||||
return entryBlock;
|
return entryBlock;
|
||||||
}
|
}
|
||||||
@ -231,6 +194,20 @@
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
private void loadLocalEntryBlockMap(String type){
|
||||||
|
ResNameMap<EntryBlock> localMap = mLocalResNameMap;
|
||||||
|
for(PackageBlock packageBlock:currentPackage.getTableBlock().listPackages()){
|
||||||
|
SpecTypePair specTypePair=packageBlock.searchByTypeName(type);
|
||||||
|
if(specTypePair!=null){
|
||||||
|
for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){
|
||||||
|
for(EntryBlock entryBlock:typeBlock.listEntries(true)){
|
||||||
|
localMap.add(entryBlock.getTypeName(),
|
||||||
|
entryBlock.getName(), entryBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
public EntryBlock getFrameworkEntry(String type, String name){
|
public EntryBlock getFrameworkEntry(String type, String name){
|
||||||
for(FrameworkTable table:frameworkTables){
|
for(FrameworkTable table:frameworkTables){
|
||||||
EntryBlock entryBlock = table.searchEntryBlock(type, name);
|
EntryBlock entryBlock = table.searchEntryBlock(type, name);
|
||||||
@ -282,16 +259,12 @@
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EncodeMaterials setForceCreateNamespaces(boolean force) {
|
public EncodeMaterials setForceCreateNamespaces(boolean force) {
|
||||||
this.mForceCreateNamespaces = force;
|
this.mForceCreateNamespaces = force;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public EncodeMaterials addPackageIds(Collection<ResourceIds.Table.Package> packageIdList) {
|
|
||||||
this.packageIdSet.addAll(packageIdList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
public EncodeMaterials addPackageIds(ResourceIds.Table.Package packageIds) {
|
public EncodeMaterials addPackageIds(ResourceIds.Table.Package packageIds) {
|
||||||
|
packageIds.loadEntryMap();
|
||||||
this.packageIdSet.add(packageIds);
|
this.packageIdSet.add(packageIds);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -99,16 +99,23 @@ public class XMLFileEncoder {
|
|||||||
int count=element.getAttributeCount();
|
int count=element.getAttributeCount();
|
||||||
for(int i=0;i<count;i++){
|
for(int i=0;i<count;i++){
|
||||||
XMLAttribute attribute=element.getAttributeAt(i);
|
XMLAttribute attribute=element.getAttributeAt(i);
|
||||||
|
if(attribute instanceof SchemaAttr){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if(SchemaAttr.looksSchema(attribute.getName(), attribute.getValue())){
|
if(SchemaAttr.looksSchema(attribute.getName(), attribute.getValue())){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
EntryBlock entryBlock=materials.getAttributeBlock(attribute.getName());
|
String name=attribute.getNameWoPrefix();
|
||||||
int resourceId=0;
|
int resourceId=decodeUnknownAttributeHex(name);
|
||||||
if(entryBlock!=null){
|
EntryBlock entryBlock=null;
|
||||||
resourceId=entryBlock.getResourceId();
|
if(resourceId==0){
|
||||||
|
entryBlock=getAttributeBlock(attribute);
|
||||||
|
if(entryBlock!=null){
|
||||||
|
resourceId=entryBlock.getResourceId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ResXmlAttribute xmlAttribute =
|
ResXmlAttribute xmlAttribute =
|
||||||
resXmlElement.createAttribute(attribute.getNameWoPrefix(), resourceId);
|
resXmlElement.createAttribute(name, resourceId);
|
||||||
String prefix=attribute.getNamePrefix();
|
String prefix=attribute.getNamePrefix();
|
||||||
if(prefix!=null){
|
if(prefix!=null){
|
||||||
ResXmlStartNamespace ns = resXmlElement.getStartNamespaceByPrefix(prefix);
|
ResXmlStartNamespace ns = resXmlElement.getStartNamespaceByPrefix(prefix);
|
||||||
@ -198,11 +205,37 @@ public class XMLFileEncoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void addResourceId(ResIdBuilder idBuilder, XMLAttribute attribute){
|
private void addResourceId(ResIdBuilder idBuilder, XMLAttribute attribute){
|
||||||
EntryBlock entryBlock = materials.getAttributeBlock(attribute.getName());
|
String name=attribute.getNameWoPrefix();
|
||||||
|
int id=decodeUnknownAttributeHex(name);
|
||||||
|
if(id!=0){
|
||||||
|
idBuilder.add(id, name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EntryBlock entryBlock = getAttributeBlock(attribute);
|
||||||
if(entryBlock!=null){
|
if(entryBlock!=null){
|
||||||
idBuilder.add(entryBlock.getResourceId(), entryBlock.getName());
|
idBuilder.add(entryBlock.getResourceId(), entryBlock.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private int decodeUnknownAttributeHex(String name){
|
||||||
|
if(name.length()==0||name.charAt(0)!='@'){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
name=name.substring(1);
|
||||||
|
if(!ValueDecoder.isHex(name)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ValueDecoder.parseHex(name);
|
||||||
|
}
|
||||||
|
private EntryBlock getAttributeBlock(XMLAttribute attribute){
|
||||||
|
if(attribute instanceof SchemaAttr){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String name=attribute.getName();
|
||||||
|
if(name.indexOf(':')<0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return materials.getAttributeBlock(name);
|
||||||
|
}
|
||||||
private ResXmlStartNamespace forceCreateNamespace(ResXmlElement resXmlElement,
|
private ResXmlStartNamespace forceCreateNamespace(ResXmlElement resXmlElement,
|
||||||
int resourceId, String prefix){
|
int resourceId, String prefix){
|
||||||
if(!materials.isForceCreateNamespaces()){
|
if(!materials.isForceCreateNamespaces()){
|
||||||
|
@ -39,8 +39,7 @@ public class FrameworkTable extends TableBlock {
|
|||||||
private String mFrameworkTitle;
|
private String mFrameworkTitle;
|
||||||
private String mFrameworkName;
|
private String mFrameworkName;
|
||||||
private String mFrameworkVersion;
|
private String mFrameworkVersion;
|
||||||
private Map<String, Map<String, EntryGroup>> mNameGroupMap;
|
private ResNameMap<EntryGroup> mNameGroupMap;
|
||||||
private final Object mMapLock=new Object();
|
|
||||||
public FrameworkTable(){
|
public FrameworkTable(){
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -57,55 +56,40 @@ public class FrameworkTable extends TableBlock {
|
|||||||
* Call this if you plan to search entries frequently
|
* Call this if you plan to search entries frequently
|
||||||
*/
|
*/
|
||||||
public void loadResourceNameMap(){
|
public void loadResourceNameMap(){
|
||||||
synchronized (mMapLock){
|
ResNameMap<EntryGroup> resNameMap = mNameGroupMap;
|
||||||
if(mNameGroupMap !=null){
|
if(resNameMap == null){
|
||||||
return;
|
resNameMap = new ResNameMap<>();
|
||||||
}
|
|
||||||
Map<String, Map<String, EntryGroup>> typeMap=new HashMap<>();
|
|
||||||
for(PackageBlock packageBlock:listPackages()){
|
for(PackageBlock packageBlock:listPackages()){
|
||||||
for(EntryGroup group:packageBlock.listEntryGroup()){
|
for(EntryGroup group:packageBlock.listEntryGroup()){
|
||||||
String type=group.getTypeName();
|
resNameMap.add(group.getTypeName(),
|
||||||
Map<String, EntryGroup> groupMap=typeMap.get(type);
|
group.getSpecName(),
|
||||||
if(groupMap==null){
|
group);
|
||||||
groupMap=new HashMap<>();
|
|
||||||
typeMap.put(type, groupMap);
|
|
||||||
}
|
|
||||||
groupMap.put(group.getSpecName(), group);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mNameGroupMap = typeMap;
|
mNameGroupMap = resNameMap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Clears resource name map from memory
|
* Clears resource name map from memory
|
||||||
*/
|
*/
|
||||||
public void clearResourceNameMap(){
|
public void clearResourceNameMap(){
|
||||||
synchronized (mMapLock){
|
if(mNameGroupMap!=null){
|
||||||
if(mNameGroupMap!=null){
|
mNameGroupMap.clear();
|
||||||
mNameGroupMap.clear();
|
mNameGroupMap =null;
|
||||||
mNameGroupMap =null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private boolean hasResourceGroupMap(){
|
private boolean hasResourceGroupMap(){
|
||||||
synchronized (mMapLock){
|
return mNameGroupMap!=null;
|
||||||
return mNameGroupMap!=null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
private EntryBlock searchEntryBlockFromMap(String typeName, String entryName){
|
private EntryBlock searchEntryBlockFromMap(String typeName, String entryName){
|
||||||
synchronized (mMapLock){
|
if(mNameGroupMap ==null){
|
||||||
if(mNameGroupMap ==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Map<String, EntryGroup> groupMap = mNameGroupMap.get(typeName);
|
|
||||||
if(groupMap!=null){
|
|
||||||
EntryGroup group=groupMap.get(entryName);
|
|
||||||
if(group!=null){
|
|
||||||
return group.pickOne();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
EntryGroup entryGroup = mNameGroupMap.get(typeName, entryName);
|
||||||
|
if(entryGroup!=null){
|
||||||
|
return entryGroup.pickOne();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
public EntryBlock searchEntryBlock(String typeName, String entryName){
|
public EntryBlock searchEntryBlock(String typeName, String entryName){
|
||||||
if(hasResourceGroupMap()){
|
if(hasResourceGroupMap()){
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.arsc.util;
|
package com.reandroid.lib.arsc.util;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
65
src/main/java/com/reandroid/lib/arsc/util/ResNameMap.java
Normal file
65
src/main/java/com/reandroid/lib/arsc/util/ResNameMap.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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.lib.arsc.util;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ResNameMap<VALUE> {
|
||||||
|
private final Object mLock = new Object();
|
||||||
|
private final Map<String, Map<String, VALUE>> mainMap;
|
||||||
|
public ResNameMap(){
|
||||||
|
this.mainMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public VALUE get(String type, String name){
|
||||||
|
synchronized (mLock){
|
||||||
|
if(type==null || name==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Map<String, VALUE> valueMap = mainMap.get(type);
|
||||||
|
if(valueMap!=null){
|
||||||
|
return valueMap.get(name);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void add(String type, String name, VALUE value){
|
||||||
|
synchronized (mLock){
|
||||||
|
if(type==null || name==null || value==null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, VALUE> valueMap = mainMap.get(type);
|
||||||
|
if(valueMap==null){
|
||||||
|
valueMap=new HashMap<>();
|
||||||
|
mainMap.put(type, valueMap);
|
||||||
|
}
|
||||||
|
valueMap.put(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void clear(){
|
||||||
|
synchronized (mLock){
|
||||||
|
for(Map<String, VALUE> valueMap:mainMap.values()){
|
||||||
|
valueMap.clear();
|
||||||
|
}
|
||||||
|
mainMap.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String TYPE_ATTR = "attr";
|
||||||
|
private static final String TYPE_ID = "id";
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user