Example #1
0
    def _create_data_extension_details(self):
        super(SICDWriter, self)._create_data_extension_details()
        uh_args = self.sicd_meta.get_des_details(self._check_older_version)

        desshdt = str(self.sicd_meta.ImageCreation.DateTime.astype('datetime64[s]'))
        if desshdt[-1] != 'Z':
            desshdt += 'Z'
        uh_args['DESSHDT'] = desshdt

        desshlpg = ''
        if self.sicd_meta.GeoData is not None and self.sicd_meta.GeoData.ImageCorners is not None:
            # noinspection PyTypeChecker
            icp = self.sicd_meta.GeoData.ImageCorners.get_array(dtype=numpy.float64)
            temp = []
            for entry in icp:
                temp.append('{0:0=+12.8f}{1:0=+13.8f}'.format(entry[0], entry[1]))
            temp.append(temp[0])
            desshlpg = ''.join(temp)
        uh_args['DESSHLPG'] = desshlpg

        subhead = DataExtensionHeader(
            Security=self._security_tags,
            UserHeader=XMLDESSubheader(**uh_args))

        self._des_details = (
            DESDetails(subhead, self.sicd_meta.to_xml_bytes(tag='SICD', urn=uh_args['DESSHTN'])), )
Example #2
0
    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()
Example #3
0
    def find_des():
        for i in range(nitf_details.des_subheader_offsets.size):
            subhead_bytes = nitf_details.get_des_subheader_bytes(i)
            if nitf_details.nitf_version == '02.00':
                des_header = DataExtensionHeader0.from_bytes(subhead_bytes,
                                                             start=0)
            elif nitf_details.nitf_version == '02.10':
                des_header = DataExtensionHeader.from_bytes(subhead_bytes,
                                                            start=0)
            else:
                raise ValueError('Got unhandled NITF version {}'.format(
                    nitf_details.nitf_version))

            if subhead_bytes.startswith(b'DEXML_DATA_CONTENT'):
                des_bytes = nitf_details.get_des_bytes(i).decode(
                    'utf-8').strip().encode()
                # noinspection PyBroadException
                try:
                    root_node, xml_ns = parse_xml_from_string(des_bytes)
                    if 'SIDD' in root_node.tag:  # namespace makes this ugly
                        sidd_des.append(
                            (i, des_bytes, root_node, xml_ns, des_header))
                    elif 'SICD' in root_node.tag:
                        sicd_des.append(
                            (i, des_bytes, root_node, xml_ns, des_header))
                except Exception:
                    continue
            elif subhead_bytes.startswith(b'DESIDD_XML'):
                # This is an old format SIDD
                des_bytes = nitf_details.get_des_bytes(i).decode(
                    'utf-8').strip().encode()
                try:
                    root_node, xml_ns = parse_xml_from_string(des_bytes)
                    if 'SIDD' in root_node.tag:  # namespace makes this ugly
                        sidd_des.append(
                            (i, des_bytes, root_node, xml_ns, des_header))
                except Exception as e:
                    logger.exception(
                        'SIDD: Old-style SIDD DES header at index {}, but failed parsing'
                        .format(i))
                    continue
            elif subhead_bytes.startswith(b'DESICD_XML'):
                # This is an old format SICD
                des_bytes = nitf_details.get_des_bytes(i).decode(
                    'utf-8').strip().encode()
                try:
                    root_node, xml_ns = parse_xml_from_string(des_bytes)
                    if 'SICD' in root_node.tag:  # namespace makes this ugly
                        sicd_des.append(
                            (i, des_bytes, root_node, xml_ns, des_header))
                except Exception as e:
                    logger.exception(
                        'SIDD: Old-style SICD DES header at index {}, but failed parsing'
                        .format(i))
                    continue
