
    j                     p   d dl Z d dlZd dlZd dlZddlmZ ddlmZ ddlm	Z	  ej
        ej        d            G d d	          Z G d
 d          Z G d d          Z G d d          Z G d d          Z G d d          Z G d d          Z G d d          Z G d d          Z G d d          Z G d d          Z G d d          Zd e j        d!efd"Zej        ej        ej        ej        ej        ed#Zd e j        d$efd%Zd& Zd' Zd( Zd2d+e d,e d-e!fd.Z"d/e j        d-e!fd0Z#d1 Z$dS )3    N   )!extract_file_based_on_header_info)ZipEntry)escape_xml_entitieszS%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d -> %(funcName)s : %(message)s)levelformatc                   .    e Zd ZdZd Zed             ZdS )ResChunkHeaderz
    Chunk header used throughout the axml.
    This header is essential as it contains information about the header size but also the total size of the chunk
    the header belongs to.
    c                 >    || _         || _        || _        || _        d S N)typeheader_size
total_sizedata)selfheader_typer   r   r   s        X/home/ubuntu/.hermes/hermes-agent/venv/lib/python3.11/site-packages/apkInspector/axml.py__init__zResChunkHeader.__init__   s#    	&$			    c                     |                     d          }t          |          dk     rdS t          j        d|          \  }}} | ||||          S )a)  
        Read the header type (2 bytes), header size (2 bytes), and entry size (4 bytes).

        :param file: the xml file e.g. with open('/path/AndroidManifest.xml', 'rb') as file
        :type file: bytesIO
        :return: Returns an instance of itself
        :rtype: ResChunkHeader
           Nz<HHI)readlenstructunpack)clsfileheader_datar   r   r   s         r   parsezResChunkHeader.parse   sY     iill{a4/5}V[/Q/Q,[*s;ZEEEr   N__name__
__module____qualname____doc__r   classmethodr    r   r   r
   r
      sM            F F [F F Fr   r
   c                   4    e Zd ZdZdefdZed             ZdS )ResStringPoolHeaderzZ
    It reads the string pool header which contains information about the StringPool.
    headerc                 h    || _         || _        || _        || _        || _        || _        || _        d S r   )r)   string_countstyle_countflagsstrings_startstyles_startr   )r   r)   r+   r,   r-   r.   r/   r   s           r   r   zResStringPoolHeader.__init__4   s;    (&
*(			r   c           	          t                               |          }|                    d          }t          j        d|          \  }}}}} | |||||||          S )z
        Read and parse ResStringPoolHeader from the file.

        :param file: the xml file right after the header has been read.
        :type file: bytesIO
        :return: Returns an instance of itself
        :rtype: ResStringPoolHeader
           z<IIIII)r
   r   r   r   r   )	r   r   r)   string_pool_header_datar+   r,   r-   r.   r/   s	            r   r   zResStringPoolHeader.parse>   si      %%d++"&))B--HNV^`wHxHxEk5-s6<e]!8: : 	:r   Nr!   r"   r#   r$   r
   r   r%   r   r&   r   r   r(   r(   /   sT         ~     : : [: : :r   r(   c                       e Zd ZdZdefdZed             Zed             Zed             Z	ed             Z
ed             Zed	             Zed
             Zed             ZdS )StringPoolTypez
    The stringPool class which is a composition of the ResStringPoolHeader
    along with the string offsets and the string data.
    string_pool_headerc                 >    || _         || _        || _        || _        d S r   )
str_headerstring_offsetsstring_listr   )r   r6   r9   stringsstring_pool_datas        r   r   zStringPoolType.__init__U   s$    ,,"$			r   c           	      <   g }t          d|          D ]C}|                    t          j        d|                    d                    d                    D|                                |k    r-t          j        d|                                 d| d           |S )a&  
        Reads the offset available for each string. Requires to know the number of strings available beforehand.

        :param file: the xml file right after the string pool header has been read.
        :type file: bytesIO
        :param num_of_strings: the calculated number of strings available
        :type num_of_strings: int
        :param end_absolute_offset: the absolute value of the offset where the offsets finish.
        :type end_absolute_offset: int
        :return: Returns a list of strings offsets.
        :rtype: list
        r   <I   zCurrent file read:z3 is not as expected to the start of the stringData:))rangeappendr   r   r   tellloggingwarning)r   r   num_of_stringsend_absolute_offsetr9   is         r   read_string_offsetsz"StringPoolType.read_string_offsets[   s     q.)) 	H 	HA!!&-diill"C"CA"FGGGG99;;---O{TYY[[{{ex{{{} } }r   c                     	 |                     |dz             t          j        d|                    d                    d         }|S # t          $ r%}t          j        d| d|            Y d }~d S d }~ww xY w)Nr?   r>   r   zString offset at position z failed to be read: )seekr   r   r   	ExceptionrD   error)r   r   positionstring_offsetes        r   read_string_offsetz!StringPoolType.read_string_offsetr   s    	IIhl###"M$		!==a@M   	 	 	MXxXXUVXXYYY44444	s   AA
 

A9A44A9c                    |st          j        d|                    d                    d         }|dz  dk    r,|                    |dz                                d          }nt          j        d|                    d                    d         }|dz  dz  |z  }||k    rdS |                    |dz                                d          }not          j        d	|                    d
                    d         }|                    d
           |}|                    |                              dd          }|S )a  
        Handling the different encoding possibilities that can be met.

        :param file: the xml file at the offset where the string is to be read
        :type file: bytesIO
        :param is_utf8: boolean to check if a utf8 string is expected
        :type is_utf8: bool
        :param end_stringpool_offset:
        :type end_stringpool_offset: int
        :return: Returns the decoded string
        :rtype: str
        <H   r   i   zutf-16lei      Br   zutf-8replace)errors)r   r   r   decode)	r   r   is_utf8end_stringpool_offsetu16lencontent
