1 /*
2 * Copyright (C) 2022 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.server.permission.access.util
18
19 import com.android.modules.utils.BinaryXmlPullParser
20 import java.io.IOException
21 import java.io.InputStream
22 import org.xmlpull.v1.XmlPullParser
23 import org.xmlpull.v1.XmlPullParserException
24
25 /**
26 * Parse content from [InputStream] with [BinaryXmlPullParser].
27 */
28 @Throws(IOException::class, XmlPullParserException::class)
parseBinaryXmlnull29 inline fun InputStream.parseBinaryXml(block: BinaryXmlPullParser.() -> Unit) {
30 BinaryXmlPullParser().apply {
31 setInput(this@parseBinaryXml, null)
32 block()
33 }
34 }
35
36 /**
37 * Iterate through child tags of the current tag.
38 * <p>
39 * Attributes for the current tag needs to be accessed before this method is called because this
40 * method will advance the parser past the start tag of the current tag. The code inspecting each
41 * child tag may access the attributes of the child tag, and/or call [forEachTag] recursively to
42 * inspect grandchild tags, which will naturally leave the parser at either the start tag or the end
43 * tag of the child tag it inspected.
44 *
45 * @see BinaryXmlPullParser.next
46 * @see BinaryXmlPullParser.getEventType
47 * @see BinaryXmlPullParser.getDepth
48 */
49 @Throws(IOException::class, XmlPullParserException::class)
forEachTagnull50 inline fun BinaryXmlPullParser.forEachTag(block: BinaryXmlPullParser.() -> Unit) {
51 when (val eventType = eventType) {
52 // Document start or start tag of the parent tag.
53 XmlPullParser.START_DOCUMENT, XmlPullParser.START_TAG -> nextTagOrEnd()
54 else -> throw XmlPullParserException("Unexpected event type $eventType")
55 }
56 while (true) {
57 when (val eventType = eventType) {
58 // Start tag of a child tag.
59 XmlPullParser.START_TAG -> {
60 val childDepth = depth
61 block()
62 // block() should leave the parser at either the start tag (no grandchild tags
63 // expected) or the end tag (grandchild tags parsed with forEachTag()) of this child
64 // tag.
65 val postBlockDepth = depth
66 if (postBlockDepth != childDepth) {
67 throw XmlPullParserException(
68 "Unexpected post-block depth $postBlockDepth, expected $childDepth"
69 )
70 }
71 // Skip the parser to the end tag of this child tag.
72 while (true) {
73 when (val childEventType = this.eventType) {
74 // Start tag of either this child tag or a grandchild tag.
75 XmlPullParser.START_TAG -> nextTagOrEnd()
76 XmlPullParser.END_TAG -> {
77 if (depth > childDepth) {
78 // End tag of a grandchild tag.
79 nextTagOrEnd()
80 } else {
81 // End tag of this child tag.
82 break
83 }
84 }
85 else ->
86 throw XmlPullParserException("Unexpected event type $childEventType")
87 }
88 }
89 // Skip the end tag of this child tag.
90 nextTagOrEnd()
91 }
92 // End tag of the parent tag, or document end.
93 XmlPullParser.END_TAG, XmlPullParser.END_DOCUMENT -> break
94 else -> throw XmlPullParserException("Unexpected event type $eventType")
95 }
96 }
97 }
98
99 /**
100 * Advance the parser until the current event is one of [XmlPullParser.START_TAG],
101 * [XmlPullParser.START_TAG] and [XmlPullParser.START_TAG]
102 *
103 * @see BinaryXmlPullParser.next
104 */
105 @Throws(IOException::class, XmlPullParserException::class)
106 @Suppress("NOTHING_TO_INLINE")
nextTagOrEndnull107 inline fun BinaryXmlPullParser.nextTagOrEnd(): Int {
108 while (true) {
109 when (val eventType = next()) {
110 XmlPullParser.START_TAG, XmlPullParser.END_TAG, XmlPullParser.END_DOCUMENT ->
111 return eventType
112 else -> continue
113 }
114 }
115 }
116
117 /**
118 * @see BinaryXmlPullParser.getName
119 */
120 inline val BinaryXmlPullParser.tagName: String
121 get() = name
122
123 /**
124 * Check whether an attribute exists for the current tag.
125 */
126 @Suppress("NOTHING_TO_INLINE")
hasAttributenull127 inline fun BinaryXmlPullParser.hasAttribute(name: String): Boolean = getAttributeIndex(name) != -1
128
129 /**
130 * @see BinaryXmlPullParser.getAttributeIndex
131 */
132 @Suppress("NOTHING_TO_INLINE")
133 inline fun BinaryXmlPullParser.getAttributeIndex(name: String): Int = getAttributeIndex(null, name)
134
135 /**
136 * @see BinaryXmlPullParser.getAttributeIndexOrThrow
137 */
138 @Suppress("NOTHING_TO_INLINE")
139 @Throws(XmlPullParserException::class)
140 inline fun BinaryXmlPullParser.getAttributeIndexOrThrow(name: String): Int =
141 getAttributeIndexOrThrow(null, name)
142
143 /**
144 * @see BinaryXmlPullParser.getAttributeValue
145 */
146 @Suppress("NOTHING_TO_INLINE")
147 @Throws(XmlPullParserException::class)
148 inline fun BinaryXmlPullParser.getAttributeValue(name: String): String? =
149 getAttributeValue(null, name)
150
151 /**
152 * @see BinaryXmlPullParser.getAttributeValue
153 */
154 @Suppress("NOTHING_TO_INLINE")
155 @Throws(XmlPullParserException::class)
156 inline fun BinaryXmlPullParser.getAttributeValueOrThrow(name: String): String =
157 getAttributeValue(getAttributeIndexOrThrow(name))
158
159 /**
160 * @see BinaryXmlPullParser.getAttributeBytesHex
161 */
162 @Suppress("NOTHING_TO_INLINE")
163 inline fun BinaryXmlPullParser.getAttributeBytesHex(name: String): ByteArray? =
164 getAttributeBytesHex(null, name, null)
165
166 /**
167 * @see BinaryXmlPullParser.getAttributeBytesHex
168 */
169 @Suppress("NOTHING_TO_INLINE")
170 @Throws(XmlPullParserException::class)
171 inline fun BinaryXmlPullParser.getAttributeBytesHexOrThrow(name: String): ByteArray =
172 getAttributeBytesHex(null, name)
173
174 /**
175 * @see BinaryXmlPullParser.getAttributeBytesBase64
176 */
177 @Suppress("NOTHING_TO_INLINE")
178 inline fun BinaryXmlPullParser.getAttributeBytesBase64(name: String): ByteArray? =
179 getAttributeBytesBase64(null, name, null)
180
181 /**
182 * @see BinaryXmlPullParser.getAttributeBytesBase64
183 */
184 @Suppress("NOTHING_TO_INLINE")
185 @Throws(XmlPullParserException::class)
186 inline fun BinaryXmlPullParser.getAttributeBytesBase64OrThrow(name: String): ByteArray =
187 getAttributeBytesBase64(null, name)
188
189 /**
190 * @see BinaryXmlPullParser.getAttributeInt
191 */
192 @Suppress("NOTHING_TO_INLINE")
193 inline fun BinaryXmlPullParser.getAttributeIntOrDefault(name: String, defaultValue: Int): Int =
194 getAttributeInt(null, name, defaultValue)
195
196 /**
197 * @see BinaryXmlPullParser.getAttributeInt
198 */
199 @Suppress("NOTHING_TO_INLINE")
200 @Throws(XmlPullParserException::class)
201 inline fun BinaryXmlPullParser.getAttributeIntOrThrow(name: String): Int =
202 getAttributeInt(null, name)
203
204 /**
205 * @see BinaryXmlPullParser.getAttributeIntHex
206 */
207 @Suppress("NOTHING_TO_INLINE")
208 inline fun BinaryXmlPullParser.getAttributeIntHexOrDefault(name: String, defaultValue: Int): Int =
209 getAttributeIntHex(null, name, defaultValue)
210
211 /**
212 * @see BinaryXmlPullParser.getAttributeIntHex
213 */
214 @Suppress("NOTHING_TO_INLINE")
215 @Throws(XmlPullParserException::class)
216 inline fun BinaryXmlPullParser.getAttributeIntHexOrThrow(name: String): Int =
217 getAttributeIntHex(null, name)
218
219 /**
220 * @see BinaryXmlPullParser.getAttributeLong
221 */
222 @Suppress("NOTHING_TO_INLINE")
223 inline fun BinaryXmlPullParser.getAttributeLongOrDefault(name: String, defaultValue: Long): Long =
224 getAttributeLong(null, name, defaultValue)
225
226 /**
227 * @see BinaryXmlPullParser.getAttributeLong
228 */
229 @Suppress("NOTHING_TO_INLINE")
230 @Throws(XmlPullParserException::class)
231 inline fun BinaryXmlPullParser.getAttributeLongOrThrow(name: String): Long =
232 getAttributeLong(null, name)
233
234 /**
235 * @see BinaryXmlPullParser.getAttributeLongHex
236 */
237 @Suppress("NOTHING_TO_INLINE")
238 inline fun BinaryXmlPullParser.getAttributeLongHexOrDefault(
239 name: String,
240 defaultValue: Long
241 ): Long = getAttributeLongHex(null, name, defaultValue)
242
243 /**
244 * @see BinaryXmlPullParser.getAttributeLongHex
245 */
246 @Suppress("NOTHING_TO_INLINE")
247 @Throws(XmlPullParserException::class)
248 inline fun BinaryXmlPullParser.getAttributeLongHexOrThrow(name: String): Long =
249 getAttributeLongHex(null, name)
250
251 /**
252 * @see BinaryXmlPullParser.getAttributeFloat
253 */
254 @Suppress("NOTHING_TO_INLINE")
255 inline fun BinaryXmlPullParser.getAttributeFloatOrDefault(
256 name: String,
257 defaultValue: Float
258 ): Float = getAttributeFloat(null, name, defaultValue)
259
260 /**
261 * @see BinaryXmlPullParser.getAttributeFloat
262 */
263 @Suppress("NOTHING_TO_INLINE")
264 @Throws(XmlPullParserException::class)
265 inline fun BinaryXmlPullParser.getAttributeFloatOrThrow(name: String): Float =
266 getAttributeFloat(null, name)
267
268 /**
269 * @see BinaryXmlPullParser.getAttributeDouble
270 */
271 @Suppress("NOTHING_TO_INLINE")
272 inline fun BinaryXmlPullParser.getAttributeDoubleOrDefault(
273 name: String,
274 defaultValue: Double
275 ): Double = getAttributeDouble(null, name, defaultValue)
276
277 /**
278 * @see BinaryXmlPullParser.getAttributeDouble
279 */
280 @Suppress("NOTHING_TO_INLINE")
281 @Throws(XmlPullParserException::class)
282 inline fun BinaryXmlPullParser.getAttributeDoubleOrThrow(name: String): Double =
283 getAttributeDouble(null, name)
284
285 /**
286 * @see BinaryXmlPullParser.getAttributeBoolean
287 */
288 @Suppress("NOTHING_TO_INLINE")
289 inline fun BinaryXmlPullParser.getAttributeBooleanOrDefault(
290 name: String,
291 defaultValue: Boolean
292 ): Boolean = getAttributeBoolean(null, name, defaultValue)
293
294 /**
295 * @see BinaryXmlPullParser.getAttributeBoolean
296 */
297 @Suppress("NOTHING_TO_INLINE")
298 @Throws(XmlPullParserException::class)
299 inline fun BinaryXmlPullParser.getAttributeBooleanOrThrow(name: String): Boolean =
300 getAttributeBoolean(null, name)
301