Example #4
0
    def check_data_extension_headers():
        # type: () -> (str, Union[DataExtensionHeader, DataExtensionHeader0])
        sicd_des = []

        for i in range(nitf_details.des_subheader_offsets.size):
            subhead_bytes = nitf_details.get_des_subheader_bytes(i)
            des_bytes = None
            if subhead_bytes.startswith(b'DEXML_DATA_CONTENT'):
                des_bytes = nitf_details.get_des_bytes(i)

            elif subhead_bytes.startswith(b'DESIDD_XML'):
                raise ValueError(
                    'This file contains an old format SIDD DES, and should be a SIDD file'
                )
            elif subhead_bytes.startswith(b'DESICD_XML'):
                des_bytes = nitf_details.get_des_bytes(i)

            if des_bytes is None:
                continue

            # compare the SICD structure and the des header structure
            if nitf_details.nitf_version == '02.00':
                des_header = DataExtensionHeader0.from_bytes(subhead_bytes,
                                                             start=0)
            elif nitf_details.nitf_version == '02.10':
                des_header = DataExtensionHeader.from_bytes(subhead_bytes,
                                                            start=0)
            else:
                raise ValueError('Got unhandled NITF version {}'.format(
                    nitf_details.nitf_version))

            try:
                des_bytes = des_bytes.decode('utf-8').strip().encode()
                root_node, xml_ns = parse_xml_from_string(des_bytes)
                # namespace makes this ugly
                if 'SIDD' in root_node.tag:
                    raise ValueError(
                        'This file contains a SIDD DES, and should be a SIDD file'
                    )
                elif 'SICD' in root_node.tag:
                    sicd_des.append((i, des_bytes, des_header))
            except Exception as e:
                logger.error(
                    'Failed parsing the xml DES entry {} as xml'.format(i))
                raise e

        if len(sicd_des) == 0:
            raise ValueError(
                'No SICD DES values found, so this is not a viable SICD file')
        elif len(sicd_des) > 1:
            raise ValueError('Multiple SICD DES values found at indices {},\n'
                             'so this is not a viable SICD file'.format(
                                 [entry[0] for entry in sicd_des]))

        return sicd_des[0][1], sicd_des[0][2]
Example #5
0
    def _create_sidd_des_segment(self, index):
        """
        Create the details for the sidd data extension at `index`.

        Parameters
        ----------
        index : int

        Returns
        -------
        DESDetails
        """

        imgs = self._img_groups[index]
        security = self.image_details[imgs[0]].subheader.Security
        sidd = self.sidd_meta[index]
        uh_args = sidd.get_des_details()

        try:
            desshdt = str(
                sidd.ProductCreation.ProcessorInformation.ProcessingDateTime.
                astype('datetime64[s]'))
        except AttributeError:
            desshdt = str(numpy.datetime64('now'))
        if desshdt[-1] != 'Z':
            desshdt += 'Z'
        uh_args['DESSHDT'] = desshdt

        desshlpg = ''
        icp = self._get_icp(sidd)
        if icp is not None:
            temp = []
            for entry in icp:
                temp.append('{0:0=+12.8f}{1:0=+13.8f}'.format(
                    entry[0], entry[1]))
            temp.append(temp[0])
            desshlpg = ''.join(temp)
        uh_args['DESSHLPG'] = desshlpg
        subhead = DataExtensionHeader(Security=security,
                                      UserHeader=XMLDESSubheader(**uh_args))
        return DESDetails(subhead, sidd.to_xml_bytes(tag='SIDD'))
Example #6
0
    def _create_sicd_des_segment(self, index):
        """
        Create the details for the sicd data extension at `index`.

        Parameters
        ----------
        index : int

        Returns
        -------
        DESDetails
        """

        security_tags = self.security_tags
        sicd = self.sicd_meta[index]
        uh_args = sicd.get_des_details(check_version1_compliance=True)
        if sicd.ImageCreation.DateTime is None:
            desshdt = datetime.utcnow().isoformat('T', timespec='seconds')
        else:
            desshdt = str(sicd.ImageCreation.DateTime.astype('datetime64[s]'))
        if desshdt[-1] != 'Z':
            desshdt += 'Z'
        uh_args['DESSHDT'] = desshdt

        desshlpg = ''
        if sicd.GeoData is not None and sicd.GeoData.ImageCorners is not None:
            # noinspection PyTypeChecker
            icp = sicd.GeoData.ImageCorners.get_array(dtype=numpy.float64)
            temp = []
            for entry in icp:
                temp.append('{0:0=+12.8f}{1:0=+13.8f}'.format(
                    entry[0], entry[1]))
            temp.append(temp[0])
            desshlpg = ''.join(temp)
        uh_args['DESSHLPG'] = desshlpg

        subhead = DataExtensionHeader(Security=security_tags,
                                      UserHeader=XMLDESSubheader(**uh_args))

        return DESDetails(
            subhead, sicd.to_xml_bytes(tag='SICD', urn=uh_args['DESSHTN']))
