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