1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/*
5 *******************************************************************************
6 * Copyright (C) 2015-2016, International Business Machines Corporation and
7 * others. All Rights Reserved.
8 *******************************************************************************
9 */
10package android.icu.impl;
11
12import java.nio.ByteBuffer;
13
14import android.icu.util.UResourceBundle;
15import android.icu.util.UResourceTypeMismatchException;
16
17// Class UResource is named consistently with the public class UResourceBundle,
18// in case we want to make it public at some point.
19
20/**
21 * ICU resource bundle key and value types.
22 * @hide Only a subset of ICU is exposed in Android
23 */
24public final class UResource {
25    /**
26     * Represents a resource bundle item's key string.
27     * Avoids object creations as much as possible.
28     * Mutable, not thread-safe.
29     * For permanent storage, use clone() or toString().
30     */
31    public static final class Key implements CharSequence, Cloneable, Comparable<Key> {
32        // Stores a reference to the resource bundle key string bytes array,
33        // with an offset of the key, to avoid creating a String object
34        // until one is really needed.
35        // Alternatively, we could try to always just get the key String object,
36        // and cache it in the reader, and see if that performs better or worse.
37        private byte[] bytes;
38        private int offset;
39        private int length;
40        private String s;
41
42        /**
43         * Constructs an empty resource key string object.
44         */
45        public Key() {
46            s = "";
47        }
48
49        /**
50         * Constructs a resource key object equal to the given string.
51         */
52        public Key(String s) {
53            setString(s);
54        }
55
56        private Key(byte[] keyBytes, int keyOffset, int keyLength) {
57            bytes = keyBytes;
58            offset = keyOffset;
59            length = keyLength;
60        }
61
62        /**
63         * Mutates this key for a new NUL-terminated resource key string.
64         * The corresponding ASCII-character bytes are not copied and
65         * must not be changed during the lifetime of this key
66         * (or until the next setBytes() call)
67         * and lifetimes of subSequences created from this key.
68         *
69         * @param keyBytes new key string byte array
70         * @param keyOffset new key string offset
71         */
72        public Key setBytes(byte[] keyBytes, int keyOffset) {
73            bytes = keyBytes;
74            offset = keyOffset;
75            for (length = 0; keyBytes[keyOffset + length] != 0; ++length) {}
76            s = null;
77            return this;
78        }
79
80        /**
81         * Mutates this key to an empty resource key string.
82         */
83        public Key setToEmpty() {
84            bytes = null;
85            offset = length = 0;
86            s = "";
87            return this;
88        }
89
90        /**
91         * Mutates this key to be equal to the given string.
92         */
93        public Key setString(String s) {
94            if (s.isEmpty()) {
95                setToEmpty();
96            } else {
97                bytes = new byte[s.length()];
98                offset = 0;
99                length = s.length();
100                for (int i = 0; i < length; ++i) {
101                    char c = s.charAt(i);
102                    if (c <= 0x7f) {
103                        bytes[i] = (byte)c;
104                    } else {
105                        throw new IllegalArgumentException('\"' + s + "\" is not an ASCII string");
106                    }
107                }
108                this.s = s;
109            }
110            return this;
111        }
112
113        /**
114         * {@inheritDoc}
115         * Does not clone the byte array.
116         */
117        @Override
118        public Key clone() {
119            try {
120                return (Key)super.clone();
121            } catch (CloneNotSupportedException cannotOccur) {
122                return null;
123            }
124        }
125
126        @Override
127        public char charAt(int i) {
128            assert(0 <= i && i < length);
129            return (char)bytes[offset + i];
130        }
131
132        @Override
133        public int length() {
134            return length;
135        }
136
137        @Override
138        public Key subSequence(int start, int end) {
139            assert(0 <= start && start < length);
140            assert(start <= end && end <= length);
141            return new Key(bytes, offset + start, end - start);
142        }
143
144        /**
145         * Creates/caches/returns this resource key string as a Java String.
146         */
147        @Override
148        public String toString() {
149            if (s == null) {
150                s = internalSubString(0, length);
151            }
152            return s;
153        }
154
155        private String internalSubString(int start, int end) {
156            StringBuilder sb = new StringBuilder(end - start);
157            for (int i = start; i < end; ++i) {
158                sb.append((char)bytes[offset + i]);
159            }
160            return sb.toString();
161        }
162
163        /**
164         * Creates a new Java String for a sub-sequence of this resource key string.
165         */
166        public String substring(int start) {
167            assert(0 <= start && start < length);
168            return internalSubString(start, length);
169        }
170
171        /**
172         * Creates a new Java String for a sub-sequence of this resource key string.
173         */
174        public String substring(int start, int end) {
175            assert(0 <= start && start < length);
176            assert(start <= end && end <= length);
177            return internalSubString(start, end);
178        }
179
180        private boolean regionMatches(byte[] otherBytes, int otherOffset, int n) {
181            for (int i = 0; i < n; ++i) {
182                if (bytes[offset + i] != otherBytes[otherOffset + i]) {
183                    return false;
184                }
185            }
186            return true;
187        }
188
189        private boolean regionMatches(int start, CharSequence cs, int n) {
190            for (int i = 0; i < n; ++i) {
191                if (bytes[offset + start + i] != cs.charAt(i)) {
192                    return false;
193                }
194            }
195            return true;
196        }
197
198        @Override
199        public boolean equals(Object other) {
200            if (other == null) {
201                return false;
202            } else if (this == other) {
203                return true;
204            } else if (other instanceof Key) {
205                Key otherKey = (Key)other;
206                return length == otherKey.length &&
207                        regionMatches(otherKey.bytes, otherKey.offset, length);
208            } else {
209                return false;
210            }
211        }
212
213        public boolean contentEquals(CharSequence cs) {
214            if (cs == null) {
215                return false;
216            }
217            return this == cs || (cs.length() == length && regionMatches(0, cs, length));
218        }
219
220        public boolean startsWith(CharSequence cs) {
221            int csLength = cs.length();
222            return csLength <= length && regionMatches(0, cs, csLength);
223        }
224
225        public boolean endsWith(CharSequence cs) {
226            int csLength = cs.length();
227            return csLength <= length && regionMatches(length - csLength, cs, csLength);
228        }
229
230        /**
231         * @return true if the substring of this key starting from the offset
232         *         contains the same characters as the other sequence.
233         */
234        public boolean regionMatches(int start, CharSequence cs) {
235            int csLength = cs.length();
236            return csLength == (length - start) && regionMatches(start, cs, csLength);
237        }
238
239        @Override
240        public int hashCode() {
241            // Never return s.hashCode(), so that
242            // Key.hashCode() is the same whether we have cached s or not.
243            if (length == 0) {
244                return 0;
245            }
246
247            int h = bytes[offset];
248            for (int i = 1; i < length; ++i) {
249                h = 37 * h + bytes[offset];
250            }
251            return h;
252        }
253
254        @Override
255        public int compareTo(Key other) {
256            return compareTo((CharSequence)other);
257        }
258
259        public int compareTo(CharSequence cs) {
260            int csLength = cs.length();
261            int minLength = length <= csLength ? length : csLength;
262            for (int i = 0; i < minLength; ++i) {
263                int diff = charAt(i) - cs.charAt(i);
264                if (diff != 0) {
265                    return diff;
266                }
267            }
268            return length - csLength;
269        }
270    }
271
272    /**
273     * Interface for iterating over a resource bundle array resource.
274     * Does not use Java Iterator to reduce object creations.
275     */
276    public interface Array {
277        /**
278         * @return The number of items in the array resource.
279         */
280        public int getSize();
281        /**
282         * @param i Array item index.
283         * @param value Output-only, receives the value of the i'th item.
284         * @return true if i is non-negative and less than getSize().
285         */
286        public boolean getValue(int i, Value value);
287    }
288
289    /**
290     * Interface for iterating over a resource bundle table resource.
291     * Does not use Java Iterator to reduce object creations.
292     */
293    public interface Table {
294        /**
295         * @return The number of items in the array resource.
296         */
297        public int getSize();
298        /**
299         * @param i Array item index.
300         * @param key Output-only, receives the key of the i'th item.
301         * @param value Output-only, receives the value of the i'th item.
302         * @return true if i is non-negative and less than getSize().
303         */
304        public boolean getKeyAndValue(int i, Key key, Value value);
305    }
306
307    /**
308     * Represents a resource bundle item's value.
309     * Avoids object creations as much as possible.
310     * Mutable, not thread-safe.
311     */
312    public static abstract class Value {
313        protected Value() {}
314
315        /**
316         * @return ICU resource type like {@link UResourceBundle#getType()},
317         *     for example, {@link UResourceBundle#STRING}
318         */
319        public abstract int getType();
320
321        /**
322         * @see UResourceBundle#getString()
323         * @throws UResourceTypeMismatchException if this is not a string resource
324         */
325        public abstract String getString();
326
327        /**
328         * @throws UResourceTypeMismatchException if this is not an alias resource
329         */
330        public abstract String getAliasString();
331
332        /**
333         * @see UResourceBundle#getInt()
334         * @throws UResourceTypeMismatchException if this is not an integer resource
335         */
336        public abstract int getInt();
337
338        /**
339         * @see UResourceBundle#getUInt()
340         * @throws UResourceTypeMismatchException if this is not an integer resource
341         */
342        public abstract int getUInt();
343
344        /**
345         * @see UResourceBundle#getIntVector()
346         * @throws UResourceTypeMismatchException if this is not an intvector resource
347         */
348        public abstract int[] getIntVector();
349
350        /**
351         * @see UResourceBundle#getBinary()
352         * @throws UResourceTypeMismatchException if this is not a binary-blob resource
353         */
354        public abstract ByteBuffer getBinary();
355
356        /**
357         * @throws UResourceTypeMismatchException if this is not an array resource
358         */
359        public abstract Array getArray();
360
361        /**
362         * @throws UResourceTypeMismatchException if this is not a table resource
363         */
364        public abstract Table getTable();
365
366        /**
367         * Is this a no-fallback/no-inheritance marker string?
368         * Such a marker is used for CLDR no-fallback data values of "∅∅∅"
369         * when enumerating tables with fallback from the specific resource bundle to root.
370         *
371         * @return true if this is a no-inheritance marker string
372         */
373        public abstract boolean isNoInheritanceMarker();
374
375        /**
376         * @return the array of strings in this array resource.
377         * @see UResourceBundle#getStringArray()
378         * @throws UResourceTypeMismatchException if this is not an array resource
379         *     or if any of the array items is not a string
380         */
381        public abstract String[] getStringArray();
382
383        /**
384         * Same as
385         * <pre>
386         * if (getType() == STRING) {
387         *     return new String[] { getString(); }
388         * } else {
389         *     return getStringArray();
390         * }
391         * </pre>
392         *
393         * @see #getString()
394         * @see #getStringArray()
395         * @throws UResourceTypeMismatchException if this is
396         *     neither a string resource nor an array resource containing strings
397         */
398        public abstract String[] getStringArrayOrStringAsArray();
399
400        /**
401         * Same as
402         * <pre>
403         * if (getType() == STRING) {
404         *     return getString();
405         * } else {
406         *     return getStringArray()[0];
407         * }
408         * </pre>
409         *
410         * @see #getString()
411         * @see #getStringArray()
412         * @throws UResourceTypeMismatchException if this is
413         *     neither a string resource nor an array resource containing strings
414         */
415        public abstract String getStringOrFirstOfArray();
416
417        /**
418         * Only for debugging.
419         */
420        @Override
421        public String toString() {
422            switch(getType()) {
423            case UResourceBundle.STRING:
424                return getString();
425            case UResourceBundle.INT:
426                return Integer.toString(getInt());
427            case UResourceBundle.INT_VECTOR:
428                int[] iv = getIntVector();
429                StringBuilder sb = new StringBuilder("[");
430                sb.append(iv.length).append("]{");
431                if (iv.length != 0) {
432                    sb.append(iv[0]);
433                    for (int i = 1; i < iv.length; ++i) {
434                        sb.append(", ").append(iv[i]);
435                    }
436                }
437                return sb.append('}').toString();
438            case UResourceBundle.BINARY:
439                return "(binary blob)";
440            case UResourceBundle.ARRAY:
441                return "(array)";
442            case UResourceBundle.TABLE:
443                return "(table)";
444            default:  // should not occur
445                return "???";
446            }
447        }
448    }
449
450    /**
451     * Sink for ICU resource bundle contents.
452     */
453    public static abstract class Sink {
454        /**
455         * Called once for each bundle (child-parent-...-root).
456         * The value is normally an array or table resource,
457         * and implementations of this method normally iterate over the
458         * tree of resource items stored there.
459         *
460         * @param key Initially the key string of the enumeration-start resource.
461         *     Empty if the enumeration starts at the top level of the bundle.
462         *     Reuse for output values from Array and Table getters.
463         * @param value Call getArray() or getTable() as appropriate.
464         *     Then reuse for output values from Array and Table getters.
465         * @param noFallback true if the bundle has no parent;
466         *     that is, its top-level table has the nofallback attribute,
467         *     or it is the root bundle of a locale tree.
468         */
469        public abstract void put(Key key, Value value, boolean noFallback);
470    }
471}
472