u16len_fixreal_lengthu8lens	            r   decode_stringpool_mixed_stringz-StringPoolType.decode_stringpool_mixed_string|   s-     	I]4166q9F!##))FQJ//66zBB $]41>>qA
 &B6*D!6662))K!O44;;JGG ]3		!55a8FIIaLLLEii&&--gi-HHG r   c                     g }|D ]T}||z   dz   }|                     |           |                     ||||d         z             }|                    |           U|S )aI  
        Gets the actual strings based on the offsets retrieved from read_string_offsets().

        :param file: the xml file right after the string pool offsets have been read
        :type file: bytesIO
        :param string_offsets: see -> read_string_offsets()
        :type string_offsets: list
        :param strings_start: the offset at which the string data starts
        :type strings_start: int
        :param is_utf8: boolean to check if a utf8 string is expected
        :type is_utf8: bool
        :return: Returns a list of the string data
        :rtype: list
        r   )rK   rb   rB   )	r   r   r9   r.   r[   r;   offsetabsolute_offsetr^   s	            r   read_stringszStringPoolType.read_strings   sv      $ 	$ 	$F+f4q8OIIo&&&88wXfgiXjHjkkGNN7####r   c                     ||z   dz
  }|                                 j        |k     rdS |                    |           |                     |||          }|S )a  
        Read a string from the string pool when the offset of it is known already.

        :param file: the string pool data parsed as bytes
        :type file: io.bytesIO
        :param string_offset: the offset at which the string is located in the string pool
        :type string_offset: int
        :param strings_start: the offset at which the string data starts
        :type strings_start: int
        :param is_utf8: boolean to check if a utf8 string is expected
        :type is_utf8: bool
        :param end_stringpool_offset: the offset at which the string pool ends
        :type end_stringpool_offset: int
        :return: Returns the string or None
        :rtype: str or None
           N)	getbuffernbytesrK   rb   )r   r   rO   r.   r[   r\   rf   strings           r   read_stringzStringPoolType.read_string   s_    $ (-7"<>>"_444		/"""33D'CXYYr   c                     	 |                      ||          }|dS |                     |||||          S # t          $ r"}t          j        d|            Y d}~dS d}~ww xY w)a  
        Retrieve a single string from the String Pool, given its position. It first gets the correct offset of the
        string and then reads the string.

        :param position: The position of the string to be retrieved
        :type position: int
        :param string_pool_data: the string pool data parsed as bytes
        :type string_pool_data: io.BytesIO
        :param end_stringpool_offset: the offset at which the string pool ends
        :type end_stringpool_offset: int
        :param strings_start: the offset at which the string data starts
        :type strings_start: int
        :param is_utf8: boolean to check if a utf8 string is expected
        :type is_utf8: bool
        :return: Returns the string or None
        :rtype: str or None
        Nz-Exception while retrieving string from pool: )rQ   rm   rL   rD   	exception)r   rN   r<   r\   r.   r[   rO   rP   s           r   get_string_from_poolz#StringPoolType.get_string_from_pool   s    &	223CXNNM$t??#3]MSZ\qrrr 	 	 	QaQQRRR44444	s   5 5 
A!AA!c                 F   t                               |          }t          ||j                  }	 |                                }|                    d          dk    r|                    |           n+|                    |           |                    d           n||fS )a'  
        A 'lite' parser that gets the header and then reads the rest of the chunk as a blob of bytes.

        :param file: the AndroidManifest.xml file
        :type file: bytesIO
        :return: returns the header and the chunk data
        :rtype: tuple(ResStringPoolHeader, bytes)
        TrT      r   )r(   r   read_remainingr)   rC   r   rK   )r   r   ResStringPool_headerr<   cur_poss        r   
parse_litezStringPoolType.parse_lite   s      388>>)$0D0KLL	iikkGyy||{**		'"""IIgIIaLLL	 $%555r   c                 v   t                               |          }|                                }|j        dz
  }|dz  }|dz                                  st          j        d           |                     |||j        dz             }t          |j	        dz            }| 
                    |||j        |          }	 |                                }	|                    d          dk    r|                    |	           nl|                    |	           |                    d	           |                                j        |                                dz   k     rt          d
          |                                }