Example #7
0
def generic_nitf_header_test(instance, test_file):
    assert isinstance(instance, unittest.TestCase)

    # can we parse it at all? how long does it take?
    with instance.subTest(msg="header parsing"):
        start = time.time()
        details = NITFDetails(test_file)
        # how long does it take?
        logging.info('unpacked nitf details in {}'.format(time.time() - start))
        # how does it look?
        logging.debug(details.nitf_header)

    # is the output as long as it should be?
    with instance.subTest(msg="header length match"):
        header_string = details.nitf_header.to_bytes()
        equality = (len(header_string) == details.nitf_header.HL)
        if not equality:
            logging.error(
                'len(produced header) = {}, nitf_header.HL = {}'.format(
                    len(header_string), details.nitf_header.HL))
        instance.assertTrue(equality)

    # is the output what it should be?
    with instance.subTest(msg="header content match"):
        with open(test_file, 'rb') as fi:
            file_header = fi.read(details.nitf_header.HL)

        equality = (file_header == header_string)
        if not equality:
            chunk_size = 80
            start_chunk = 0
            while start_chunk < len(header_string):
                end_chunk = min(start_chunk + chunk_size, len(header_string))
                logging.error('real[{}:{}] = {}'.format(
                    start_chunk, end_chunk,
                    file_header[start_chunk:end_chunk]))
                logging.error('prod[{}:{}] = {}'.format(
                    start_chunk, end_chunk,
                    header_string[start_chunk:end_chunk]))
                start_chunk = end_chunk
        instance.assertTrue(equality)

    # is each image subheader working?
    if details.img_segment_offsets is not None:
        for i in range(details.img_segment_offsets.size):
            with instance.subTest('image subheader {} match'.format(i)):
                img_bytes = details.get_image_subheader_bytes(i)
                img_sub = ImageSegmentHeader.from_bytes(img_bytes, start=0)
                instance.assertEqual(len(img_bytes),
                                     img_sub.get_bytes_length(),
                                     msg='image subheader as long as expected')
                instance.assertEqual(
                    img_bytes,
                    img_sub.to_bytes(),
                    msg=
                    'image subheader serializes and deserializes as expected')

    # is each text segment working?
    if details.text_segment_offsets is not None:
        for i in range(details.text_segment_offsets.size):
            with instance.subTest('text subheader {} match'.format(i)):
                txt_bytes = details.get_text_subheader_bytes(i)
                txt_sub = TextSegmentHeader.from_bytes(txt_bytes, start=0)
                instance.assertEqual(len(txt_bytes),
                                     txt_sub.get_bytes_length(),
                                     msg='text subheader as long as expected')
                instance.assertEqual(
                    txt_bytes,
                    txt_sub.to_bytes(),
                    msg='text subheader serializes and deserializes as expected'
                )

    # is each graphics segment working?
    if details.graphics_segment_offsets is not None:
        for i in range(details.graphics_segment_offsets.size):
            with instance.subTest('graphics subheader {} match'.format(i)):
                graphics_bytes = details.get_graphics_subheader_bytes(i)
                graphics_sub = GraphicsSegmentHeader.from_bytes(graphics_bytes,
                                                                start=0)
                instance.assertEqual(
                    len(graphics_bytes),
                    graphics_sub.get_bytes_length(),
                    msg='graphics subheader as long as expected')
                instance.assertEqual(
                    graphics_bytes,
                    graphics_sub.to_bytes(),
                    msg=
                    'graphics subheader serializes and deserializes as expected'
                )

    # is each data extenson subheader working?
    if details.des_segment_offsets is not None:
        for i in range(details.des_segment_offsets.size):
            with instance.subTest('des subheader {} match'.format(i)):
                des_bytes = details.get_des_subheader_bytes(i)
                des_sub = DataExtensionHeader.from_bytes(des_bytes, start=0)
                instance.assertEqual(len(des_bytes),
                                     des_sub.get_bytes_length(),
                                     msg='des subheader as long as expected')
                instance.assertEqual(
                    des_bytes,
                    des_sub.to_bytes(),
                    msg='des subheader serializes and deserializes as expected'
                )