12 #include <fmt/format.h>
19 std::vector<LiteralKeyword> ReadCurrentHduKeywords(fitsfile* ptr) {
24 if (fits_get_hdrspace(ptr, &count, &more_space, &status) != 0) {
25 throw CfitsioError(status,
"Failed to get number of keywords in HDU");
27 std::vector<LiteralKeyword> keywords;
28 keywords.reserve(count);
29 for (
int keynum = 1; keynum <= count; ++keynum) {
31 char record[FLEN_CARD];
32 if (fits_read_record(ptr, keynum, &record[0], &status) != 0) {
33 throw CfitsioError(status, fmt::format(
"Failed to read record number {}", keynum));
36 keywords.emplace_back(std::string_view(record));
40 fmt::format(
"Failed to read recordd number {} as literal keyword", keynum)));
46 std::string FitsErrorMessage(
int status) {
47 char msg[FLEN_STATUS];
48 fits_get_errstatus(status, &msg[0]);
49 return std::string(msg);
59 : m_memory(std::make_unique<FitsMemory>(initial_buffer_size))
61 fitsfile* ptr =
nullptr;
63 fits_create_memfile(&ptr, &m_memory->buffer, &m_memory->size, 0u, realloc, &status);
68 MemoryFitsFile::FitsMemory::FitsMemory(
size_t initial_size) {
70 buffer = malloc(size);
71 memset(buffer, 0u, size);
74 MemoryFitsFile::FitsMemory::~FitsMemory() noexcept {
76 fits_free_memory(buffer, &status);
80 : std::runtime_error(fmt::format(
"{}: {}", message, FitsErrorMessage(status)).c_str())
85 : std::runtime_error(fmt::format(
"{}: {}", message, FitsErrorMessage(status)).c_str())
93 (void)fits_movabs_hdu(ptr, hdu_num, &type, &status);
96 fmt::format(
"HDU with number {} could not be selected", hdu_num));
101 if (ptr ==
nullptr) {
105 fits_close_file(ptr, &status);
115 (void)fits_get_num_hdus(ptr, &num_hdus, &status);
117 throw CfitsioError(HEADER_NOT_EMPTY,
"Cannot safely initialize an non-empty FITS file");
119 (void)fits_create_hdu(ptr, &status);
138 (void)fits_get_num_hdus(ptr, &num_hdus, &status);
140 throw CfitsioError(HEADER_NOT_EMPTY,
"Cannot safely initialize an non-empty FITS file");
142 (void)fits_create_hdu(ptr, &status);
143 (void)fits_write_key(
144 ptr, TLOGICAL,
"SIMPLE", &simple,
"file does conform to FITS standard", &status);
145 (void)fits_write_key(ptr, TBYTE,
"BITPIX", &bitpix,
"number of bits per data pixel", &status);
146 (void)fits_write_key(
147 ptr, TBYTE,
"NAXIS", &naxis,
"file provides primary HDU keywords only", &status);
148 (void)fits_write_key(
149 ptr, TLOGICAL,
"EXTEND", &extend,
"FITS Extension may be present", &status);
152 fits_get_errstatus(status, &err_text[0]);
154 throw CfitsioError(status, fmt::format(
"failed to initialize primary HDU: {}", err_text));
159 fitsfile* ptr =
nullptr;
161 fits_create_diskfile(&ptr,
const_cast<char*
>(filename), &status);
162 if (status != 0 || ptr ==
nullptr) {
163 throw CfitsioError(status, fmt::format(
"failed to create FITS file '{}'", filename));
169 fitsfile* ptr =
nullptr;
171 fits_open_diskfile(&ptr,
172 const_cast<char*
>(filename),
175 if (status != 0 || ptr ==
nullptr) {
176 throw CfitsioError(status, fmt::format(
"failed to open FITS file '{}'", filename));
184 return ReadCurrentHduKeywords(ptr);
187 std::vector<LiteralKeyword>
192 std::string null_terminated_name(name);
193 (void)fits_movnam_hdu(ptr,
194 static_cast<int>(type),
195 const_cast<char*
>(null_terminated_name.c_str()),
201 fmt::format(
"HDU with type {}, name '{}' and version {} could not be selected",
206 return ReadCurrentHduKeywords(ptr);
214 int num_current_keys = 0;
219 fits_get_hdrspace(ptr, &num_current_keys,
nullptr, &status);
220 for (
int keynum = num_current_keys; keynum > 0; --keynum) {
221 fits_delete_record(ptr, keynum, &status);
224 fmt::format(
"failed to delete keyword record index {}", keynum));
229 void MakeHduSpace(fitsfile* ptr,
int hdu_num,
size_t additional_keys) {
234 int num_current_keys = 0;
235 int more_keys = additional_keys;
241 fits_get_hdrspace(ptr, &num_current_keys, &more_keys, &status);
243 throw CfitsioError(status, fmt::format(
"Failed to update header space"));
249 std::vector<LiteralKeyword>
const& keywords,
250 std::optional<ssize_t>* remaining_size) {
253 std::string null_terminated_record;
254 null_terminated_record.reserve(FLEN_CARD);
256 int num_current_keys = 0;
257 int more_keys = keywords.size();
262 fits_get_hdrspace(ptr, &num_current_keys, &more_keys, &status);
264 throw CfitsioError(status, fmt::format(
"Failed to get header space"));
267 if (remaining_size !=
nullptr && more_keys != -1) {
268 *remaining_size = more_keys - keywords.size();
271 for (
auto const& kw : keywords) {
272 null_terminated_record.assign(kw.GetRecord());
274 fits_write_record(ptr, null_terminated_record.c_str(), &status);
278 fmt::format(
"Failed to write keyword record: \"{}\"", null_terminated_record));
287 fits_write_chksum(ptr, &status);
290 status, fmt::format(
"Failed to write checksum keywords to HDU number {}", hdu_num));