Coverage for /home/runner/work/torchcvnn/torchcvnn/src/torchcvnn/datasets/alos2/vol_file.py: 0%
31 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-13 08:53 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-13 08:53 +0000
1# MIT License
3# Copyright (c) 2024 Jeremy Fix
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
23# Standard imports
24from typing import Union
25import pathlib
27# Local imports
28from . import parse_utils
30descriptor_format = [
31 ("record_sequence_number", 0, 4, "B", 1),
32 ("first_record_subtype_code", 4, 1, "B", 192),
33 ("record_type_code", 5, 1, "B", 192),
34 ("second_subtype_code", 6, 1, "B", 18),
35 ("third_subtype_code", 7, 1, "B", 18),
36 ("length_record", 8, 4, "B", 360),
37 ("flag", 12, 2, "A", "A "),
38 # ("blanks", 14, 2, "A", " "),
39 ("superstructure_doc_id", 16, 12, "A", "CEOS-SAR "),
40 ("superstructure_doc_rev_level", 28, 2, "A", " A"),
41 ("superstructure_fmt_rev_level", 30, 2, "A", " A"),
42 ("software_release_level", 32, 12, "A", None),
43 ("physical_volume_id", 44, 16, "A", None),
44 ("logical_volume_id", 60, 16, "A", None),
45 ("volume_set_id", 76, 16, "A", None),
46 ("total_number_volumes", 92, 2, "I", 1),
47 ("physical_volume_seq_num_first", 94, 2, "I", 1),
48 ("physical_volume_seq_num_last", 96, 2, "I", 1),
49 ("physical_volume_seq_num_cur", 98, 2, "I", 1),
50 ("file_number", 100, 4, "I", None),
51 ("logical_volume_within_volume", 104, 4, "I", None),
52 ("logical_volume_within_physical", 108, 4, "I", None),
53 ("logical_volume_creation_date", 112, 8, "A", None), # YYYYMMDD
54 ("logical_volume_creation_time", 120, 8, "A", None), # HHMMSSXX
55 ("logical_volume_creation_country", 128, 12, "A", None),
56 ("logical_volume_creation_agency", 140, 8, "A", None),
57 ("logical_volume_generation_facility", 148, 12, "A", None),
58 ("number_of_file_pointer_records", 160, 4, "I", None),
59 ("number_of_text_records", 164, 4, "I", None),
60 # Volume descriptor spare A92 + local use segment A100
61]
62volume_descriptor_record_length = 360
64file_pointer_format = [
65 ("record_number", 0, 4, "B", None),
66 ("record_type", 5, 1, "B", None),
67 ("reference_id", 20, 16, "A", None),
68 ("reference_file_class_code", 64, 4, "A", None),
69 # ("number_of_records", 100, 8, "I", None),
70 # ("number_of_physical", 140, 2, "I", None),
71]
72file_pointer_record_length = 360
74text_records_format = [
75 ("record_number", 0, 4, "B", None),
76 ("product_id", 16, 40, "A", None),
77 ("scene_id", 156, 40, "A", None),
78 ("scene_location_id", 196, 40, "A", None),
79]
80text_record_length = 360
83class VolFile:
84 r"""
85 Processing a Volume Directory file in the CEOS format. The parsed
86 informations can be accessed through the attributes `descriptor_records`,
87 `file_pointer_records` and `text_records`
89 Arguments:
90 filepath: the path to the volume directory file
91 """
93 def __init__(self, filepath: Union[str, pathlib.Path]):
94 self.descriptor_records = {}
95 self.file_pointer_records = []
96 self.text_record = {}
98 with open(filepath, "rb") as fh:
99 # Parsing the volume descriptor
100 fh_offset = 0
101 fh_offset = parse_utils.parse_from_format(
102 fh,
103 self.descriptor_records,
104 descriptor_format,
105 1,
106 volume_descriptor_record_length,
107 fh_offset,
108 )
110 # Parsing the file pointer
111 number_of_file_pointer_records = self.descriptor_records[
112 "number_of_file_pointer_records"
113 ]
114 fh_offset = parse_utils.parse_from_format(
115 fh,
116 self.file_pointer_records,
117 file_pointer_format,
118 number_of_file_pointer_records,
119 file_pointer_record_length,
120 fh_offset,
121 )
123 # Parsing the file pointer
124 fh_offset = parse_utils.parse_from_format(
125 fh,
126 self.text_record,
127 text_records_format,
128 1,
129 text_record_length,
130 fh_offset,
131 )
133 @property
134 def num_polarizations(self):
135 return len(
136 [
137 True
138 for fp in self.file_pointer_records
139 if fp["reference_file_class_code"] == "IMOP"
140 ]
141 )
143 def __repr__(self):
144 descriptor_txt = parse_utils.format_dictionary(self.descriptor_records, 1)
145 # text_txt = parse_utils.format_dictionary(self.text_records, 1)
146 fp_texts = ""
147 for i, fi in enumerate(self.file_pointer_records):
148 fp_texts += f"File pointer {i} : \n" + parse_utils.format_dictionary(fi, 2)
149 fp_texts += "\n"
151 text_texts = parse_utils.format_dictionary(self.text_record, 1)
152 return f"""
153Descriptor:
154{descriptor_txt}
155File pointers : {len(self.file_pointer_records)} records
156{fp_texts}
158Text records:
159{text_texts}
160 """