|                    |           |                    |
|z
            } | ||||          S )a  
        Parse the string pool to acquire the strings used within the axml.

        :param file: the xml file right after the file header is read
        :type file: bytesIO
        :return: Returns an instance of itself
        :rtype: StringPoolType
        ri   r?   zAThe number of strings in the string pool is not a integer number.r      TrT   rr   r   z%Resource Map header was not detected.)r(   r   rC   r.   
is_integerrD   rE   rI   boolr-   rg   r   rK   rj   rk   
ValueError)r   r   r6   string_pool_startsize_of_strings_offsetsrF   r9   r[   r:   ru   string_pool_endr<   s               r   r   zStringPoolType.parse  s    166t<< IIKK"4"BR"G0A5'!+7799 	bO`aaa00~GYGgjkGkll)/6:;;&&t^=O=]_fgg	JiikkGyy||{**		'"""IIgIIaLLL~~&q88 !HIII	J ))++		#$$$99_7H%HIIs	
 
 	
r   N)r!   r"   r#   r$   r(   r   r%   rI   rQ   rb   rg   rm   rp   rv   r   r&   r   r   r5   r5   O   s        
%+> % % % %   [,   [ # # [#J   [4   [0   [6 6 6 [6( $
 $
 [$
 $
 $
r   r5   c                   D    e Zd ZdZd Zed             Zed             ZdS )XmlResourceMapTypezC
    Resource map class, with the header and the resource IDs.
    c                 0    || _         || _        || _        d S r   )r)   residsr   )r   r)   r   resids_datas       r   r   zXmlResourceMapType.__init__4  s    			r   c                 ^    t                               |          }t          ||          }||fS )a"  
        A 'lite' parser that gets the header and then reads the rest of the chunk as a blob of bytes.

        :param file: the AndroidManifest.xml file
        :type file: bytesIO
        :return: returns the header and the chunk data
        :rtype: tuple(ResChunkHeader, bytes)
        )r
   r   rs   )r   r   resource_map_headerresource_map_datas       r   rv   zXmlResourceMapType.parse_lite9  s5     -22488*41DEE"$555r   c                    t                               |          }|j        |j        z
  dz  }|                    |dz            fdt          dt                    d          D             }d |D             } | ||          S )z
        Parse the resource map and get the resource IDs.

        :param file: the xml file right after the string pool is read
        :type file: bytesIO
        :return: Returns an instance of itself
        :rtype: XmlResourceMapType
        r?   c                 *    g | ]}||d z            S r?   r&   ).0rH   r   s     r   
<listcomp>z,XmlResourceMapType.parse.<locals>.<listcomp>T  s&    NNN1+aAg&NNNr   r   c                 D    g | ]}t          j        d |          d         S r>   r   r   r   r   chunks     r   r   z,XmlResourceMapType.parse.<locals>.<listcomp>U  s)    DDDE&-e,,Q/DDDr   )r
   r   r   r   r   rA   r   )r   r   r)   
