All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.reandroid.arsc.value.ResConfig Maven / Gradle / Ivy

There is a newer version: 1.3.5
Show newest version
/*
 *  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.arsc.value;

import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.container.FixedBlockContainer;
import com.reandroid.arsc.io.BlockLoad;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.ByteArray;
import com.reandroid.arsc.item.IntegerItem;
import com.reandroid.json.JSONConvert;
import com.reandroid.json.JSONObject;

import java.io.IOException;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ResConfig extends FixedBlockContainer
        implements BlockLoad, JSONConvert, Comparable {

    private final IntegerItem configSize;
    private final ByteArray mValuesContainer;

    private String mQualifiers;
    private int mQualifiersStamp;

    public ResConfig(){
        this(SIZE_64);
    }
    private ResConfig(int size){
        super(2);
        this.configSize = new IntegerItem(size);
        this.mValuesContainer = new ByteArray(size - 4);
        addChild(0, configSize);
        addChild(1, mValuesContainer);
        this.configSize.setBlockLoad(this);
        this.mQualifiersStamp = 0;
    }
    public boolean isEqualOrMoreSpecificThan(ResConfig resConfig){
        if(resConfig == null){
            return false;
        }
        if(resConfig == this || resConfig.isDefault()){
            return true;
        }
        byte[] bytes = ByteArray.trimTrailZeros(this.mValuesContainer.getBytes());
        byte[] otherBytes = ByteArray.trimTrailZeros(resConfig.mValuesContainer.getBytes());
        int max = otherBytes.length;
        if(max > bytes.length){
            return false;
        }
        for(int i = 0; i> 5) + ((in0 & 0x03) << 3));
            byte third = (byte) ((in0 & 0x7c) >> 2);

            out[0] = (char) (first + base);
            out[1] = (char) (second + base);
            out[2] = (char) (third + base);
        }else if (in0 != 0) {
            out = new char[2];
            out[0] = (char) in0;
            out[1] = (char) in1;
        }else {
            out = new char[2];
        }
        return out;
    }
    private static byte[] packLanguage(char[] language) {
        return packLanguageOrRegion(language, 'a');
    }
    private static byte[] packRegion(char[] region) {
        return packLanguageOrRegion(region, '0');
    }
    private static byte[] packLanguageOrRegion(char[] in, char base) {
        byte[] out = new byte[2];
        if(in == null || in.length<2){
            return out;
        }
        if (in.length == 2 || in[2] == 0 || in[2] == '-') {
            out[0] = (byte) in[0];
            out[1] = (byte) in[1];
        } else {
            byte first = (byte) ((in[0] - base) & 0x007f);
            byte second = (byte) ((in[1] - base) & 0x007f);
            byte third = (byte) ((in[2] - base) & 0x007f);

            out[0] = (byte) (0x80 | (third << 2) | (second >> 3));
            out[1] = (byte) ((second << 5) | first);
        }
        return out;
    }

    private static byte[] toByteArray(char[] chs, int len){
        byte[] bts = new byte[len];
        if(chs == null){
            return bts;
        }
        int sz = chs.length;
        for(int i = 0; i < sz; i++){
            bts[i]= (byte) chs[i];
        }
        return bts;
    }
    private static char[] toCharArray(byte[] bts){
        if(isNull(bts)){
            return null;
        }
        int sz = bts.length;
        char[] chs = new char[sz];
        for(int i = 0; i < sz; i++){
            int val = 0xff & bts[i];
            chs[i]= (char) val;
        }
        return chs;
    }
    private static char[] trimEndingZero(char[] chars){
        if(chars == null){
            return null;
        }
        int lastNonZero = -1;
        for(int i = 0; i < chars.length; i++){
            if(chars[i]!= 0){
                lastNonZero = i;
            }
        }
        if(lastNonZero==-1){
            return null;
        }
        lastNonZero = lastNonZero+1;
        if(lastNonZero== chars.length){
            return chars;
        }
        char[] result = new char[lastNonZero];
        System.arraycopy(chars, 0, result, 0, lastNonZero);
        return result;
    }
    private static boolean isNull(char[] chs){
        if(chs == null){
            return true;
        }
        for(int i = 0; i < chs.length; i++){
            if(chs[i]!= 0){
                return false;
            }
        }
        return true;
    }
    private static boolean isNull(byte[] bts){
        if(bts == null){
            return true;
        }
        for(int i = 0; i < bts.length; i++){
            if(bts[i] != 0){
                return false;
            }
        }
        return true;
    }
    private static byte[] ensureArrayLength(byte[] bts, int length){
        if(bts == null || length == 0){
            return new byte[length];
        }
        if(bts.length == length){
            return bts;
        }
        byte[] result = new byte[length];
        int max = result.length;
        if(bts.length < max){
            max = bts.length;
        }
        System.arraycopy(bts, 0, result, 0, max);
        return result;
    }
    private static String ensureLength(String str, int min, char postfix){
        int length = str.length();
        if(length >= min){
            return str;
        }
        StringBuilder builder = new StringBuilder();
        builder.append(str);
        int remain = min - length;
        for(int i = 0; i < remain; i++){
            builder.append(postfix);
        }
        return builder.toString();
    }
    private static String trimPostfix(String str, char postfix){
        if(str == null){
            return null;
        }
        int length = str.length();
        int index = length-1;
        while (length>0 && str.charAt(index) == postfix){
            str = str.substring(0, index);
            length = str.length();
            index = length - 1;
        }
        return str;
    }
    public static boolean isValidSize(int size){
        switch (size){
            case SIZE_16:
            case SIZE_28:
            case SIZE_32:
            case SIZE_36:
            case SIZE_48:
            case SIZE_52:
            case SIZE_56:
            case SIZE_64:
                return true;
            default:
                return size > SIZE_64;
        }
    }

    public static final class Orientation extends Flag{
        public static final int MASK = 0x0f;

        public static final Orientation PORT = new Orientation("port", 0x01);
        public static final Orientation LAND = new Orientation("land", 0x02);
        public static final Orientation SQUARE = new Orientation("square", 0x03);

        public static final Orientation[] VALUES = new Orientation[]{
                PORT,
                LAND,
                SQUARE
        };
        private Orientation(String name, int flag) {
            super(name, flag);
        }
        public static Orientation valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static Orientation valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static Orientation fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static Orientation fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(Orientation flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class Touchscreen extends Flag{
        public static final int MASK = 0x0f;

        public static final Touchscreen NOTOUCH = new Touchscreen("notouch", 0x01);
        public static final Touchscreen STYLUS = new Touchscreen("stylus", 0x02);
        public static final Touchscreen FINGER = new Touchscreen("finger", 0x03);

        public static final Touchscreen[] VALUES = new Touchscreen[]{
                NOTOUCH,
                STYLUS,
                FINGER
        };
        private Touchscreen(String name, int flag) {
            super(name, flag);
        }
        public static Touchscreen valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static Touchscreen valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static Touchscreen fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static Touchscreen fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(Touchscreen flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class Density extends Flag{
        public static final int MASK = 0xffff;

        public static final Density LDPI = new Density("ldpi", 120);
        public static final Density MDPI = new Density("mdpi", 160);
        public static final Density TVDPI = new Density("tvdpi", 213);
        public static final Density HDPI = new Density("hdpi", 240);
        public static final Density XHDPI = new Density("xhdpi", 320);
        public static final Density XXHDPI = new Density("xxhdpi", 480);
        public static final Density XXXHDPI = new Density("xxxhdpi", 640);
        public static final Density ANYDPI = new Density("anydpi", 0xfffe);
        public static final Density NODPI = new Density("nodpi", 0xffff);

        public static final Density[] VALUES = new Density[]{LDPI,
                MDPI,
                TVDPI,
                HDPI,
                XHDPI,
                XXHDPI,
                XXXHDPI,
                ANYDPI,
                NODPI
        };
        private Density(String name, int flag) {
            super(name, flag);
        }
        public static Density valueOf(int flag){
            if(flag== 0){
                return null;
            }
            Density density = Flag.valueOf(VALUES, MASK, flag);
            if(density == null){
                flag = flag & MASK;
                density = new Density(flag+"dpi", flag);
            }
            return density;
        }
        public static Density valueOf(String name){
            if(name == null || name.length() < 4){
                return null;
            }
            name = name.toLowerCase();
            if(name.charAt(0) == '-'){
                name = name.substring(1);
            }
            Density density = Flag.valueOf(VALUES, name);
            if(density == null && name.endsWith("dpi")){
                name = name.substring(0, name.length()-3);
                try{
                    int flag = Integer.parseInt(name);
                    density = new Density(flag+"dpi", flag);
                }catch (NumberFormatException ignored){
                }
            }
            return density;
        }
        public static Density fromQualifiers(String qualifiers){
            return fromQualifiers(qualifiers.split("\\s*-\\s*"));
        }
        public static Density fromQualifiers(String[] qualifiers){
            if(qualifiers == null){
                return null;
            }
            for(int i = 0; i < qualifiers.length; i++){
                Density density = valueOf(qualifiers[i]);
                if(density== null){
                    continue;
                }
                qualifiers[i] = null;
                return density;
            }
            return null;
        }
        public static int update(Density flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class Keyboard extends Flag{
        public static final int MASK = 0x0f;

        public static final Keyboard NOKEYS = new Keyboard("nokeys", 0x01);
        public static final Keyboard QWERTY = new Keyboard("qwerty", 0x02);
        public static final Keyboard KEY12 = new Keyboard("12key", 0x03);

        public static final Keyboard[] VALUES = new Keyboard[]{
                NOKEYS,
                QWERTY,
                KEY12
        };
        private Keyboard(String name, int flag) {
            super(name, flag);
        }
        public static Keyboard valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static Keyboard valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static Keyboard fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static Keyboard fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(Keyboard flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class Navigation extends Flag{
        public static final int MASK = 0x0f;

        public static final Navigation NONAV = new Navigation("nonav", 0x01);
        public static final Navigation DPAD = new Navigation("dpad", 0x02);
        public static final Navigation TRACKBALL = new Navigation("trackball", 0x03);
        public static final Navigation WHEEL = new Navigation("wheel", 0x04);
        public static final Navigation[] VALUES = new Navigation[]{
                NONAV,
                DPAD,
                TRACKBALL,
                WHEEL
        };
        private Navigation(String name, int flag) {
            super(name, flag);
        }
        public static Navigation valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static Navigation valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static Navigation fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static Navigation fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(Navigation flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class InputFlagsKeysHidden extends Flag{
        public static final int MASK = 0x03;

        public static final InputFlagsKeysHidden KEYSEXPOSED = new InputFlagsKeysHidden("keysexposed", 0x01);
        public static final InputFlagsKeysHidden KEYSHIDDEN = new InputFlagsKeysHidden("keyshidden", 0x02);
        public static final InputFlagsKeysHidden KEYSSOFT = new InputFlagsKeysHidden("keyssoft", 0x03);
        public static final InputFlagsKeysHidden[] VALUES = new InputFlagsKeysHidden[]{
                KEYSEXPOSED,
                KEYSHIDDEN,
                KEYSSOFT
        };
        private InputFlagsKeysHidden(String name, int flag) {
            super(name, flag);
        }
        public static InputFlagsKeysHidden valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static InputFlagsKeysHidden valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static InputFlagsKeysHidden fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static InputFlagsKeysHidden fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(InputFlagsKeysHidden flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class InputFlagsNavHidden extends Flag{
        public static final int MASK = 0x0C;

        public static final InputFlagsNavHidden NAVEXPOSED = new InputFlagsNavHidden("navexposed", 0x04);
        public static final InputFlagsNavHidden NAVHIDDEN = new InputFlagsNavHidden("navhidden", 0x08);
        public static final InputFlagsNavHidden[] VALUES = new InputFlagsNavHidden[]{
                NAVEXPOSED,
                NAVHIDDEN
        };
        private InputFlagsNavHidden(String name, int flag) {
            super(name, flag);
        }
        public static InputFlagsNavHidden valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static InputFlagsNavHidden valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static InputFlagsNavHidden fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static InputFlagsNavHidden fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(InputFlagsNavHidden flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class UiModeType extends Flag{
        public static final int MASK = 0x0f;

        public static final UiModeType NORMAL = new UiModeType("normal", 0x01);
        public static final UiModeType DESK = new UiModeType("desk", 0x02);
        public static final UiModeType CAR = new UiModeType("car", 0x03);
        public static final UiModeType TELEVISION = new UiModeType("television", 0x04);
        public static final UiModeType APPLIANCE = new UiModeType("appliance", 0x05);
        public static final UiModeType WATCH = new UiModeType("watch", 0x06);
        public static final UiModeType VRHEADSET = new UiModeType("vrheadset", 0x07);
        public static final UiModeType GODZILLAUI = new UiModeType("godzillaui", 0x0b);
        public static final UiModeType SMALLUI = new UiModeType("smallui", 0x0c);
        public static final UiModeType MEDIUMUI = new UiModeType("mediumui", 0x0d);
        public static final UiModeType LARGEUI = new UiModeType("largeui", 0x0e);
        public static final UiModeType HUGEUI = new UiModeType("hugeui", 0x0f);

        private static final UiModeType[] VALUES = new UiModeType[]{
                NORMAL,
                DESK,
                CAR,
                TELEVISION,
                APPLIANCE,
                WATCH,
                VRHEADSET,
                GODZILLAUI,
                SMALLUI,
                MEDIUMUI,
                LARGEUI,
                HUGEUI
        };

        private UiModeType(String name, int flag) {
            super(name, flag);
        }
        public static UiModeType valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static UiModeType valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static UiModeType fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static UiModeType fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(UiModeType flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class UiModeNight extends Flag{
        public static final int MASK = 0x30;
        public static final UiModeNight NOTNIGHT = new UiModeNight("notnight",0x10);
        public static final UiModeNight NIGHT = new UiModeNight("night",0x20);
        private static final UiModeNight[] VALUES = new UiModeNight[]{
                NOTNIGHT,
                NIGHT
        };
        private UiModeNight(String name, int flag) {
            super(name, flag);
        }
        public static UiModeNight valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static UiModeNight valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static UiModeNight fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static UiModeNight fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(UiModeNight flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class ScreenLayoutSize extends Flag{
        public static final int MASK = 0x0f;

        public static final ScreenLayoutSize SMALL = new ScreenLayoutSize("small", 0x01);
        public static final ScreenLayoutSize NORMAL = new ScreenLayoutSize("normal", 0x02);
        public static final ScreenLayoutSize LARGE = new ScreenLayoutSize("large", 0x03);
        public static final ScreenLayoutSize XLARGE = new ScreenLayoutSize("xlarge", 0x04);
        public static final ScreenLayoutSize[] VALUES = new ScreenLayoutSize[]{
                SMALL,
                NORMAL,
                LARGE,
                XLARGE
        };
        private ScreenLayoutSize(String name, int flag) {
            super(name, flag);
        }
        public static ScreenLayoutSize valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static ScreenLayoutSize valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static ScreenLayoutSize fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static ScreenLayoutSize fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(ScreenLayoutSize flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class ScreenLayoutLong extends Flag{
        public static final int MASK = 0x30;
        public static final ScreenLayoutLong NOTLONG = new ScreenLayoutLong("notlong", 0x10);
        public static final ScreenLayoutLong LONG = new ScreenLayoutLong("long", 0x20);
        public static final ScreenLayoutLong[] VALUES = new ScreenLayoutLong[]{
                NOTLONG,
                LONG
        };
        private ScreenLayoutLong(String name, int flag) {
            super(name, flag);
        }
        public static ScreenLayoutLong valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static ScreenLayoutLong valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static ScreenLayoutLong fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static ScreenLayoutLong fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(ScreenLayoutLong flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class ScreenLayoutDir extends Flag{
        public static final int MASK = 0xC0;
        public static final ScreenLayoutDir LDLTR = new ScreenLayoutDir("ldltr", 0x40);
        public static final ScreenLayoutDir LDRTL = new ScreenLayoutDir("ldrtl", 0x80);
        public static final ScreenLayoutDir[] VALUES = new ScreenLayoutDir[]{
                LDLTR,
                LDRTL
        };
        private ScreenLayoutDir(String name, int flag) {
            super(name, flag);
        }
        public static ScreenLayoutDir valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static ScreenLayoutDir valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static ScreenLayoutDir fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static ScreenLayoutDir fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(ScreenLayoutDir flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class ScreenLayoutRound extends Flag{
        public static final int MASK = 0x03;
        public static final ScreenLayoutRound NOTROUND = new ScreenLayoutRound("notround", 0x01);
        public static final ScreenLayoutRound ROUND = new ScreenLayoutRound("round", 0x02);
        public static final ScreenLayoutRound[] VALUES = new ScreenLayoutRound[]{
                NOTROUND,
                ROUND
        };
        private ScreenLayoutRound(String name, int flag) {
            super(name, flag);
        }
        public static ScreenLayoutRound valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static ScreenLayoutRound valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static ScreenLayoutRound fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static ScreenLayoutRound fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(ScreenLayoutRound flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class ColorModeWide extends Flag{
        public static final int MASK = 0x03;
        public static final ColorModeWide NOWIDECG = new ColorModeWide("nowidecg", 0x01);
        public static final ColorModeWide WIDECG = new ColorModeWide("widecg", 0x02);
        public static final ColorModeWide[] VALUES = new ColorModeWide[]{
                NOWIDECG,
                WIDECG
        };
        private ColorModeWide(String name, int flag) {
            super(name, flag);
        }
        public static ColorModeWide valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static ColorModeWide valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static ColorModeWide fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static ColorModeWide fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(ColorModeWide flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }
    public static final class ColorModeHdr extends Flag{
        public static final int MASK = 0x0C;
        public static final ColorModeHdr LOWDR = new ColorModeHdr("lowdr", 0x04);
        public static final ColorModeHdr HIGHDR = new ColorModeHdr("highdr", 0x08);
        public static final ColorModeHdr[] VALUES = new ColorModeHdr[]{
                LOWDR,
                HIGHDR
        };
        private ColorModeHdr(String name, int flag) {
            super(name, flag);
        }
        public static ColorModeHdr valueOf(int flag){
            return Flag.valueOf(VALUES, MASK, flag);
        }
        public static ColorModeHdr valueOf(String name){
            return Flag.valueOf(VALUES, name);
        }
        public static ColorModeHdr fromQualifiers(String qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static ColorModeHdr fromQualifiers(String[] qualifiers){
            return Flag.fromQualifiers(VALUES, qualifiers);
        }
        public static int update(ColorModeHdr flag, int value){
            return Flag.update(MASK, flag, value);
        }
    }

    static class Flag{
        private final String name;
        private final int flag;
        Flag(String name, int flag){
            this.name = name;
            this.flag = flag;
        }
        public int getFlag() {
            return flag;
        }
        @Override
        public boolean equals(Object obj) {
            return obj == this;
        }
        @Override
        public int hashCode() {
            return super.hashCode();
        }
        @Override
        public String toString() {
            return name;
        }
        public static String toString(Flag flag){
            if(flag!= null){
                return flag.toString();
            }
            return null;
        }
        static T fromQualifiers(T[] values, String qualifiers){
            if(qualifiers == null){
                return null;
            }
            return fromQualifiers(values, qualifiers.split("\\s*-\\s*"));
        }
        static T fromQualifiers(T[] values, String[] qualifiers){
            if(qualifiers == null){
                return null;
            }
            for(int i = 0; i < qualifiers.length; i++){
                T flag = Flag.valueOf(values, qualifiers[i]);
                if(flag != null){
                    qualifiers[i] = null;
                    return flag;
                }
            }
            return null;
        }
        static T valueOf(T[] values, int mask, int flagValue){
            flagValue = flagValue & mask;
            for(T flag:values){
                if(flagValue == flag.getFlag()){
                    return flag;
                }
            }
            return null;
        }
        static T valueOf(T[] values, String name){
            if(name == null || name.length() == 0){
                return null;
            }
            if(name.charAt(0) == '-'){
                name = name.substring(1);
            }
            name = name.toLowerCase();
            for(T flag:values){
                if(name.equals(flag.toString())){
                    return flag;
                }
            }
            return null;
        }
        public static int update(int mask, Flag flag, int value){
            int flip = (~mask) & 0xff;
            value = value & flip;
            if(flag != null){
                value = value | flag.getFlag();
            }
            return value;
        }
    }

    static class QualifierBuilder{
        private final ResConfig mConfig;
        private StringBuilder mBuilder;
        public QualifierBuilder(ResConfig resConfig){
            this.mConfig = resConfig;
        }
        public String build(){
            ResConfig resConfig = this.mConfig;
            if(resConfig.isDefault()){
                return "";
            }
            this.mBuilder = new StringBuilder();
            appendPrefixedNumber("mcc", resConfig.getMcc());
            appendPrefixedNumber("mnc", resConfig.getMnc());

            appendLanguageAndRegion();

            appendFlag(resConfig.getOrientation());
            appendFlag(resConfig.getTouchscreen());
            appendFlag(resConfig.getDensity());
            appendFlag(resConfig.getKeyboard());
            appendFlag(resConfig.getNavigation());
            appendFlag(resConfig.getInputFlagsKeysHidden());
            appendFlag(resConfig.getInputFlagsNavHidden());

            appendScreenWidthHeight();

            appendPrefixedNumber("v", resConfig.getSdkVersion());
            // append resConfig.getMinorVersion()
            appendFlag(resConfig.getScreenLayoutSize());
            appendFlag(resConfig.getScreenLayoutLong());
            appendFlag(resConfig.getScreenLayoutDir());

            appendFlag(resConfig.getUiModeType());
            appendFlag(resConfig.getUiModeNight());

            appendDp("sw", resConfig.getSmallestScreenWidthDp());
            appendDp("w", resConfig.getScreenWidthDp());
            appendDp("h", resConfig.getScreenHeightDp());

            appendFlag(resConfig.getScreenLayoutRound());

            appendFlag(resConfig.getColorModeWide());
            appendFlag(resConfig.getColorModeHdr());

            appendLocaleNumberingSystem();

            return mBuilder.toString();
        }
        private void appendScreenWidthHeight(){
            ResConfig resConfig = this.mConfig;
            int width = resConfig.getScreenWidth();
            int height = resConfig.getScreenHeight();
            if(width == 0 && height == 0){
                return;
            }
            mBuilder.append('-').append(width).append('x').append(height);
        }
        private void appendLanguageAndRegion(){
            ResConfig resConfig = this.mConfig;
            String language = resConfig.getLanguage();
            String region = resConfig.getRegion();
            String script = resConfig.getLocaleScript();
            String variant = resConfig.getLocaleVariant();
            if(language == null && region == null){
                return;
            }
            StringBuilder builder = this.mBuilder;
            char separator;
            if(script != null || variant != null){
                builder.append('-');
                builder.append('b');
                separator = '+';
            }else {
                separator = '-';
            }
            if(language!= null){
                builder.append(separator);
                builder.append(language);
            }
            if(region!= null){
                builder.append(separator);
                if(region.length() == 2){
                    builder.append('r');
                }
                builder.append(region);
            }
            if(script!= null){
                builder.append(separator);
                builder.append(script);
            }
            if(variant!= null){
                builder.append(separator);
                builder.append(variant);
            }
        }
        private void appendLocaleNumberingSystem(){
            String numberingSystem = mConfig.getLocaleNumberingSystem();
            if(numberingSystem== null){
                return;
            }
            StringBuilder builder = mBuilder;
            builder.append("-u+nu+");
            builder.append(numberingSystem);
        }
        private void appendFlag(ResConfig.Flag flag){
            if(flag== null){
                return;
            }
            mBuilder.append('-').append(flag.toString());
        }
        private void appendDp(String prefix, int number){
            if(number == 0){
                return;
            }
            StringBuilder builder = this.mBuilder;
            builder.append('-');
            if(prefix!= null){
                builder.append(prefix);
            }
            builder.append(number);
            builder.append("dp");
        }
        private void appendPrefixedNumber(String prefix, int number){
            if(number == 0){
                return;
            }
            StringBuilder builder = this.mBuilder;
            builder.append('-');
            builder.append(prefix);
            builder.append(number);
        }
    }
    static class QualifierParser{
        private final ResConfig mConfig;
        private final String[] mQualifiers;
        private final int mPreferredSize;
        private boolean mEmpty;
        private boolean mLanguageRegionParsed;
        private boolean mParseComplete;

        public QualifierParser(ResConfig resConfig, String[] qualifiers){
            this.mConfig = resConfig;
            this.mQualifiers = qualifiers;
            this.mPreferredSize = resConfig.getConfigSize();
        }
        public QualifierParser(ResConfig resConfig, String qualifiers){
            this(resConfig, splitQualifiers(qualifiers));
        }

        public void parse(){
            if(this.mParseComplete){
                return;
            }
            if(isEmpty()){
                onParseComplete();
                return;
            }
            ResConfig resConfig = this.mConfig;
            resConfig.setConfigSize(ResConfig.SIZE_64);
            parsePrefixedNumber();
            parseDp();
            parseWidthHeight();
            parseLocaleNumberingSystem();
            if(isEmpty()){
                onParseComplete();
                return;
            }
            String[] qualifiers = this.mQualifiers;
            resConfig.setOrientation(ResConfig.Orientation.fromQualifiers(qualifiers));
            resConfig.setTouchscreen(ResConfig.Touchscreen.fromQualifiers(qualifiers));
            resConfig.setDensity(ResConfig.Density.fromQualifiers(qualifiers));
            resConfig.setKeyboard(ResConfig.Keyboard.fromQualifiers(qualifiers));
            resConfig.setNavigation(ResConfig.Navigation.fromQualifiers(qualifiers));
            if(isEmpty()){
                onParseComplete();
                return;
            }
            resConfig.setInputFlagsKeysHidden(ResConfig.InputFlagsKeysHidden.fromQualifiers(qualifiers));
            resConfig.setInputFlagsNavHidden(ResConfig.InputFlagsNavHidden.fromQualifiers(qualifiers));
            resConfig.setScreenLayoutSize(ResConfig.ScreenLayoutSize.fromQualifiers(qualifiers));
            resConfig.setScreenLayoutLong(ResConfig.ScreenLayoutLong.fromQualifiers(qualifiers));
            resConfig.setScreenLayoutDir(ResConfig.ScreenLayoutDir.fromQualifiers(qualifiers));
            if(isEmpty()){
                onParseComplete();
                return;
            }
            resConfig.setUiModeType(ResConfig.UiModeType.fromQualifiers(qualifiers));
            resConfig.setUiModeNight(ResConfig.UiModeNight.fromQualifiers(qualifiers));

            resConfig.setScreenLayoutRound(ResConfig.ScreenLayoutRound.fromQualifiers(qualifiers));

            resConfig.setColorModeWide(ResConfig.ColorModeWide.fromQualifiers(qualifiers));
            resConfig.setColorModeHdr(ResConfig.ColorModeHdr.fromQualifiers(qualifiers));
            if(isEmpty()){
                onParseComplete();
                return;
            }
            parseLocaleScriptVariant();
            parseLanguage();
            parseRegion();
            onParseComplete();
        }
        public String[] getErrors(){
            if(!this.mParseComplete){
                return null;
            }
            String[] qualifiers = this.mQualifiers;
            if(qualifiers == null || qualifiers.length == 0){
                return null;
            }
            int length = qualifiers.length;
            String[] tmp = new String[length];
            int count = 0;
            for(int i = 0; i < length; i++){
                String qualifier = qualifiers[i];
                if(qualifier == null || qualifier.length() == 0){
                    continue;
                }
                tmp[count] = qualifier;
                count++;
            }
            if(count == 0){
                return null;
            }
            if(count == length){
                return tmp;
            }
            String[] errors = new String[count];
            System.arraycopy(tmp, 0, errors, 0, count);
            return errors;
        }
        private void onParseComplete(){
            this.mConfig.trimToSize(this.mPreferredSize);
            this.mParseComplete = true;
        }

        private void parsePrefixedNumber(){
            if(isEmpty()){
                return;
            }
            String[] qualifiers = this.mQualifiers;
            for(int i = 0; i < qualifiers.length; i++){
                if(parsePrefixedNumber(qualifiers[i])){
                    qualifiers[i] = null;
                }
            }
        }
        private boolean parsePrefixedNumber(String qualifier){
            if(qualifier == null){
                return false;
            }
            Matcher matcher = PATTERN_PREFIX_NUMBER.matcher(qualifier);
            if(!matcher.find()){
                return false;
            }
            String prefix = matcher.group(1);
            int value = Integer.parseInt(matcher.group(2));
            ResConfig resConfig = mConfig;
            if("mcc".equals(prefix)){
                resConfig.setMcc(value);
            }else if("mnc".equals(prefix)) {
                resConfig.setMnc(value);
            }else if("v".equals(prefix)){
                resConfig.setSdkVersion(value);
            }else {
                return false;
            }
            return true;
        }
        private void parseDp(){
            if(isEmpty()){
                return;
            }
            String[] qualifiers = this.mQualifiers;
            for(int i = 0; i < qualifiers.length; i++){
                if(parseDp(qualifiers[i])){
                    qualifiers[i] = null;
                }
            }
        }
        private boolean parseDp(String qualifier){
            if(qualifier == null){
                return false;
            }
            Matcher matcher = PATTERN_DP.matcher(qualifier);
            if(!matcher.find()){
                return false;
            }
            String prefix = matcher.group(1);
            int value = Integer.parseInt(matcher.group(2));
            ResConfig resConfig = this.mConfig;
            if("sw".equals(prefix)){
                resConfig.setSmallestScreenWidthDp(value);
            }else if("w".equals(prefix)) {
                resConfig.setScreenWidthDp(value);
            }else if("h".equals(prefix)){
                resConfig.setScreenHeightDp(value);
            }else {
                return false;
            }
            return true;
        }
        private void parseWidthHeight(){
            if(isEmpty()){
                return;
            }
            String[] qualifiers = this.mQualifiers;
            for(int i = 0; i < qualifiers.length; i++){
                if(parseWidthHeight(qualifiers[i])){
                    qualifiers[i] = null;
                    return;
                }
            }
        }
        private boolean parseWidthHeight(String qualifier){
            if(qualifier == null){
                return false;
            }
            Matcher matcher = PATTERN_WIDTH_HEIGHT.matcher(qualifier);
            if(!matcher.find()){
                return false;
            }
            int width = Integer.parseInt(matcher.group(1));
            int height = Integer.parseInt(matcher.group(2));
            ResConfig resConfig = this.mConfig;
            resConfig.setScreenWidth(width);
            resConfig.setScreenHeight(height);
            return true;
        }
        private void parseLocaleNumberingSystem(){
            if(isEmpty()){
                return;
            }
            String[] qualifiers = this.mQualifiers;
            for(int i = 0; i < qualifiers.length; i++){
                if(parseLocaleNumberingSystem(qualifiers[i])){
                    qualifiers[i] = null;
                    return;
                }
            }
        }
        private boolean parseLocaleNumberingSystem(String qualifier){
            if(qualifier == null){
                return false;
            }
            Matcher matcher = PATTERN_LOCALE_NUMBERING_SYSTEM.matcher(qualifier);
            if(!matcher.find()){
                return false;
            }
            this.mConfig.setLocaleNumberingSystem(matcher.group(1));
            return true;
        }
        private void parseLocaleScriptVariant(){
            if(this.mLanguageRegionParsed || isEmpty()){
                return;
            }
            String[] qualifiers = this.mQualifiers;
            for(int i = 0; i < qualifiers.length; i++){
                if(parseLocaleScriptVariant(qualifiers[i])){
                    qualifiers[i] = null;
                    this.mLanguageRegionParsed = true;
                    return;
                }
            }
        }
        private boolean parseLocaleScriptVariant(String qualifier){
            if(qualifier == null || qualifier.length() < 4 ){
                return false;
            }
            char[] chars = qualifier.toCharArray();
            if(chars[0] != 'b' || chars[1] != '+'){
                return false;
            }
            Matcher matcher = PATTERN_LOCALE_SCRIPT_VARIANT.matcher(qualifier);
            if(!matcher.find()){
                return false;
            }
            String language = trimPlus(matcher.group(1));
            String region = trimPlus(matcher.group(2));
            String script = trimPlus(matcher.group(3));
            String variant = trimPlus(matcher.group(4));
            if(script == null && variant == null){
                return false;
            }
            ResConfig resConfig = this.mConfig;
            resConfig.setLanguage(language);
            resConfig.setRegion(region);
            resConfig.setLocaleScript(script);
            resConfig.setLocaleVariant(variant);
            return true;
        }

        private void parseLanguage(){
            if(mLanguageRegionParsed || isEmpty()){
                return;
            }
            String[] qualifiers = this.mQualifiers;
            for(int i = 0; i < qualifiers.length; i++){
                if(parseLanguage(qualifiers[i])){
                    qualifiers[i] = null;
                    return;
                }
            }
        }
        private boolean parseLanguage(String qualifier){
            if(!isLanguage(qualifier)){
                return false;
            }
            this.mConfig.setLanguage(qualifier);
            return true;
        }
        private void parseRegion(){
            if(mLanguageRegionParsed || isEmpty()){
                return;
            }
            String[] qualifiers = this.mQualifiers;
            for(int i = 0; i < qualifiers.length; i++){
                if(parseRegion(qualifiers[i])){
                    qualifiers[i] = null;
                    return;
                }
            }
        }
        private boolean parseRegion(String qualifier){
            if(!isRegion(qualifier)){
                return false;
            }
            this.mConfig.setRegion(qualifier);
            return true;
        }


        private boolean isEmpty(){
            if(!mEmpty){
                mEmpty = isEmpty(mQualifiers);
            }
            return mEmpty;
        }

        private static boolean isEmpty(String[] qualifiers){
            if(qualifiers == null){
                return true;
            }
            for(int i = 0; i < qualifiers.length; i++){
                String qualifier = qualifiers[i];
                if(qualifier == null){
                    continue;
                }
                if(qualifier.length() == 0){
                    qualifiers[i] = null;
                    continue;
                }
                return false;
            }
            return true;
        }
        private static String trimPlus(String text){
            if(text == null||text.length() == 0){
                return null;
            }
            if(text.charAt(0) == '+'){
                text = text.substring(1);
            }
            return text;
        }
        private static boolean isLanguage(String qualifier){
            if(qualifier == null){
                return false;
            }
            char[] chars = qualifier.toCharArray();
            int length = chars.length;
            if(length != 2  && length !=3 ){
                return false;
            }
            for(int i = 0; i < length; i++){
                if(!isAtoZLower(chars[i])) {
                    return false;
                }
            }
            return true;
        }
        private static boolean isRegion(String qualifier){
            if(qualifier == null || qualifier.length() != 3){
                return false;
            }
            char[] chars = qualifier.toCharArray();
            boolean checkDigit = false;
            for(int i = 0; i < chars.length; i++){
                char ch = chars[i];
                if(i == 0){
                    if(ch == 'r'){
                        continue;
                    }
                    checkDigit = isDigit(ch);
                    if(checkDigit){
                        continue;
                    }
                    return false;
                }
                if(checkDigit){
                    if(!isDigit(ch)){
                        return false;
                    }
                }else if(!isAtoZUpper(ch)) {
                    return false;
                }
            }
            return true;
        }
        private static String[] splitQualifiers(String qualifier){
            if(qualifier == null || qualifier.length() == 0){
                return null;
            }
            return qualifier.split("-");
        }
        private static boolean isDigit(char ch){
            return ch <= '9' && ch >= '0';
        }
        private static boolean isAtoZLower(char ch){
            return ch <= 'z' && ch >= 'a';
        }
        private static boolean isAtoZUpper(char ch){
            return ch <= 'Z' && ch >= 'A';
        }

        private static final Pattern PATTERN_PREFIX_NUMBER = Pattern.compile("^([mcnv]+)([0-9]+)$");
        private static final Pattern PATTERN_DP = Pattern.compile("^([swh]+)([0-9]+)dp$");
        private static final Pattern PATTERN_WIDTH_HEIGHT = Pattern.compile("^([0-9]+)[xX]([0-9]+)$");
        private static final Pattern PATTERN_LOCALE_NUMBERING_SYSTEM = Pattern.compile("^u\\+nu\\+(.{1,8})$");
        private static final Pattern PATTERN_LOCALE_SCRIPT_VARIANT = Pattern.compile("^b(\\+[a-z]{2})?(\\+r[A-Z]{2})?(\\+[A-Z][a-z]{3})?(\\+[A-Z]{2,8})?$");
    }

    public static final int SIZE_16 = 16;
    public static final int SIZE_28 = 28;
    public static final int SIZE_32 = 32;
    public static final int SIZE_36 = 36;
    public static final int SIZE_48 = 48;
    public static final int SIZE_52 = 52;
    public static final int SIZE_56 = 56;
    public static final int SIZE_64 = 64;

    private static final int OFFSET_mcc = 0;
    private static final int OFFSET_mnc = 2;
    private static final int OFFSET_language = 4;
    private static final int OFFSET_region = 6;
    private static final int OFFSET_orientation = 8;
    private static final int OFFSET_touchscreen = 9;
    private static final int OFFSET_density = 10;
    //SIZE=16
    private static final int OFFSET_keyboard = 12;
    private static final int OFFSET_navigation = 13;
    private static final int OFFSET_inputFlags = 14;
    private static final int OFFSET_inputPad0 = 15;
    private static final int OFFSET_screenWidth = 16;
    private static final int OFFSET_screenHeight = 18;
    private static final int OFFSET_sdkVersion = 20;
    private static final int OFFSET_minorVersion = 22;
    //SIZE=28
    private static final int OFFSET_screenLayout = 24;
    private static final int OFFSET_uiMode = 25;
    private static final int OFFSET_smallestScreenWidthDp = 26;
    //SIZE=32
    private static final int OFFSET_screenWidthDp = 28;
    private static final int OFFSET_screenHeightDp = 30;
    //SIZE=36
    private static final int OFFSET_localeScript = 32;
    private static final int OFFSET_localeVariant = 36;
    //SIZE=48
    private static final int OFFSET_screenLayout2 = 44;
    private static final int OFFSET_colorMode = 45;
    private static final int OFFSET_reservedPadding = 46;
    //SIZE=52
    private static final int OFFSET_localeNumberingSystem = 48;
    //SIZE=60

    private static final int LEN_localeScript = 4;
    private static final int LEN_localeVariant = 8;
    private static final int LEN_localeNumberingSystem = 8;

    private static final String NAME_mcc = "mcc";
    private static final String NAME_mnc = "mnc";
    private static final String NAME_language = "language";
    private static final String NAME_region = "region";
    private static final String NAME_orientation = "orientation";
    private static final String NAME_touchscreen = "touchscreen";
    private static final String NAME_density = "density";
    //SIZE=16
    private static final String NAME_keyboard = "keyboard";
    private static final String NAME_navigation = "navigation";
    private static final String NAME_input_flags_keys_hidden = "input_flags_keys_hidden";
    private static final String NAME_input_flags_nav_hidden = "input_flags_nav_hidden";
    private static final String NAME_inputPad0 = "inputPad0";
    private static final String NAME_screenWidth = "screenWidth";
    private static final String NAME_screenHeight = "screenHeight";
    private static final String NAME_sdkVersion = "sdkVersion";
    private static final String NAME_minorVersion = "minorVersion";
    //SIZE=28
    private static final String NAME_screen_layout_size = "screen_layout_size";
    private static final String NAME_screen_layout_long = "screen_layout_long";
    private static final String NAME_screen_layout_dir = "screen_layout_dir";
    private static final String NAME_ui_mode_type = "ui_mode_type";
    private static final String NAME_ui_mode_night = "ui_mode_night";
    private static final String NAME_smallestScreenWidthDp = "smallestScreenWidthDp";
    //SIZE=32 = "";
    private static final String NAME_screenWidthDp = "screenWidthDp";
    private static final String NAME_screenHeightDp = "screenHeightDp";
    //SIZE=36
    private static final String NAME_localeScript = "localeScript";
    private static final String NAME_localeVariant = "localeVariant";
    private static final String NAME_screen_layout_round = "screen_layout_round";
    private static final String NAME_color_mode_wide = "color_mode_wide";
    private static final String NAME_color_mode_hdr = "color_mode_hdr";

    private static final String NAME_localeNumberingSystem = "localeNumberingSystem";

    private static final char POSTFIX_locale = '#';

    private static final ResConfig DEFAULT_INSTANCE = new ResConfig(SIZE_16);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy