1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.media.testmediaapp.loader;
18 
19 import android.content.Context;
20 import android.util.Log;
21 
22 import androidx.annotation.Nullable;
23 
24 import org.json.JSONArray;
25 import org.json.JSONException;
26 import org.json.JSONObject;
27 
28 import java.io.ByteArrayOutputStream;
29 import java.io.Closeable;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.OutputStream;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 
38 class TmaLoaderUtils {
39 
40     private static final String TAG = "TmaLoaderUtils";
41 
42     /** The default buffer size to use to read files. */
43     private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
44     private static final String[] NO_STRINGS = {};
45 
TmaLoaderUtils()46     private TmaLoaderUtils() {
47     }
48 
49     @Nullable
jsonFromAsset(Context context, String assetPathName)50     static JSONObject jsonFromAsset(Context context, String assetPathName) {
51         String jsonString = stringFromAsset(context, assetPathName);
52         try {
53             return (jsonString != null) ? new JSONObject(jsonString) : null;
54         } catch (JSONException e) {
55             Log.e(TAG, "Failed to convert to json object: " + e);
56             return null;
57         }
58     }
59 
60     /** Returns a map from the enum value names to the enum values. */
enumNamesToValues(T[] values)61     static <T extends Enum> Map<String, T> enumNamesToValues(T[] values) {
62         Map<String, T> result = new HashMap<>();
63         for (T val : values) {
64             result.put(val.name(), val);
65         }
66         return result;
67     }
68 
69     /** Returns the enum value mapped to the name of the given key, or fallback if missing. */
70     @Nullable
getEnum( JSONObject json, K key, Map<String, E> enumMap, E fallback)71     static <K extends Enum, E extends Enum> E getEnum(
72             JSONObject json, K key, Map<String, E> enumMap, E fallback) {
73         E result = enumMap.get(getString(json, key));
74         return (result != null) ? result : fallback;
75     }
76 
77     /** Returns the array mapped to the name of the given key, or null if missing. */
78     @Nullable
getArray(JSONObject json, T key)79     static <T extends Enum> JSONArray getArray(JSONObject json, T key) {
80         try {
81             return json.has(key.name()) ? json.getJSONArray(key.name()) : null;
82         } catch (JSONException e) {
83             Log.e(TAG, "JSONException getting array for: " + key + " e: " + e);
84             return null;
85         }
86     }
87 
88     /** Returns the array mapped to the name of the given key, or empty if missing. */
getEnumArray(JSONObject json, T key, Map<String, U> enumMap)89     static <T extends Enum, U extends Enum> List<U> getEnumArray(JSONObject json, T key,
90             Map<String, U> enumMap) {
91         try {
92             JSONArray array = json.has(key.name()) ? json.getJSONArray(key.name()) : null;
93             int count = (array != null) ? array.length() : 0;
94             List<U> result = new ArrayList<>(count);
95             for (int i = 0; i < count; i++) {
96                 result.add(enumMap.get(array.getString(i)));
97             }
98             return result;
99         } catch (JSONException e) {
100             Log.e(TAG, "JSONException getting array for: " + key + " e: " + e);
101             return new ArrayList<>();
102         }
103     }
104 
105     /** Returns the string mapped to the name of the given key, or null if missing. */
106     @Nullable
getString(JSONObject json, T key)107     static <T extends Enum> String getString(JSONObject json, T key) {
108         try {
109             return json.has(key.name()) ? json.getString(key.name()) : null;
110         } catch (JSONException e) {
111             Log.e(TAG, "JSONException getting string for: " + key + " e: " + e);
112             return null;
113         }
114     }
115 
116     /** Returns the integer mapped to the name of the given key, or 0 if missing. */
getInt(JSONObject json, T key)117     static <T extends Enum> int getInt(JSONObject json, T key) {
118         try {
119             return json.has(key.name()) ? json.getInt(key.name()) : 0;
120         } catch (JSONException e) {
121             Log.e(TAG, "JSONException getting int for: " + key + " e: " + e);
122             return 0;
123         }
124     }
125 
126     /** Takes a | separated list of flags and turns it into a bitfield value. */
parseFlags(@ullable String jsonFlags, Map<String, Integer> flagsMap)127     static int parseFlags(@Nullable String jsonFlags, Map<String, Integer> flagsMap) {
128         int result = 0;
129         String[] flags = (jsonFlags != null) ? jsonFlags.split("\\|") : NO_STRINGS;
130         for (String flag : flags) {
131             Integer value = flagsMap.get(flag);
132             if (value != null) {
133                 result |= value;
134             } else {
135                 Log.e(TAG, "Unknown flag: " + flag);
136             }
137         }
138         return result;
139     }
140 
copy(InputStream input, OutputStream output)141     private static void copy(InputStream input, OutputStream output) throws IOException {
142         byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
143         int n;
144         while (-1 != (n = input.read(buffer))) {
145             output.write(buffer, 0, n);
146         }
147     }
148 
toByteArray(InputStream input)149     private static byte[] toByteArray(InputStream input) throws IOException {
150         ByteArrayOutputStream output = new ByteArrayOutputStream();
151         copy(input, output);
152         return output.toByteArray();
153     }
154 
155     @Nullable
stringFromAsset(Context context, String assetPathName)156     private static String stringFromAsset(Context context, String assetPathName) {
157         InputStream stream = null;
158         try {
159             stream = context.getAssets().open(assetPathName);
160             if (stream == null) {
161                 return null;
162             }
163             return new String(toByteArray(stream));
164         } catch (IOException e) {
165             Log.e(TAG, "failed to load string from asset: " + e);
166             return null;
167         } finally {
168             close(stream);
169         }
170     }
171 
close(@ullable Closeable closeable)172     private static void close(@Nullable Closeable closeable) {
173         if (closeable == null) {
174             return;
175         }
176         try {
177             closeable.close();
178         } catch (IOException e) {
179             Log.e(TAG, "Error in close(): " + e);
180         }
181     }
182 }
183