num_residschunksr   r   s         @r   r   zXmlResourceMapType.parseG  s      %%d++'&*<<B
ii
Q//NNNNa[9I9I10M0MNNNDDVDDDs66;///r   N)r!   r"   r#   r$   r   r%   rv   r   r&   r   r   r   r   /  sc              
 6 6 [6 0 0 [0 0 0r   r   c                   4    e Zd ZdZdefdZed             ZdS )ResXMLHeaderz
    Chunk header used as a header for the elements.
    This header represents the header for the rest of the elements besides the initial header, the string pool and
    the resource map.
    r)   c                 "    || _         || _        d S r   )r)   r   )r   r)   r   s      r   r   zResXMLHeader.__init__a  s     			r   c                     t                               |          }d}|j        dk    r|                    |j        dz
            } | ||          S )aC  
        Supporting header for the elements besides the initial header, the string pool and
        the resource map.

        :param file: the xml file e.g. with open('/path/AndroidManifest.xml', 'rb') as file
        :type file: bytesIO
        :return: Returns an instance of itself
        :rtype: ResXMLHeader
        r   r   )r
   r   r   r   )r   r   r)   r   s       r   r   zResXMLHeader.parseg  sU      %%d++!!))F$6$:;;Ks6;'''r   Nr3   r&   r   r   r   r   Z  sT         ~     ( ( [( ( (r   r   c                   :    e Zd ZdZdefdZedefd            ZdS )XmlStartNamespacezX
    The actual start of the xml, after this the elements of the xml will be found.
    r)   c                 0    || _         || _        || _        d S r   )r)   extr   )r   r)   r   ext_datas       r   r   zXmlStartNamespace.__init__~  s    			r   header_tc                     |j         j        |j         j        z
  dz  }|                    |dz            fdt	          dt                    d          D             }d |D             } | ||          S )aF  
        Parse the starting element of a Namespace
        :param file: the axml already pointing at the right offset
        :type file: bytesIO
        :param header_t: the already read header of the chunk
        :type header_t: ResXMLHeader
        :return: an instance of itself
        :rtype: XmlStartNamespace
        r?   c                 *    g | ]}||d z            S r   r&   )r   rH   r   s     r   r   z+XmlStartNamespace.parse.<locals>.<listcomp>  s&    HHH(1QU7#HHHr   r   c                 D    g | ]}t          j        d |          d         S r   r   r   s     r   r   z+XmlStartNamespace.parse.<locals>.<listcomp>  s)    AAAv}T5))!,AAAr   )r)   r   r   r   rA   r   )r   r   r   num_extsr   r   r   s         @r   r   zXmlStartNamespace.parse  s     O.1LLQRR99X\**HHHHU1c(mmQ-G-GHHHAA&AAAs8S(+++r   Nr!   r"   r#   r$   r   r   r%   r   r&   r   r   r   r   y  s`         |    
 ,< , , , [, , ,r   r   c                   :    e Zd ZdZdefdZedefd            ZdS )XmlEndNamespacez4
    Class to represent the end of a Namespace.
    r)   c                 >    || _         || _        || _        || _        d S r   )r)   prefix_namespace_index	uri_indexr   )r   r)   r   r   end_namespace_datas        r   r   zXmlEndNamespace.__init__  s#    &<#"&			r   r   c                 x    |                     d          }t          j        d|          \  }} | ||||          S )aD  
        Parse the ending element of a Namespace.

        :param file: the axml already pointing at the right offset
        :type file: bytesIO
        :param header_t: the already read header of the chunk
        :type header_t: ResXMLHeader
        :return: an instance of itself
        :rtype: XmlEndNamespace
        r   <IIr   r   r   )r   r   r   r   r   r   s         r   r   zXmlEndNamespace.parse  sD     "YYq\\,2M%AS,T,T)	s83Y@RSSSr   Nr   r&   r   r   r   r     sg         '| ' ' ' ' T< T T T [T T Tr   r   c                   .    e Zd ZdZd Zed             ZdS )XmlAttributeElementz`
    The attributes within each element within the axml, should be described by this class.
    c                 h    || _         || _        || _        || _        || _        || _        || _        d S r   )full_namespace_index
name_indexraw_value_indextyped_value_sizetyped_value_res0typed_value_datatypetyped_value_data)r   r   r   r   r   r   r   r   s           r   r   zXmlAttributeElement.__init__  s?    $8!$. 0 0$8! 0r   c                    g }t          d|          D ]r}|                                }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }	t          j        d|                    d                    d         }
t          j        d|                    d                    d         }t          j        d|                    d                    d         }|dk    r=t          t          j        d|                    d                    d         d          }n|d	k    r/t          j        d|                    d                    d         }nc|d
k    r/t          j        d|                    d                    d         }n.t          j        d|                    d                    d         }|                     | |||	|
|||                     |                                |z
  |k    r-|                    ||                                |z
  z
             t|S )a  
        The method is responsible to parse and retrieve the attributes of an element based on the attribute count.
        There are many datatypes that are not read according to the specification (at least for now), but that does
        not affect the main goal of the tool, therefore it is not a priority. For the presentation of the values
        another check is occurring in the process_attributes method.

        :param file: the axml already pointing at the right offset
        :type file: BytesIO
        :param attr_count: The attribute count value part of XmlStartElement.attrext
        :type attr_count: int
        :param attr_size: The attribute size value part of XmlStartElement
        :type attr_size: int
        :return: List of attributes
        :rtype: list
        r   r>   r?   rS   rT   z<Br   z<f   rU   z<i)rA   rC   r   r   r   roundrB   )r   r   
attr_count	attr_sizeattrs_tnr   r   r   r   r   r   r   s                 r   r   zXmlAttributeElement.parse  s)   " q*%% 	: 	:AB#)=tyy||#D#DQ#G tTYYq\\::1=J$mD$))A,,??BO%}T499Q<<@@C%}T499Q<<@@C#)=tyy||#D#DQ#G #q((#(tTYYq\\)J)J1)Mq#Q#Q  %**#)=tyy||#D#DQ#G  %++#)=tyy||#D#DQ#G  #)=tyy||#D#DQ#G LL1:P`br13CE E F F Fyy{{R9,,		)tyy{{R'78999r   Nr    r&   r   r   r   r     sH         1 1 1 % % [% % %r   r   c                   :    e Zd ZdZdefdZedefd            ZdS )XmlStartElementz
    The starting point of an element, its attributes are described by XmlAttributeElement.
    The attrext contains information about the element including the attribute count.
    r)   c                 >    || _         || _        || _        || _        d S r   )r)   attrext
attributesr   )r   r)   r   r   start_element_datas        r   r   zXmlStartElement.__init__  s"    $&			r   r   c                 j   |                     d          }t          j        d|          \  }}}}}}	}
}||||||	|
|g}|dk    r|dz
  }|                     |           |                     ||z            }t                              t          j        |          ||          } | |||||z             S )a5  
        Parse the current element

        :param file: the axml already pointing at the right offset
        :type file: BytesIO
        :param header_t: the already read header of the chunk
        :type header_t: ResXMLHeader
        :return: an instance of itself
        :rtype: XmlStartElement
        r1   z	<IIHHHHHH)r   r   r   r   r   ioBytesIO)r   r   r   attrext_datar   r   
attr_startr   r   id_indexclass_indexstyle_indexr   gap_sizeattributes_datar   s                   r   r   zXmlStartElement.parse  s     yy}}rxrs' s'oj*iXWbdo'ZJX`bm !BHIIh))I
$:;;(..rz//J/JJXabb
s8Wj</3QSSSr   Nr   r&   r   r   r   r     sg         
'| ' ' ' ' T< T T T [T T Tr   r   c                   :    e Zd ZdZdefdZedefd            ZdS )XmlEndElementzo
    The end of an element, where the attrext contains the necessary information on which element it ends.
    r)   c                 0    || _         || _        || _        d S r   )r)   r   r   )r   r)   r   r   s       r   r   zXmlEndElement.__init__  s     			r   r   c                 ~    |                     d          }t          j        d|          \  }}||g} | |||          S )a6  
        Parse the end of an element.

        :param file: the axml already pointing at the right offset
        :type file: bytesIO
        :param header_t: the already read header of the chunk
        :type header_t: ResXMLHeader
        :return: an instance of itself
        :rtype: XmlEndElement
        r   r   r   )r   r   r   r   r   r   r   s          r   r   zXmlEndElement.parse  sH     yy||+1=+M+M(j'4s8Wl333r   Nr   r&   r   r   r   r     s`         !| ! ! ! !
 4< 4 4 4 [4 4 4r   r   c                   :    e Zd ZdZdefdZedefd            ZdS )XmlcDataElementzq
    A class to cover any CDATA section
    https://developer.android.com/reference/org/w3c/dom/CDATASection
    r)   c                 h    || _         || _        || _        || _        || _        || _        || _        d S r   )r)   
data_indexr   r   r   r   r   )r   r)   r   r   r   r   r   
cdata_datas           r   r   zXmlcDataElement.__init__1  s;    $ 0 0$8! 0			r   r   c           	          |                     d          }t          j        d|          \  }}}}} | |||||||          S )a4  
        Parse the CDATA element.

        :param file: the axml already pointing at the right offset
        :type file: bytesIO
        :param header_t: the already read header of the chunk
        :type header_t: ResXMLHeader
        :return: an instance of itself
        :rtype: XmlcDataElement
           z<IHBBIr   )	r   r   r   r   r   r   r   r   r   s	            r   r   zXmlcDataElement.parse;  sk     YYr]]
aganow  zD  bE  bE^
$&68LN^s8Z)9;K')9:G G 	Gr   Nr   r&   r   r   r   r   +  sg         
|     G< G G G [G G Gr   r   c                       e Zd ZdZdededefdZede	j
        fd            Zed             Zedd
            Zd Zedd            Zed             Zd	S )ManifestStructzC
    A class to represent the AndroidManifest as a composition
    r)   string_poolresource_mapc                 >    || _         || _        || _        || _        d S r   )r)   r   r   elements)r   r)   r   r   r   s        r   r   zManifestStruct.__init__R  s$    &( r   r   c                 |   d}	 |                                  }|                                 j        ||z   k     rdS 	 t          j        d|                     d                    \  }}}|                     |           ||cxk    r|k    rn ndS n# t          j        $ r Y dS w xY w|                     |dz              )a  
        Static method to check if the next element right after the resource map chunk has been reached.
        Android tolerates unknown chunk types, so we only need to verify
        there's enough data for a header and that the header size is plausible.
        Reference: AOSP ResXMLTree::setTo()

        :param file: The AndroidManifest file
        :type file: io.BytesIO
        r   Tz<HHLr   N)rC   rj   rk   r   r   r   rK   rM   )r   min_sizeru   _type_header_size_sizes         r   check_reached_elementz$ManifestStruct.check_reached_elementX  s     	#iikkG~~&8);;;-3]6499Q<<-P-P*|U		'"""|4444u444444<   IIgk"""	#s   AB B"!B"c                     t                               |           }|j        }|dS t          |j                  }t
                              |t
          d                   } || |          S )a  
        Dispatcher method to parse the next available header. It takes into account to move on past the header if it
        contains extra info besides the standard ones.
        The dispatcher automatically picks the correct processing method for each chunk type.

        :param file: the axml that will be processed
        :type file: bytesIO
        :raises NotImplementedError: The chunk type identified is not supported
        :return: Dispatches to the appropriate processing method for each chunk type.
        Ndefault)r   r   r)   hexr   chunk_type_handlersget)r   chunk_header_totalchunk_header
chunk_typehandlers        r   parse_next_headerz ManifestStruct.parse_next_headerq  si     *//55)04*++
%))*6I)6TUUwt/000r   Nc                 Z   g }	 |                                  }|                                 j        |dz   k     rnt                              |            t
                              |           }t          | |j                  }|j        j	        |j	        z   |z   }t          
                    t          j        |                    }t          |t                    r"d|v rt          j        d|d                     |                    |           |t%          |          |k    rn'|S )a  
        It starts processing the remaining chunks **after** the resource map chunk.

        :param file: the axml that will be processed
        :type file: BytesIO
        :param num_of_elements: how many elements should it process
        :type num_of_elements: int
        :return: Returns all the elements found as their corresponding classes and whether dummy data were found in between.
        :rtype: set(list, set(bool, bool))
        Tr   rawzUnknown chunk type found: r   )rC   rj   rk   r   r   r   r   rs   r)   r   r   r   r   
isinstancedictrD   rE   rB   r   )r   num_of_elementsr   ru   resXMLTree_nodecur_elem_data	elem_dataelements           r   process_elementszManifestStruct.process_elements  s    	iikkG~~&14400666*0066O*41GHHM'.3o6JJ]ZI$66rz)7L7LMMG'4(( Ug-=-= NWV_ N NOOOOOG$$$&8}}//#	$ r   c                 D    t          | j        | j        j                  }|S )z
        Method to return the AndroidManifest created from this instance

        :return: The AndroidManifest.xml as a string
        :rtype: str
        )create_manifestr   r   r:   )r   manifests     r   get_manifestzManifestStruct.get_manifest  s      #4=$2B2NOOr   c                     t                               |           }t                              |           \  }}t                              |           \  }}t
                              | |          }|||g||g|fS )aR  
        Parse the AndroidManifest with a limit on the elements to be parsed after the string pool. The goal of this method
        is to make it possible to partially parse the AndroidManifest and allow faster parsing when needed. Only the
        header is parsed from each chunk, and the rest are there as blobs of bytes.

        :param manifest: The manifest to be processed
        :type manifest: bytesIO
        :param num_of_elements: How many elements of the manifest to process. Usually 3 are enough to get basic info about it.
        :type num_of_elements: int
        :return: A tuple containing four elements: ResChunkHeader, [ResStringPoolHeader, string_pool_data], [ResChunkHeader, resource_map_data], elements
        :rtype: tuple (ResChunkHeader_init, [ResStringPoolHeader, bytes], [ResChunkHeader, bytes], list of bytes)
        r   )r
   r   r5   rv   r   r   r   )r   r   ResChunkHeader_initrt   r<   r   r   r   s           r   rv   zManifestStruct.parse_lite  s     -228<<1?1J1J81T1T..1C1N1Nx1X1X..!228_2]]"%9;K$LObO`Obckl 	lr   c                     t                               |          }t                              |          }t                              |          }|                     |          } | ||||          S )a$  
        A composition of the rest of the classes available in the apkInspector.axml module, to form the AndroidManifest structure.

        :param file: the axml that will be processed
        :type file: bytesIO
        :return: an instance of itself
        :rtype: ManifestStruct
        )r
   r   r5   r   r   )r   r   r)   r   r   r   s         r   r   zManifestStruct.parse  sf      %%d++$**400)//55''--s6;h???r   r   )r!   r"   r#   r$   r
   r5   r   r   staticmethodr   r   r   r   r   r   rv   r%   r   r&   r   r   r   r   M  s         !~ !N !Zl ! ! ! ! #BJ # # # \#0 1 1 \1&    \@   l l l \l( @ @ [@ @ @r   r   r   r   c                 d    t          | |j                  }t          |j        j                  |dS )z
    Default handler for unknown chunk types.
    # ResourceTypes.cpp skips unrecognized chunk types
    # as long as their size and header are valid.
    # Reference: AOSP ResXMLTree::setTo() and ResXMLParser::nextNode()
    )r   r   )rs   r)   r   r   )r   r   r   s      r   handle_unknown_chunkr    s9     $00D HO())  r   )0x1000x1010x1020x1030x104r   r)   c                 J    |j         |j        z
  }|                     |          S )a$  

    :param file: the current file that is being processed
    :type file: io.BytesIO
    :param header: the header of the current chunk of instance ResChunkHeader
    :type header: ResChunkHeader
    :return: Returns the remaining bytes of the chunk except the header
    :rtype: bytes
    )r   r   r   )r   r)   remaining_to_be_reads      r   rs   rs     s(     ",v/AA99)***r   c           
      l   g }| D ]}	 ||j                  }n#  Y xY w|sdt          j        dd           }d|v r8|j        dk    rd|j         }n|j        dk    r*	 t          ||j                           }n{#  |j        }Y npxY w|j        dk    rd	                    |j                  }nG|j        d
k    rt          |j                  rdnd}n#|j        dk    r|c S t          |j                  }|j	        t          |          k     rw||j	                 }|sd}	 |                    ||          d| d| d           @#  |                    |                    d          d          d| d| d           Y |xY w|                    | d| d           d                    |          S )a  
    Helps in processing the representation of attributes found in each element of the axml. It should be noted that not
    all datatypes are taken into account, meaning that the values of certain attributes might not be represented properly.

    :param attributes: the attributes of an XmlStartElement object as returned by XmlAttributeElement.parse()
    :type attributes: list
    :param string_list: the string data list from the String Pool
    :type string_list: list
    :param ns_dict: a namespace dictionary based on the XmlStartNamespace elements found
    :type ns_dict: dict
    :return: returns a string of all the attributes with their values
    :rtype: str
    Unknown_Attribute_Name_i  i'  
r   @      z0x{:08X}   truefalser   android:=""/rd    )r   randomrandintr   r   r   r   rz   strr   r   rB   splitjoin)r   r:   ns_dictattribute_listattrnamevalue	namespaces           r   process_attributesr$    s1    N $7 $7	t/DD	H 	JIV^D$-G-GIID4<<$))/-//EE&!++.+K8M,NOO.-&",,%%d&;<<EE&",,"4#899FFFwEE&!++KKK -..E$s;'7'777#D$=>I &%	V%%);&N&Nd&N&Ne&N&N&NOOOOV%%)=)=b)A&T&TD&T&TE&T&T&TUUUUU!!T"5"5U"5"5"5666688N###s    A::	B$E9Fc                    g }i }i }g }| D ]}t          |t                    r|j        d         t          |          k     s|j        d         t          |          k     rfd||j        d                   d||j        d                   d|||j        d                  <   ||j        d                  |||j        d                  <   t          |t                    r3t          |j        ||          }t          d |                    d          D                       }g }	|D ]V}
|
|vrP|
|v r|		                    ||
                    n|
dk    r|		                    d	           |	                    |
           W|	rJ|r0d
||j
        d                   dd                    |	           d| dnd
||j
        d                   d}n3|rd
||j
        d                   d| dnd
||j
        d                   d}|	                    |           t          |t                    r>|d         d         dk    r*|d                             d||j                           |d<   Wt          |t                    r:||j
        d                  }|dk    rd| dnd| d}|	                    |           d                    |          S )an  
    Method to create the readable XML AndroidManifest.xml file based on the elements discovered from the processed APK

    :param elements: The parsed elements as returned by process_elements()[0]
    :type elements: list
    :param string_list: The string pool data
    :type string_list: list
    :return: The AndroidManifest.xml as a string
    :rtype: str
    r   r   zxmlns:r  r  c              3   T   K   | ]#}d |v |                     d           d         V  $dS )r  r   N)r  )r   nss     r   	<genexpr>z"create_manifest.<locals>.<genexpr>J  s=      ]]BSVZ\S\S\rxx}}Q/S\S\S\S\]]r   r  r  z:xmlns:android="http://schemas.android.com/apk/res/android"<z>
rd   r  r   z</>rV   )r   r   r   r   r   r$  r   setr  rB   r   r  r   rX   r   r   )r   r:   android_manifest_xml
namespacesr  ns_declaredr   r   attr_ns_listtmp_nsvltag_liner!  closing_tags                 r   r   r   4  s    JGK 5 5g011 	5{1~K 0 000GKNSEUEU4U4U ;A;w{[\~C^  ;A  ;Abmnunyz{n|b}  ;A  ;A  ;A
;w{1~677B7;q>7RGKN3411 	5+G,>WUUJ]]*:J:J3:O:O]]]]]LF" + +[((Z''jn5555y&cddd&&r*** Mgq  `c{7?1+=>cc&AQAQccT^cccc  x`  |G  HO  HW  XY  HZ  |[  x`  x`  x`T^  MP{7?1+=>PPPPPP  eMhst{  uD  EF  uG  iH  eM  eM  eM ''111111 	5#B'+t33+?+C+K+KDLWX_XjLk,m ,m$R(// 	5wq12D*.**<*<,t,,,,.t...K ''44477'(((r   c                 ^    t                               |           }|                                S )a&  
    Helper method to directly return the AndroidManifest file as created by create_manifest()

    :param raw_manifest: expects the encoded AndroidManifest.xml file as a file-like object
    :type raw_manifest: bytesIO
    :return: returns the decoded AndroidManifest file
    :rtype: str
    )r   r   r   )raw_manifestmanifest_objects     r   r   r   c  s)     %**<88O'')))r   Fr  r   liter   c                    |r| }nNt          | d          5 }t          j        |                                          }ddd           n# 1 swxY w Y   t	          j        |d          }|j        d                                         }t          |||j	        j
        d                                                   d         }|r$t          t          j        |          |          }	n!t          t          j        |                    }	|	S )aa  
    Helper method to retrieve the AndroidManifest directly from an APK, either by providing the APK itself or the path.

    :param inc_apk: The path of the APK file or the APK itself
    :type inc_apk: str
    :param raw: Boolean parameter to define whether the manifest is provided as string or bytes
    :type raw: bool
    :param lite: Boolean parameter to define whether the lite parsing would occur or not
    :type lite: bool
    :param num_of_elements: Number of elements to parse from the APK
    :type num_of_elements: int
    :return: Returns the AndroidManifest.xml as string
    :rtype: str
    rbNzAndroidManifest.xmlr   r   )openr   r   r   r   parse_singlelocal_headersto_dictr   central_directoryentriesget_manifest_liter   )
inc_apkr   r7  r   apk_fileapkentry_manifestmanifest_localmanifest_bytesr   s
             r   parse_apk_for_manifestrG  p  s<     .'4   	.Cz#((**--H	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. *85JKKN#12GHPPRRN6x7E7W7_;P8RRYRYR[R[] ]]^`N  <$RZ%?%?Q`aaa
> : :;;Os   'A		AAr   c                    t                               | |          \  }\  }}\  }}}|j        j        dz   }|j        }	t          |j        dz            }
i }|D ]}t          |t                    r|j	        D ]w}t          |t                    r`t                              |j        t          j        |          ||	|
          }t!          ||||	|
t          j        |                    }|||<   x|S )aP  
    A method to provide 'lite' parsing of the AndroidManifest in order to retrieve a few details as fast as possible.
    Based on the integer 'num_of_elements' being passed as a parameter, it will attempt to fetch this many chunks right
    after the 'resource map' chunk and will get the attributes values of these elements if they are of instance XmlStartElement

    :param manifest: The manifest to be processed
    :type manifest: io.BytesIO
    :param num_of_elements:
    :type num_of_elements: int
    :return: Returns a dictionary of the attributes discovered
    :rtype: dict
    r   r   rx   )r   rv   r)   r   r.   rz   r-   r   r   r   r   r5   rp   r   r   r   get_attribute_value)r   r   r   string_pool_ResChunkHeaderr<   r   r   r   r\   r.   r[   attributes_dictr   r   	attr_nameattribute_values                   r   r@  r@    s2    <J;T;TU]et <U <v <v93 "2-,x6=H1L.<M-3v>??GO A Ag// 	A* A Ad$788 A . C CDOUWU_`pUqUqDY[hjq!s !sI&9)TK`bo:A2:N^C_C_'a 'aO1@OI.r   c                    	 |j         dk    r
d|j         S |j         dk    rHt                              |j        ||||          }|rt	          |          nt          |j                  S |j         dk    r`t                              |j        ||||          }|s#t                              |j        ||||          }|r|nt          |j                  S |j         dk    rd|j        dS |j         dk    r|j        rd	nd
S t          |j                  S # t          $ r8}t          j	        d|  d|            t          |j                  cY d}~S d}~ww xY w)a  
    Gets the value for a single attribute

    :param attr_name: The attribute name as it has been retrieved by the string pool
    :type attr_name: str
    :param attribute: the parsed attribute itself
    :type attribute: XmlAttributeElement
    :param end_stringpool_offset: The end of string pool offset
    :type end_stringpool_offset: int
    :param strings_start: the strings start offset for the string pool
    :type strings_start: int
    :param is_utf8: boolean to check if a utf8 string is expected
    :type is_utf8: bool
    :param string_pool_data: The string pool data as io.BytesIO
    :type string_pool_data: io.BytesIO
    :return: returns the attribute value
    :rtype: str
    r   r  r  r?   r  0x08Xr  r  r  zException processing attribute z: N)
r   r   r5   rp   r   r  r   rL   rD   ro   )rL  	attributer\   r.   r[   r<   str_pool_locrP   s           r   rI  rI    s   &/)Q..3y1333+q00)>>y?Y[k?T?LgW WL 9Ei&|444#iNhJiJii+q00)>>y?Y[k?T?LgW WL   [-BB9C\^nCXCPRY [  [ $0T<<S9S5T5TT+r118	28888+r11&7D66WDy1222 / / /LILLLLMMM9-......../s<   D AD *A*D D +D D 
E-EEE)FFr  )%r   rD   r   r  extractr   headersr   helpersr   basicConfigDEBUGr
   r(   r5   r   r   r   r   r   r   r   r   r   r   r  r   r   rs   r$  r   r   rz   intrG  r@  rI  r&   r   r   <module>rY     s   				    6 6 6 6 6 6       ( ( ( ( ( (  
-`   F F F F F F F F>: : : : : : : :@]
 ]
 ]
 ]
 ]
 ]
 ]
 ]
@(0 (0 (0 (0 (0 (0 (0 (0V( ( ( ( ( ( ( (>, , , , , , , ,8T T T T T T T T85 5 5 5 5 5 5 5p#T #T #T #T #T #T #T #TL4 4 4 4 4 4 4 48G G G G G G G GDF@ F@ F@ F@ F@ F@ F@ F@Rrz \      $"" "#  + +^ + + + +5$ 5$ 5$p,) ,) ,)^
* 
* 
*  T \_    B
 S    B,/ ,/ ,/ ,/ ,/r   