def _get_sicd_xml_from_nitf(sicd_details): """ Fetch the xml string for the SICD. Parameters ---------- sicd_details : SICDDetails """ for i in range(sicd_details.des_subheader_offsets.size): subhead_bytes = sicd_details.get_des_subheader_bytes(i) if subhead_bytes.startswith(b'DEXML_DATA_CONTENT'): des_bytes = sicd_details.get_des_bytes(i).decode('utf-8').strip() # noinspection PyBroadException try: root_node, xml_ns = parse_xml_from_string(des_bytes) if 'SICD' in root_node.tag: # namespace makes this ugly return des_bytes, root_node, xml_ns except Exception: continue elif subhead_bytes.startswith(b'DESICD_XML'): # This is an old format SICD des_bytes = sicd_details.get_des_bytes(i).decode('utf-8').strip() try: root_node, xml_ns = parse_xml_from_string(des_bytes) if 'SICD' in root_node.tag: # namespace makes this ugly return des_bytes, root_node, xml_ns except Exception as e: logger.error('We found an apparent old-style SICD DES header, ' 'but failed parsing with error {}'.format(e)) continue return None, None, None
def _find_sicd(self): self._is_sicd = False self._sicd_meta = None if self.des_subheader_offsets is None: return for i in range(self.des_subheader_offsets.size): subhead_bytes = self.get_des_subheader_bytes(i) if subhead_bytes.startswith(b'DEXML_DATA_CONTENT'): des_header = DataExtensionHeader.from_bytes(subhead_bytes, start=0) des_bytes = self.get_des_bytes(i) # noinspection PyBroadException try: root_node, xml_ns = parse_xml_from_string(des_bytes.decode('utf-8').strip()) if 'SIDD' in root_node.tag: # namespace makes this ugly # NOTE that SIDD files are supposed to have the corresponding # SICD xml as one of the DES AFTER the SIDD xml. # The same basic format is used for both headers. # So, abandon if we find a SIDD xml self._des_index = None self._des_header = None self._is_sicd = False break elif 'SICD' in root_node.tag: # namespace makes this ugly self._des_index = i self._des_header = des_header self._is_sicd = True self._sicd_meta = SICDType.from_node(root_node, xml_ns, ns_key='default') break except Exception: continue elif subhead_bytes.startswith(b'DESIDD_XML'): # This is an old format SIDD and can't be a SICD self._des_index = None self._des_header = None self._is_sicd = False break elif subhead_bytes.startswith(b'DESICD_XML'): # This is an old format SICD des_bytes = self.get_des_bytes(i) try: root_node, xml_ns = parse_xml_from_string(des_bytes) if 'SICD' in root_node.tag: # namespace makes this ugly self._des_index = i self._des_header = None self._is_sicd = True self._sicd_meta = SICDType.from_node(root_node, xml_ns, ns_key='default') break except Exception as e: logging.error('We found an apparent old-style SICD DES header, ' 'but failed parsing with error {}'.format(e)) continue if not self._is_sicd: return self._sicd_meta.derive()
def _find_sidd(self): self._is_sidd = False if self.des_subheader_offsets is None: return self._sidd_meta = [] self._sicd_meta = [] for i in range(self.des_subheader_offsets.size): subhead_bytes = self.get_des_subheader_bytes(i) if subhead_bytes.startswith(b'DEXML_DATA_CONTENT'): des_bytes = self.get_des_bytes(i) try: root_node, xml_ns = parse_xml_from_string(des_bytes) if 'SIDD' in root_node.tag: self._is_sidd = True self._sidd_meta.append(SIDDType.from_node(root_node, xml_ns, ns_key='default')) elif 'SICD' in root_node.tag: self._sicd_meta.append(SICDType.from_node(root_node, xml_ns, ns_key='default')) except Exception as e: logging.error('Failed checking des xml header at index {} with error {}'.format(i, e)) continue elif subhead_bytes.startswith(b'DESIDD_XML'): # This is an old format SIDD header des_bytes = self.get_des_bytes(i) try: root_node, xml_ns = parse_xml_from_string(des_bytes) if 'SIDD' in root_node.tag: self._is_sidd = True self._sidd_meta.append(SIDDType.from_node(root_node, xml_ns, ns_key='default')) except Exception as e: logging.error('We found an apparent old-style SIDD DES header at index {}, ' 'but failed parsing with error {}'.format(i, e)) continue elif subhead_bytes.startswith(b'DESICD_XML'): # This is an old format SICD header des_bytes = self.get_des_bytes(i) try: root_node, xml_ns = parse_xml_from_string(des_bytes) if 'SICD' in root_node.tag: self._sicd_meta.append(SICDType.from_node(root_node, xml_ns, ns_key='default')) except Exception as e: logging.error('We found an apparent old-style SICD DES header at index {}, ' 'but failed parsing with error {}'.format(i, e)) continue if not self._is_sidd: return for sicd in self._sicd_meta: sicd.derive()
def generic_construction_test(instance, the_type, the_dict, tag='The_Type', print_xml=False, print_json=False): if not issubclass(the_type, Serializable): raise TypeError( 'Class {} must be a subclass of Serializable'.format(the_type)) the_item = the_type.from_dict(the_dict) with instance.subTest(msg='Comparing json deserialization with original'): new_dict = the_item.to_dict() if print_json: print(json.dumps(the_dict, indent=1)) print(json.dumps(new_dict, indent=1)) instance.assertEqual(the_dict, new_dict) with instance.subTest(msg='Test xml serialization issues'): # let's serialize to xml xml = the_item.to_xml_string(tag=tag) if print_xml: print(xml) # let's deserialize from xml node, xml_ns = parse_xml_from_string(xml) item2 = the_type.from_node(node, xml_ns) instance.assertEqual(the_item.to_dict(), item2.to_dict()) with instance.subTest(msg='Test validity'): instance.assertTrue(the_item.is_valid()) return the_item
def _extract_cphd(self, fi): """ Extract and interpret the CPHD structure from the file. Parameters ---------- fi The open file object, required to be opened in binary mode. Returns ------- None """ xml = self._get_cphd_bytes(fi) if self.cphd_version.startswith('0.3'): the_type = CPHDType0_3 elif self.cphd_version.startswith('1.0'): the_type = CPHDType else: raise ValueError('Got unhandled version number {}'.format( self.cphd_version)) root_node, xml_ns = parse_xml_from_string(xml) if 'default' in xml_ns: self._cphd_meta = the_type.from_node(root_node, xml_ns, ns_key='default') else: self._cphd_meta = the_type.from_node(root_node, xml_ns)
def check_file(file_name): """ Check the SICD validity for the given file SICD (i.e. appropriately styled NITF) or xml file containing the SICD structure alone. Parameters ---------- file_name : str|SICDDetails Returns ------- bool """ sicd_xml, root_node, xml_ns, urn_string = None, None, None, None if isinstance(file_name, SICDDetails): sicd_xml, root_node, xml_ns = _get_sicd_xml_from_nitf(file_name) else: # check if this is just an xml file with open(file_name, 'rb') as fi: initial_bits = fi.read(100) if initial_bits.startswith(b'<?xml') or initial_bits.startswith(b'<SICD'): sicd_xml = fi.read().decode('utf-8') root_node, xml_ns = parse_xml_from_string(sicd_xml) if sicd_xml is None: # try to first test whether this is SICD file try: sicd_details = SICDDetails(file_name) if not sicd_details.is_sicd: logger.error('File {} is a NITF file, but is apparently not a SICD file.') return False sicd_xml, root_node, xml_ns = _get_sicd_xml_from_nitf(sicd_details) except SarpyIOError: pass if sicd_xml is None: logger.error('Could not interpret input {}'.format(file_name)) return False urn_string = xml_ns['default'] valid_xml = evaluate_xml_versus_schema(sicd_xml, urn_string) if valid_xml is None: valid_xml = True the_sicd = SICDType.from_node(root_node, xml_ns=xml_ns) valid_sicd_contents = the_sicd.is_valid(recursive=True, stack=False) return valid_xml & valid_sicd_contents
def _extract_cphd(self, fi): """ Extract and interpret the CPHD structure from the file. Parameters ---------- fi The open file object, required to be opened in binary mode. Returns ------- None """ header = self.cphd_header if header is None: raise ValueError('No cphd_header populated.') if self.cphd_version.startswith('0.3'): assert isinstance(header, CPHDHeader0_3) # extract the xml data fi.seek(header.XML_BYTE_OFFSET) xml = fi.read(header.XML_DATA_SIZE) the_type = CPHDType0_3 elif self.cphd_version.startswith('1.0'): assert isinstance(header, CPHDHeader) # extract the xml data fi.seek(header.XML_BLOCK_BYTE_OFFSET) xml = fi.read(header.XML_BLOCK_SIZE) the_type = CPHDType else: raise ValueError('Got unhandled version number {}'.format( self.cphd_version)) root_node, xml_ns = parse_xml_from_string(xml) if 'default' in xml_ns: self._cphd_meta = the_type.from_node(root_node, xml_ns, ns_key='default') else: self._cphd_meta = the_type.from_node(root_node, xml_ns) return xml
def get_sicd(self): """ Extract the SICD details. Returns ------- SICDType """ if self._sicd is not None: return self._sicd if self._user_data is None: self._read_user_data() if self._caspr_data is None: self._find_caspr_data() # Check if the user data contains a sicd structure. sicd_string = None for nam in ['SICDMETA', 'SICD_META', 'SICD']: if sicd_string is None: sicd_string = self._user_data.get(nam, None) # If so, assume that this SICD is valid and simply present it if sicd_string is not None: root_node, xml_ns = parse_xml_from_string(sicd_string) self._sicd = SICDType.from_node(root_node, xml_ns) self._sicd.derive() else: # otherwise, we populate a really minimal sicd structure num_rows, num_cols = self.data_size self._sicd = SICDType(ImageData=ImageDataType( NumRows=num_rows, NumCols=num_cols, FirstRow=0, FirstCol=0, PixelType=self.pixel_type, FullImage=FullImageType(NumRows=num_rows, NumCols=num_cols), SCPPixel=RowColType(Row=num_rows / 2, Col=num_cols / 2))) return self._sicd