@@ -7,14 +7,18 @@ namespace ApplicationUtility;
7
7
public class AndroidManifest : IAspect
8
8
{
9
9
public string Description { get ; }
10
+ public string ? PackageName { get ; }
10
11
11
- AXMLParser ? binaryParser ;
12
12
XmlDocument ? xmlDoc ;
13
+ XmlNamespaceManager ? nsmgr ;
13
14
14
15
AndroidManifest ( AXMLParser binaryParser , string ? description )
15
16
{
16
17
Description = String . IsNullOrEmpty ( description ) ? "Android manifest" : description ;
17
- this . binaryParser = binaryParser ;
18
+ Read ( binaryParser ) ;
19
+
20
+ nsmgr = PrepareForReading ( xmlDoc ) ;
21
+ PackageName = TryGetPackageName ( xmlDoc , nsmgr ) ;
18
22
}
19
23
20
24
public static IAspect LoadAspect ( Stream stream , IAspectState state , string ? description )
@@ -30,7 +34,6 @@ public static IAspect LoadAspect (Stream stream, IAspectState state, string? des
30
34
} else {
31
35
throw new NotImplementedException ( ) ;
32
36
}
33
- ret . Read ( ) ;
34
37
35
38
return ret ;
36
39
}
@@ -62,7 +65,7 @@ public static IAspectState ProbeAspect (Stream stream, string? description)
62
65
return new BasicAspectState ( success : false ) ;
63
66
}
64
67
65
- void Read ( )
68
+ void Read ( AXMLParser ? binaryParser )
66
69
{
67
70
if ( binaryParser == null ) {
68
71
throw new NotImplementedException ( ) ;
@@ -76,6 +79,131 @@ void Read ()
76
79
Log . Debug ( $ "'{ Description } ' loaded and parsed correctly.") ;
77
80
}
78
81
82
+ static XmlNamespaceManager ? PrepareForReading ( XmlDocument ? doc )
83
+ {
84
+ if ( doc == null ) {
85
+ return null ;
86
+ }
87
+
88
+ var nsmgr = new XmlNamespaceManager ( doc . NameTable ) ;
89
+ nsmgr . AddNamespace ( "android" , "http://schemas.android.com/apk/res/android" ) ;
90
+ return nsmgr ;
91
+ }
92
+
93
+ static bool ValidXmlContext ( XmlDocument ? doc , XmlNamespaceManager ? nsmgr , out XmlElement ? root )
94
+ {
95
+ root = null ;
96
+ if ( doc == null || nsmgr == null ) {
97
+ return false ;
98
+ }
99
+
100
+ root = doc . DocumentElement ;
101
+ return root != null ;
102
+ }
103
+
104
+ static string ? TryGetMainActivity ( XmlDocument ? doc , XmlNamespaceManager ? nsmgr )
105
+ {
106
+ if ( ! ValidXmlContext ( doc , nsmgr , out XmlElement ? root ) ) {
107
+ return null ;
108
+ }
109
+
110
+ XmlNodeList ? activities = root ! . SelectNodes ( "//manifest/application/activity" , nsmgr ! ) ;
111
+ if ( activities == null || activities . Count == 0 ) {
112
+ return null ;
113
+ }
114
+
115
+ foreach ( XmlNode activity in activities ) {
116
+ string ? name = GetLauncherActivityName ( activity ) ;
117
+ if ( name == null ) {
118
+ continue ;
119
+ }
120
+
121
+ return name ;
122
+ }
123
+
124
+ return null ;
125
+
126
+ string ? GetLauncherActivityName ( XmlNode activity )
127
+ {
128
+ XmlNodeList ? intentFilters = activity . SelectNodes ( "./intent-filter" , nsmgr ! ) ;
129
+ if ( intentFilters == null || intentFilters . Count == 0 ) {
130
+ return null ;
131
+ }
132
+
133
+ bool isMain = false ;
134
+ foreach ( XmlNode intentFilter in intentFilters ) {
135
+ XmlNodeList ? actions = activity . SelectNodes ( "./action" , nsmgr ! ) ;
136
+ if ( actions == null || actions . Count == 0 ) {
137
+ continue ;
138
+ }
139
+
140
+ if ( ! HaveNodeWithNameAttribute ( actions , "android.intent.action.MAIN" ) ) {
141
+ continue ;
142
+ }
143
+
144
+ XmlNodeList ? categories = activity . SelectNodes ( "./category" , nsmgr ! ) ;
145
+ if ( categories == null || categories . Count == 0 ) {
146
+ continue ;
147
+ }
148
+
149
+ if ( ! HaveNodeWithNameAttribute ( categories , "android.intent.category.LAUNCHER" ) ) {
150
+ continue ;
151
+ }
152
+
153
+ isMain = true ;
154
+ break ;
155
+ }
156
+
157
+ if ( ! isMain ) {
158
+ return null ;
159
+ }
160
+
161
+ var attr = activity . Attributes ? . GetNamedItem ( "android:name" ) ;
162
+ if ( attr == null ) {
163
+ return null ;
164
+ }
165
+
166
+ return attr . Value ;
167
+ }
168
+
169
+ bool HaveNodeWithNameAttribute ( XmlNodeList list , string nameValue )
170
+ {
171
+ foreach ( XmlNode ? node in list ) {
172
+ var attr = node ? . Attributes ? . GetNamedItem ( "android:name" ) ;
173
+ if ( attr == null || String . IsNullOrEmpty ( attr . Value ) ) {
174
+ continue ;
175
+ }
176
+
177
+ if ( attr . Value == nameValue ) {
178
+ return true ;
179
+ }
180
+ }
181
+
182
+ return false ;
183
+ }
184
+ }
185
+
186
+ static string ? TryGetPackageName ( XmlDocument ? doc , XmlNamespaceManager ? nsmgr )
187
+ {
188
+ Log . Debug ( "Trying to read package name" ) ;
189
+ if ( ! ValidXmlContext ( doc , nsmgr , out XmlElement ? root ) || root == null ) {
190
+ return null ;
191
+ }
192
+
193
+ XmlNode ? manifest = root . SelectSingleNode ( "//manifest" , nsmgr ) ;
194
+ if ( manifest == null || manifest . Attributes == null ) {
195
+ Log . Debug ( "`manifest` element not found or it has no attributes" ) ;
196
+ return null ;
197
+ }
198
+
199
+ XmlNode ? package = manifest . Attributes . GetNamedItem ( "package" ) ;
200
+ if ( package == null ) {
201
+ Log . Debug ( "`package` attribute in the `manifest` element not found" ) ;
202
+ }
203
+
204
+ return package == null ? null : package . Value ;
205
+ }
206
+
79
207
static XmlDocument ParsePlainXML ( Stream stream )
80
208
{
81
209
stream . Seek ( 0 , SeekOrigin . Begin ) ;
0 commit comments