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 /** Parse content from [InputStream] with [BinaryXmlPullParser]. */
26 @Throws(IOException::class, XmlPullParserException::class)
parseBinaryXmlnull27 inline fun InputStream.parseBinaryXml(block: BinaryXmlPullParser.() -> Unit) {
28 BinaryXmlPullParser().apply {
29 setInput(this@parseBinaryXml, null)
30 block()
31 }
32 }
33
34 /**
35 * Iterate through child tags of the current tag.
36 *
37 * <p>
38 * Attributes for the current tag needs to be accessed before this method is called because this
39 * method will advance the parser past the start tag of the current tag. The code inspecting each
40 * child tag may access the attributes of the child tag, and/or call [forEachTag] recursively to
41 * inspect grandchild tags, which will naturally leave the parser at either the start tag or the end
42 * tag of the child tag it inspected.
43 *
44 * @see BinaryXmlPullParser.next
45 * @see BinaryXmlPullParser.getEventType
46 * @see BinaryXmlPullParser.getDepth
47 */
48 @Throws(IOException::class, XmlPullParserException::class)
forEachTagnull49 inline fun BinaryXmlPullParser.forEachTag(block: BinaryXmlPullParser.() -> Unit) {
50 when (val eventType = eventType) {
51 // Document start or start tag of the parent tag.
52 XmlPullParser.START_DOCUMENT,
53 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,
94 XmlPullParser.END_DOCUMENT -> break
95 else -> throw XmlPullParserException("Unexpected event type $eventType")
96 }
97 }
98 }
99
100 /**
101 * Advance the parser until the current event is one of [XmlPullParser.START_TAG],
102 * [XmlPullParser.START_TAG] and [XmlPullParser.START_TAG]
103 *
104 * @see BinaryXmlPullParser.next
105 */
106 @Throws(IOException::class, XmlPullParserException::class)
107 @Suppress("NOTHING_TO_INLINE")
nextTagOrEndnull108 inline fun BinaryXmlPullParser.nextTagOrEnd(): Int {
109 while (true) {
110 when (val eventType = next()) {
111 XmlPullParser.START_TAG,
112 XmlPullParser.END_TAG,
113 XmlPullParser.END_DOCUMENT -> return eventType
114 else -> continue
115 }
116 }
117 }
118
119 /** @see BinaryXmlPullParser.getName */
120 inline val BinaryXmlPullParser.tagName: String
121 get() = name
122
123 /** Check whether an attribute exists for the current tag. */
124 @Suppress("NOTHING_TO_INLINE")
hasAttributenull125 inline fun BinaryXmlPullParser.hasAttribute(name: String): Boolean = getAttributeIndex(name) != -1
126
127 /** @see BinaryXmlPullParser.getAttributeIndex */
128 @Suppress("NOTHING_TO_INLINE")
129 inline fun BinaryXmlPullParser.getAttributeIndex(name: String): Int = getAttributeIndex(null, name)
130
131 /** @see BinaryXmlPullParser.getAttributeIndexOrThrow */
132 @Suppress("NOTHING_TO_INLINE")
133 @Throws(XmlPullParserException::class)
134 inline fun BinaryXmlPullParser.getAttributeIndexOrThrow(name: String): Int =
135 getAttributeIndexOrThrow(null, name)
136
137 /** @see BinaryXmlPullParser.getAttributeValue */
138 @Suppress("NOTHING_TO_INLINE")
139 @Throws(XmlPullParserException::class)
140 inline fun BinaryXmlPullParser.getAttributeValue(name: String): String? =
141 getAttributeValue(null, name)
142
143 /** @see BinaryXmlPullParser.getAttributeValue */
144 @Suppress("NOTHING_TO_INLINE")
145 @Throws(XmlPullParserException::class)
146 inline fun BinaryXmlPullParser.getAttributeValueOrThrow(name: String): String =
147 getAttributeValue(getAttributeIndexOrThrow(name))
148
149 /** @see BinaryXmlPullParser.getAttributeBytesHex */
150 @Suppress("NOTHING_TO_INLINE")
151 inline fun BinaryXmlPullParser.getAttributeBytesHex(name: String): ByteArray? =
152 getAttributeBytesHex(null, name, null)
153
154 /** @see BinaryXmlPullParser.getAttributeBytesHex */
155 @Suppress("NOTHING_TO_INLINE")
156 @Throws(XmlPullParserException::class)
157 inline fun BinaryXmlPullParser.getAttributeBytesHexOrThrow(name: String): ByteArray =
158 getAttributeBytesHex(null, name)
159
160 /** @see BinaryXmlPullParser.getAttributeBytesBase64 */
161 @Suppress("NOTHING_TO_INLINE")
162 inline fun BinaryXmlPullParser.getAttributeBytesBase64(name: String): ByteArray? =
163 getAttributeBytesBase64(null, name, null)
164
165 /** @see BinaryXmlPullParser.getAttributeBytesBase64 */
166 @Suppress("NOTHING_TO_INLINE")
167 @Throws(XmlPullParserException::class)
168 inline fun BinaryXmlPullParser.getAttributeBytesBase64OrThrow(name: String): ByteArray =
169 getAttributeBytesBase64(null, name)
170
171 /** @see BinaryXmlPullParser.getAttributeInt */
172 @Suppress("NOTHING_TO_INLINE")
173 inline fun BinaryXmlPullParser.getAttributeIntOrDefault(name: String, defaultValue: Int): Int =
174 getAttributeInt(null, name, defaultValue)
175
176 /** @see BinaryXmlPullParser.getAttributeInt */
177 @Suppress("NOTHING_TO_INLINE")
178 @Throws(XmlPullParserException::class)
179 inline fun BinaryXmlPullParser.getAttributeIntOrThrow(name: String): Int =
180 getAttributeInt(null, name)
181
182 /** @see BinaryXmlPullParser.getAttributeIntHex */
183 @Suppress("NOTHING_TO_INLINE")
184 inline fun BinaryXmlPullParser.getAttributeIntHexOrDefault(name: String, defaultValue: Int): Int =
185 getAttributeIntHex(null, name, defaultValue)
186
187 /** @see BinaryXmlPullParser.getAttributeIntHex */
188 @Suppress("NOTHING_TO_INLINE")
189 @Throws(XmlPullParserException::class)
190 inline fun BinaryXmlPullParser.getAttributeIntHexOrThrow(name: String): Int =
191 getAttributeIntHex(null, name)
192
193 /** @see BinaryXmlPullParser.getAttributeLong */
194 @Suppress("NOTHING_TO_INLINE")
195 inline fun BinaryXmlPullParser.getAttributeLongOrDefault(name: String, defaultValue: Long): Long =
196 getAttributeLong(null, name, defaultValue)
197
198 /** @see BinaryXmlPullParser.getAttributeLong */
199 @Suppress("NOTHING_TO_INLINE")
200 @Throws(XmlPullParserException::class)
201 inline fun BinaryXmlPullParser.getAttributeLongOrThrow(name: String): Long =
202 getAttributeLong(null, name)
203
204 /** @see BinaryXmlPullParser.getAttributeLongHex */
205 @Suppress("NOTHING_TO_INLINE")
206 inline fun BinaryXmlPullParser.getAttributeLongHexOrDefault(
207 name: String,
208 defaultValue: Long
209 ): Long = getAttributeLongHex(null, name, defaultValue)
210
211 /** @see BinaryXmlPullParser.getAttributeLongHex */
212 @Suppress("NOTHING_TO_INLINE")
213 @Throws(XmlPullParserException::class)
214 inline fun BinaryXmlPullParser.getAttributeLongHexOrThrow(name: String): Long =
215 getAttributeLongHex(null, name)
216
217 /** @see BinaryXmlPullParser.getAttributeFloat */
218 @Suppress("NOTHING_TO_INLINE")
219 inline fun BinaryXmlPullParser.getAttributeFloatOrDefault(
220 name: String,
221 defaultValue: Float
222 ): Float = getAttributeFloat(null, name, defaultValue)
223
224 /** @see BinaryXmlPullParser.getAttributeFloat */
225 @Suppress("NOTHING_TO_INLINE")
226 @Throws(XmlPullParserException::class)
227 inline fun BinaryXmlPullParser.getAttributeFloatOrThrow(name: String): Float =
228 getAttributeFloat(null, name)
229
230 /** @see BinaryXmlPullParser.getAttributeDouble */
231 @Suppress("NOTHING_TO_INLINE")
232 inline fun BinaryXmlPullParser.getAttributeDoubleOrDefault(
233 name: String,
234 defaultValue: Double
235 ): Double = getAttributeDouble(null, name, defaultValue)
236
237 /** @see BinaryXmlPullParser.getAttributeDouble */
238 @Suppress("NOTHING_TO_INLINE")
239 @Throws(XmlPullParserException::class)
240 inline fun BinaryXmlPullParser.getAttributeDoubleOrThrow(name: String): Double =
241 getAttributeDouble(null, name)
242
243 /** @see BinaryXmlPullParser.getAttributeBoolean */
244 @Suppress("NOTHING_TO_INLINE")
245 inline fun BinaryXmlPullParser.getAttributeBooleanOrDefault(
246 name: String,
247 defaultValue: Boolean
248 ): Boolean = getAttributeBoolean(null, name, defaultValue)
249
250 /** @see BinaryXmlPullParser.getAttributeBoolean */
251 @Suppress("NOTHING_TO_INLINE")
252 @Throws(XmlPullParserException::class)
253 inline fun BinaryXmlPullParser.getAttributeBooleanOrThrow(name: String): Boolean =
254 getAttributeBoolean(null, name)
255