/* * 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.pool; import com.reandroid.lib.arsc.chunk.ChunkType; import com.reandroid.lib.arsc.array.StringArray; import com.reandroid.lib.arsc.array.StyleArray; import com.reandroid.lib.arsc.base.Block; import com.reandroid.lib.arsc.chunk.BaseChunk; import com.reandroid.lib.arsc.group.StringGroup; import com.reandroid.lib.arsc.io.BlockLoad; import com.reandroid.lib.arsc.io.BlockReader; import com.reandroid.lib.arsc.item.*; import com.reandroid.lib.arsc.model.StyleSpanInfo; import com.reandroid.lib.json.JSONConvert; import com.reandroid.lib.json.JSONArray; import com.reandroid.lib.json.JSONObject; import java.io.IOException; import java.util.*; public abstract class BaseStringPool extends BaseChunk implements BlockLoad, JSONConvert, Comparator { private final IntegerItem mCountStrings; private final IntegerItem mCountStyles; private final ShortItem mFlagUtf8; private final ShortItem mFlagSorted; private final IntegerItem mStartStrings; private final IntegerItem mStartStyles; private final IntegerArray mOffsetStrings; private final IntegerArray mOffsetStyles; private final StringArray mArrayStrings; private final StyleArray mArrayStyles; private final Map> mUniqueMap; BaseStringPool(boolean is_utf8){ super(ChunkType.STRING, 4); this.mCountStrings=new IntegerItem(); //header this.mCountStyles=new IntegerItem(); //header this.mFlagUtf8 =new ShortItem(); //header this.mFlagSorted=new ShortItem(); //header this.mStartStrings=new IntegerItem(); //header this.mStartStyles=new IntegerItem(); //header this.mOffsetStrings=new IntegerArray();//1 this.mOffsetStyles=new IntegerArray(); //2 this.mArrayStrings=newInstance(mOffsetStrings, mCountStrings, mStartStrings, is_utf8); //3 this.mArrayStyles=new StyleArray(mOffsetStyles, mCountStyles, mStartStyles); //4 addToHeader(mCountStrings); addToHeader(mCountStyles); addToHeader(mFlagUtf8); addToHeader(mFlagSorted); addToHeader(mStartStrings); addToHeader(mStartStyles); addChild(mOffsetStrings); addChild(mOffsetStyles); addChild(mArrayStrings); addChild(mArrayStyles); setUtf8(is_utf8, false); mFlagUtf8.setBlockLoad(this); mUniqueMap=new HashMap<>(); } public List toStringList(){ return getStringsArray().toStringList(); } public void addStrings(Collection stringList){ if(stringList==null || stringList.size()==0){ return; } Set uniqueSet; if(stringList instanceof HashSet){ uniqueSet=(HashSet)stringList; }else { uniqueSet=new HashSet<>(stringList); } refreshUniqueIdMap(); Set keySet=mUniqueMap.keySet(); for(String key:keySet){ uniqueSet.remove(key); } List sortedList=new ArrayList<>(stringList); sortedList.sort(this); insertStrings(sortedList); } private void insertStrings(List stringList){ StringArray stringsArray = getStringsArray(); int initialSize=stringsArray.childesCount(); stringsArray.ensureSize(initialSize + stringList.size()); int size=stringsArray.childesCount(); int j=0; for (int i=initialSize;i group= getOrCreateGroup(str); group.add(item); } } public List removeUnusedStrings(){ return getStringsArray().removeUnusedStrings(); } public List listUnusedStrings(){ return getStringsArray().listUnusedStrings(); } public Collection listStrings(){ return getStringsArray().listItems(); } public StyleArray getStyleArray(){ return mArrayStyles; } public StringArray getStringsArray(){ return mArrayStrings; } public void removeReferences(Collection referenceList){ if(referenceList==null){ return; } for(ReferenceItem ref:referenceList){ removeReference(ref); } } public boolean removeReference(ReferenceItem ref){ if(ref==null){ return false; } T item=get(ref.get()); if(item!=null){ return item.removeReference(ref); } return false; } public void addReference(ReferenceItem ref){ if(ref==null){ return; } T item=get(ref.get()); if(item!=null){ item.addReference(ref); } } public void addReferences(Collection referenceList){ if(referenceList==null){ return; } for(ReferenceItem ref:referenceList){ addReference(ref); } } public boolean contains(String str){ return mUniqueMap.containsKey(str); } public final T get(int index){ return mArrayStrings.get(index); } public final StringGroup get(String str){ return mUniqueMap.get(str); } public T getOrCreate(String str){ StringGroup group=getOrCreateGroup(str); T[] items=group.getItems(); if(items.length==0){ T t=createNewString(str); group.add(t); items=group.getItems(); } return items[0]; } private StringGroup getOrCreateGroup(String str){ StringGroup group=get(str); if(group!=null){ return group; } group=new StringGroup<>(mArrayStrings, str); mUniqueMap.put(str, group); return group; } private T createNewString(String str){ T item=mArrayStrings.createNext(); item.set(str); mCountStrings.set(mArrayStrings.childesCount()); return item; } public final StyleItem getStyle(int index){ return mArrayStyles.get(index); } public final int countStrings(){ return mArrayStrings.childesCount(); } public final int countStyles(){ return mArrayStyles.childesCount(); } public final T[] getStrings(){ return mArrayStrings.getChildes(); } public final StyleItem[] getStyles(){ return mArrayStyles.getChildes(); } private void setUtf8Flag(short flag){ mFlagUtf8.set(flag); } public void setUtf8(boolean is_utf8){ setUtf8(is_utf8, true); } private void setSortedFlag(short flag){ mFlagSorted.set(flag); } public final void setSorted(boolean sorted){ if(sorted){ setSortedFlag(FLAG_SORTED); }else { setSortedFlag((short)0); } } private void setUtf8(boolean is_utf8, boolean updateAll){ boolean old= isUtf8Flag(); if(is_utf8){ setUtf8Flag(UTF8_FLAG_VALUE); }else { setUtf8Flag((short) 0); } if(!updateAll || old == isUtf8Flag()){ return; } mArrayStrings.setUtf8(is_utf8); } private boolean isUtf8Flag(){ return (mFlagUtf8.get() & FLAG_UTF8) !=0; } private boolean isSortedFlag(){ return (mFlagSorted.get() & FLAG_SORTED) !=0; } abstract StringArray newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8); @Override protected void onChunkRefreshed() { mArrayStrings.refreshCountAndStart(); mArrayStyles.refreshCountAndStart(); } @Override public void onChunkLoaded() { refreshUniqueIdMap(); } @Override public void onBlockLoaded(BlockReader reader, Block sender) throws IOException { if(sender== mFlagUtf8){ mArrayStrings.setUtf8(isUtf8Flag()); } } @Override public JSONArray toJson() { return getStringsArray().toJson(); } //Only for styled strings @Override public void fromJson(JSONArray json) { if(json==null){ return; } loadStyledStrings(json); refresh(); } public void loadStyledStrings(JSONArray jsonArray) { //Styled strings should be at first rows of string pool thus we clear all before adding getStringsArray().clearChildes(); getStyleArray().clearChildes(); List styledStringList = StyledString.fromJson(jsonArray); loadText(styledStringList); Map tagIndexMap = loadStyleTags(styledStringList); loadStyles(styledStringList, tagIndexMap); refreshUniqueIdMap(); } private void loadText(List styledStringList) { StringArray stringsArray = getStringsArray(); int size=styledStringList.size(); stringsArray.ensureSize(size); for(int i=0;i loadStyleTags(List styledStringList) { Map indexMap=new HashMap<>(); List tagList=new ArrayList<>(getStyleTags(styledStringList)); tagList.sort(this); StringArray stringsArray = getStringsArray(); int tagsSize = tagList.size(); int initialSize = stringsArray.childesCount(); stringsArray.ensureSize(initialSize + tagsSize); for(int i=0;i styledStringList, Map tagIndexMap){ StyleArray styleArray = getStyleArray(); int size=styledStringList.size(); styleArray.ensureSize(size); for(int i=0;i getStyleTags(List styledStringList){ Set results=new HashSet<>(); for(StyledString ss:styledStringList){ for(StyleSpanInfo spanInfo:ss.spanInfoList){ results.add(spanInfo.getTag()); } } return results; } @Override public int compare(String s1, String s2) { return s1.compareTo(s2); } private static class StyledString{ final String text; final List spanInfoList; StyledString(String text, List spanInfoList){ this.text=text; this.spanInfoList=spanInfoList; } @Override public String toString(){ return text; } static List fromJson(JSONArray jsonArray){ int length = jsonArray.length(); List results=new ArrayList<>(); for(int i=0;i spanInfoList = toSpanInfoList(spansArray); return new StyledString(text, spanInfoList); } private static List toSpanInfoList(JSONArray jsonArray){ int length = jsonArray.length(); List results=new ArrayList<>(length); for(int i=0;i