@@ -7,14 +7,18 @@ namespace ApplicationUtility;
77public class AndroidManifest : IAspect
88{
99 public string Description { get ; }
10+ public string ? PackageName { get ; }
1011
11- AXMLParser ? binaryParser ;
1212 XmlDocument ? xmlDoc ;
13+ XmlNamespaceManager ? nsmgr ;
1314
1415 AndroidManifest ( AXMLParser binaryParser , string ? description )
1516 {
1617 Description = String . IsNullOrEmpty ( description ) ? "Android manifest" : description ;
17- this . binaryParser = binaryParser ;
18+ Read ( binaryParser ) ;
19+
20+ nsmgr = PrepareForReading ( xmlDoc ) ;
21+ PackageName = TryGetPackageName ( xmlDoc , nsmgr ) ;
1822 }
1923
2024 public static IAspect LoadAspect ( Stream stream , IAspectState state , string ? description )
@@ -30,7 +34,6 @@ public static IAspect LoadAspect (Stream stream, IAspectState state, string? des
3034 } else {
3135 throw new NotImplementedException ( ) ;
3236 }
33- ret . Read ( ) ;
3437
3538 return ret ;
3639 }
@@ -62,7 +65,7 @@ public static IAspectState ProbeAspect (Stream stream, string? description)
6265 return new BasicAspectState ( success : false ) ;
6366 }
6467
65- void Read ( )
68+ void Read ( AXMLParser ? binaryParser )
6669 {
6770 if ( binaryParser == null ) {
6871 throw new NotImplementedException ( ) ;
@@ -76,6 +79,131 @@ void Read ()
7679 Log . Debug ( $ "'{ Description } ' loaded and parsed correctly.") ;
7780 }
7881
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+
79207 static XmlDocument ParsePlainXML ( Stream stream )
80208 {
81209 stream . Seek ( 0 , SeekOrigin . Begin ) ;
0 commit comments