| 1 | //Compile with g++ -o FixFits fixFits.cpp -O2 -std=c++11
|
|---|
| 2 | //This is a "FITS file fixer" program for FACT.
|
|---|
| 3 | //It goes through the file, relying only on basic header data and compressed blocks headers
|
|---|
| 4 | //It will reconstruct the catalog data too in the output file a strip all corrupt data
|
|---|
| 5 | //The actual header keywords must be edited with the FTOOLS afterwards
|
|---|
| 6 |
|
|---|
| 7 | #include <string>
|
|---|
| 8 | #include <iostream>
|
|---|
| 9 | #include <iomanip>
|
|---|
| 10 | #include <fstream>
|
|---|
| 11 | #include <cstring>
|
|---|
| 12 | #include <vector>
|
|---|
| 13 | #include <algorithm>
|
|---|
| 14 | #include <sstream>
|
|---|
| 15 |
|
|---|
| 16 | #include <boost/filesystem.hpp>
|
|---|
| 17 |
|
|---|
| 18 | #include "factfits.h"
|
|---|
| 19 | #include "Time.h"
|
|---|
| 20 | #include "Configuration.h"
|
|---|
| 21 |
|
|---|
| 22 | using namespace std;
|
|---|
| 23 | using namespace FITS;
|
|---|
| 24 | namespace fs = boost::filesystem;
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 | template<size_t N>
|
|---|
| 28 | void revcpy(char *dest, const char *src, int num)
|
|---|
| 29 | {
|
|---|
| 30 | const char *pend = src + num*N;
|
|---|
| 31 | for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
|
|---|
| 32 | std::reverse_copy(ptr, ptr+N, dest);
|
|---|
| 33 | }
|
|---|
| 34 |
|
|---|
| 35 | bool update_header_key(char buffer[], const string& keyword, uint64_t value, const string& comment)
|
|---|
| 36 | {
|
|---|
| 37 | ostringstream str;
|
|---|
| 38 | str << value;
|
|---|
| 39 |
|
|---|
| 40 | const auto num_length = str.str().size();
|
|---|
| 41 | str.str("");
|
|---|
| 42 |
|
|---|
| 43 | str << setfill(' ');
|
|---|
| 44 | str << left << setw(8) << keyword;
|
|---|
| 45 |
|
|---|
| 46 | str << "= ";
|
|---|
| 47 |
|
|---|
| 48 | str << right << setw(20) << value << " / " << comment;
|
|---|
| 49 |
|
|---|
| 50 | str << setw(80-str.str().size()) << ' ';
|
|---|
| 51 |
|
|---|
| 52 | cout << keyword.size() << ":" << num_length << ":" << str.str().size() << ":" << str.str() << '\n';
|
|---|
| 53 |
|
|---|
| 54 | if (str.str().size() != 80)
|
|---|
| 55 | {
|
|---|
| 56 | cerr << "Wrong " << keyword << " string size." << endl;
|
|---|
| 57 | return false;
|
|---|
| 58 | }
|
|---|
| 59 |
|
|---|
| 60 | memcpy(buffer, str.str().c_str(), 80);
|
|---|
| 61 |
|
|---|
| 62 | return true;
|
|---|
| 63 | }
|
|---|
| 64 |
|
|---|
| 65 | void SetupConfiguration(Configuration &conf)
|
|---|
| 66 | {
|
|---|
| 67 | po::options_description control("Root to SQL");
|
|---|
| 68 | control.add_options()
|
|---|
| 69 | ("file", var<string>()->required(), "Input file name. Fits file to be repaired.")
|
|---|
| 70 | ("out,o", var<string>(), "Output file name (+'.repaired' if empty), dry-run if not provided")
|
|---|
| 71 | ("no-progress", po_switch(), "Suppress progress output")
|
|---|
| 72 | ("dry-run", po_switch(), "Do not write any output")
|
|---|
| 73 | ;
|
|---|
| 74 |
|
|---|
| 75 | po::positional_options_description p;
|
|---|
| 76 | p.add("file", 1); // All positional options
|
|---|
| 77 | p.add("out", 1); // All positional options
|
|---|
| 78 |
|
|---|
| 79 | conf.AddOptions(control);
|
|---|
| 80 | conf.SetArgumentPositions(p);
|
|---|
| 81 | }
|
|---|
| 82 |
|
|---|
| 83 | void PrintUsage()
|
|---|
| 84 | {
|
|---|
| 85 | cout <<
|
|---|
| 86 | "fixfits - Fix the header of a none closed raw-data file\n"
|
|---|
| 87 | "\n"
|
|---|
| 88 | "The goal of this tool is to touch the data as less as possible. "
|
|---|
| 89 | "This, however, might result in a few more bytes being lost than "
|
|---|
| 90 | "strictly necessary.\n"
|
|---|
| 91 | "\n"
|
|---|
| 92 | "Usage: fixfits input-file-name [output-file-name]\n"
|
|---|
| 93 | "\n"
|
|---|
| 94 | ;
|
|---|
| 95 | cout << endl;
|
|---|
| 96 | }
|
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 | int main(int argc, const char* argv[])
|
|---|
| 100 | {
|
|---|
| 101 | Configuration conf(argv[0]);
|
|---|
| 102 | conf.SetPrintUsage(PrintUsage);
|
|---|
| 103 | SetupConfiguration(conf);
|
|---|
| 104 |
|
|---|
| 105 | if (!conf.DoParse(argc, argv))
|
|---|
| 106 | return 127;
|
|---|
| 107 |
|
|---|
| 108 | // ----------------------------- Evaluate options --------------------------
|
|---|
| 109 | const string input_name = conf.Get<string>("file");
|
|---|
| 110 | const string output_name = conf.Has("out") ? conf.Get<string>("out") :
|
|---|
| 111 | (input_name+".repaired");
|
|---|
| 112 |
|
|---|
| 113 | const bool no_progress = conf.Get<bool>("no-progress");
|
|---|
| 114 | const bool dry_run = conf.Get<bool>("dry-run");
|
|---|
| 115 |
|
|---|
| 116 | cout << "\nReading: " << input_name << endl;
|
|---|
| 117 |
|
|---|
| 118 | Time start_read;
|
|---|
| 119 |
|
|---|
| 120 | ifstream input(input_name.c_str(), ios_base::binary);
|
|---|
| 121 | if (!input)
|
|---|
| 122 | {
|
|---|
| 123 | cerr << "Error opening file: " << strerror(errno) << endl;
|
|---|
| 124 | return 6;
|
|---|
| 125 | }
|
|---|
| 126 |
|
|---|
| 127 | cout << "Seeking beginning of data table." << endl;
|
|---|
| 128 |
|
|---|
| 129 | // ------------------------------------------------------------
|
|---|
| 130 |
|
|---|
| 131 | //first off, find the beginning of the data table
|
|---|
| 132 | char buffer[2048];
|
|---|
| 133 | buffer[80] = '\0';
|
|---|
| 134 |
|
|---|
| 135 | size_t counter = 0;
|
|---|
| 136 | size_t num_bytes = 80;
|
|---|
| 137 | input.read(buffer, 80);
|
|---|
| 138 |
|
|---|
| 139 | while (counter != 2)
|
|---|
| 140 | {
|
|---|
| 141 | if (!strcmp(buffer, "XTENSION= 'BINTABLE' / binary table extension "))
|
|---|
| 142 | counter++;
|
|---|
| 143 |
|
|---|
| 144 | if (input.eof())
|
|---|
| 145 | {
|
|---|
| 146 | cerr << "Reached end-of-file but could not find start of data table." << endl;
|
|---|
| 147 | return 2;
|
|---|
| 148 | }
|
|---|
| 149 |
|
|---|
| 150 | input.read(buffer, 80);
|
|---|
| 151 | num_bytes+=80;
|
|---|
| 152 |
|
|---|
| 153 | if (!no_progress)
|
|---|
| 154 | cout << "\rByte " << num_bytes << " ";
|
|---|
| 155 | }
|
|---|
| 156 | if (no_progress)
|
|---|
| 157 | cout << "Reached " << num_bytes << '\n';
|
|---|
| 158 | cout << "\nFound beginning of data table." << endl;
|
|---|
| 159 |
|
|---|
| 160 | // ------------------------------------------------------------
|
|---|
| 161 |
|
|---|
| 162 | //we just read the start of the data table. continue until the end of the table header
|
|---|
| 163 | while (strcmp(buffer, "END "))
|
|---|
| 164 | {
|
|---|
| 165 | if (input.eof())
|
|---|
| 166 | {
|
|---|
| 167 | cerr << "Data table header was not closed properly. Aborting." << endl;
|
|---|
| 168 | return 3;
|
|---|
| 169 | }
|
|---|
| 170 |
|
|---|
| 171 | input.read(buffer, 80);
|
|---|
| 172 | num_bytes+=80;
|
|---|
| 173 |
|
|---|
| 174 | if (!no_progress)
|
|---|
| 175 | cout << "\rByte " << num_bytes << " ";
|
|---|
| 176 | }
|
|---|
| 177 | if (no_progress)
|
|---|
| 178 | cout << "Reached " << num_bytes << '\n';
|
|---|
| 179 |
|
|---|
| 180 | cout << "\nReached end of data table header" << endl;
|
|---|
| 181 |
|
|---|
| 182 | // ------------------------------------------------------------
|
|---|
| 183 |
|
|---|
| 184 | //now skip the fits padding
|
|---|
| 185 | while (num_bytes % 2880 != 0)
|
|---|
| 186 | {
|
|---|
| 187 | input.read(buffer, 80);
|
|---|
| 188 | num_bytes+=80;
|
|---|
| 189 |
|
|---|
| 190 | if (!no_progress)
|
|---|
| 191 | cout << "\rByte " << num_bytes << " ";
|
|---|
| 192 | }
|
|---|
| 193 | if (no_progress)
|
|---|
| 194 | cout << "Reached " << num_bytes << '\n';
|
|---|
| 195 |
|
|---|
| 196 |
|
|---|
| 197 | const size_t output_catalog_start = input.tellg();
|
|---|
| 198 |
|
|---|
| 199 | //now we are in the catalog. skip it until we find the string 'TILE'
|
|---|
| 200 | buffer[4] = '\0';
|
|---|
| 201 | while (strcmp(buffer, "TILE"))
|
|---|
| 202 | {
|
|---|
| 203 | input.read(buffer, 4);
|
|---|
| 204 | num_bytes += 4;
|
|---|
| 205 |
|
|---|
| 206 | if (!no_progress)
|
|---|
| 207 | cout << "\rByte " << num_bytes << " ";
|
|---|
| 208 | }
|
|---|
| 209 | if (no_progress)
|
|---|
| 210 | cout << "Reached " << num_bytes << '\n';
|
|---|
| 211 |
|
|---|
| 212 | input.seekg(num_bytes-4);
|
|---|
| 213 | cout << "\nFound start of first compressed tile." << endl;
|
|---|
| 214 |
|
|---|
| 215 | // ------------------------------------------------------------
|
|---|
| 216 |
|
|---|
| 217 | const size_t output_heap_start = input.tellg();
|
|---|
| 218 |
|
|---|
| 219 | size_t byte_where_tile_start = input.tellg();
|
|---|
| 220 |
|
|---|
| 221 | //now figure out how many blocks are in each tile
|
|---|
| 222 | TileHeader tile_head;
|
|---|
| 223 | BlockHeader block_head;
|
|---|
| 224 |
|
|---|
| 225 | input.read(reinterpret_cast<char*>(&tile_head), sizeof(TileHeader));
|
|---|
| 226 |
|
|---|
| 227 | cout << "First tile is " << tile_head.size << " bytes long." << endl;
|
|---|
| 228 |
|
|---|
| 229 | // ------------------------------------------------------------
|
|---|
| 230 |
|
|---|
| 231 | size_t block_bytes = 0;
|
|---|
| 232 | size_t num_blocks = 0;
|
|---|
| 233 |
|
|---|
| 234 | while (size_t(input.tellg()) < byte_where_tile_start+tile_head.size)
|
|---|
| 235 | {
|
|---|
| 236 | input.read(reinterpret_cast<char*>(&block_head), sizeof(BlockHeader));
|
|---|
| 237 | block_bytes += block_head.size;
|
|---|
| 238 |
|
|---|
| 239 | input.seekg(byte_where_tile_start + sizeof(TileHeader) + block_bytes);
|
|---|
| 240 | num_blocks ++;
|
|---|
| 241 |
|
|---|
| 242 | if (input.eof())
|
|---|
| 243 | {
|
|---|
| 244 | cerr << "First tile seems broken unable to recover anything." << endl;
|
|---|
| 245 | return 4;
|
|---|
| 246 | }
|
|---|
| 247 | }
|
|---|
| 248 |
|
|---|
| 249 | if (size_t(input.tellg()) != byte_where_tile_start+tile_head.size)
|
|---|
| 250 | {
|
|---|
| 251 | cerr << "Discrepancy between tile size and sum of blocks size." << endl;
|
|---|
| 252 | return 1;
|
|---|
| 253 | }
|
|---|
| 254 |
|
|---|
| 255 | cout << "There are " << num_blocks << " blocks in each tile.\nLooping over all tiles" << endl;
|
|---|
| 256 |
|
|---|
| 257 | // ------------------------------------------------------------
|
|---|
| 258 |
|
|---|
| 259 | size_t num_tiles = 0;
|
|---|
| 260 | input.seekg(output_heap_start);
|
|---|
| 261 |
|
|---|
| 262 | size_t output_heap_end = input.tellg();
|
|---|
| 263 | size_t previous_heap_end = input.tellg();
|
|---|
| 264 |
|
|---|
| 265 | vector<vector<pair<int64_t, int64_t> > > catalog;
|
|---|
| 266 |
|
|---|
| 267 | uint64_t offset_in_heap = 0;
|
|---|
| 268 | while (!input.eof())
|
|---|
| 269 | {
|
|---|
| 270 | previous_heap_end = output_heap_end;
|
|---|
| 271 | output_heap_end = input.tellg();
|
|---|
| 272 |
|
|---|
| 273 | byte_where_tile_start = input.tellg();
|
|---|
| 274 | block_bytes = 0;
|
|---|
| 275 |
|
|---|
| 276 | if (input.peek() == EOF)
|
|---|
| 277 | {
|
|---|
| 278 | cout << "Reached end-of-file." << endl;
|
|---|
| 279 | break;
|
|---|
| 280 | }
|
|---|
| 281 |
|
|---|
| 282 | input.read(reinterpret_cast<char*>(&tile_head), sizeof(TileHeader));
|
|---|
| 283 | if (memcmp(tile_head.id, "TILE", 4) || input.eof())
|
|---|
| 284 | {
|
|---|
| 285 | cout << "Reached end-of-table padding or end-of-file." << endl;
|
|---|
| 286 | break;
|
|---|
| 287 | }
|
|---|
| 288 |
|
|---|
| 289 | offset_in_heap += sizeof(TileHeader);
|
|---|
| 290 | catalog.emplace_back();
|
|---|
| 291 |
|
|---|
| 292 | for (size_t i=0; i<num_blocks; i++)
|
|---|
| 293 | {
|
|---|
| 294 | input.read((char*)(&block_head), sizeof(BlockHeader));
|
|---|
| 295 | if (input.eof())
|
|---|
| 296 | {
|
|---|
| 297 | cout << "Reached end-of-file." << endl;
|
|---|
| 298 | break;
|
|---|
| 299 | }
|
|---|
| 300 | block_bytes += block_head.size;
|
|---|
| 301 | input.seekg(byte_where_tile_start + sizeof(TileHeader) + block_bytes);
|
|---|
| 302 | if (input.eof())
|
|---|
| 303 | {
|
|---|
| 304 | cout << "Reached end-of-file." << endl;
|
|---|
| 305 | break;
|
|---|
| 306 | }
|
|---|
| 307 | catalog.back().emplace_back((int64_t)(block_head.size),offset_in_heap);
|
|---|
| 308 | offset_in_heap += block_head.size;
|
|---|
| 309 | }
|
|---|
| 310 |
|
|---|
| 311 | //one last catalog entry for the column that has no data
|
|---|
| 312 | catalog.back().emplace_back(0,0);
|
|---|
| 313 |
|
|---|
| 314 | if (!no_progress)
|
|---|
| 315 | cout << "\rByte " << input.tellg() << " ";
|
|---|
| 316 | num_tiles++;
|
|---|
| 317 | }
|
|---|
| 318 |
|
|---|
| 319 | input.clear();
|
|---|
| 320 |
|
|---|
| 321 | // ------------------------------------------------------------
|
|---|
| 322 |
|
|---|
| 323 | //ignore last read tile as we have no idea if it looked ok or not
|
|---|
| 324 | num_tiles--;
|
|---|
| 325 | output_heap_end = previous_heap_end;
|
|---|
| 326 |
|
|---|
| 327 | cout << "Recovery finished!\n";
|
|---|
| 328 |
|
|---|
| 329 | const auto time_read = Time().UnixTime()-start_read.UnixTime();
|
|---|
| 330 |
|
|---|
| 331 | // ============================================================
|
|---|
| 332 | //Now we have everything that we need. Go again through the input file and write the output, fixed file
|
|---|
| 333 |
|
|---|
| 334 | cout << "\nWriting: " << output_name << endl;
|
|---|
| 335 |
|
|---|
| 336 | Time start_write;
|
|---|
| 337 |
|
|---|
| 338 | const uint64_t num_cols = num_blocks+1;//+1 because of not-used drs-time-marker column
|
|---|
| 339 | const uint64_t output_catalog_end = output_catalog_start + num_tiles*num_cols*16;
|
|---|
| 340 |
|
|---|
| 341 | const uint64_t zheapptr = output_heap_start - output_catalog_start;
|
|---|
| 342 | const uint64_t theap = output_catalog_end - output_catalog_start;
|
|---|
| 343 |
|
|---|
| 344 | map<string, size_t> header;
|
|---|
| 345 |
|
|---|
| 346 | if (!dry_run)
|
|---|
| 347 | {
|
|---|
| 348 | ofstream output(output_name.c_str(), ios_base::binary);
|
|---|
| 349 | input.seekg(0);
|
|---|
| 350 |
|
|---|
| 351 | //copy everything until the catalog start and update header values on our way
|
|---|
| 352 | counter = 0;
|
|---|
| 353 | for (uint64_t i=0; i<output_catalog_start; i+=80)
|
|---|
| 354 | {
|
|---|
| 355 | input.read(buffer, 80);
|
|---|
| 356 |
|
|---|
| 357 | if (!strcmp(buffer, "XTENSION= 'BINTABLE' / binary table extension "))
|
|---|
| 358 | counter++;
|
|---|
| 359 |
|
|---|
| 360 | if (counter == 2)
|
|---|
| 361 | {
|
|---|
| 362 | bool rc = true;
|
|---|
| 363 |
|
|---|
| 364 | if (!memcmp(buffer, "NAXIS2", 6))
|
|---|
| 365 | rc &= update_header_key(buffer, "NAXIS2", num_tiles, "number of rows in table");
|
|---|
| 366 | if (!memcmp(buffer, "ZNAXIS2", 7))
|
|---|
| 367 | rc &= update_header_key(buffer, "ZNAXIS2", num_tiles, "Number of uncompressed rows");
|
|---|
| 368 | if (!memcmp(buffer, "PCOUNT", 6))
|
|---|
| 369 | rc &= update_header_key(buffer, "PCOUNT", output_heap_end - output_catalog_end, "size of special data area");
|
|---|
| 370 | if (!memcmp(buffer, "THEAP", 5))
|
|---|
| 371 | rc &= update_header_key(buffer, "THEAP", theap, "Pointer to heap");
|
|---|
| 372 | if (!memcmp(buffer, "ZHEAPPTR", 8))
|
|---|
| 373 | rc &= update_header_key(buffer, "ZHEAPPTR", zheapptr, "Pointer to data");
|
|---|
| 374 |
|
|---|
| 375 | if (!rc)
|
|---|
| 376 | return 5;
|
|---|
| 377 |
|
|---|
| 378 | header[string(buffer, 8)] = size_t(output.tellp())+10;
|
|---|
| 379 | }
|
|---|
| 380 |
|
|---|
| 381 | output.write(buffer, 80);
|
|---|
| 382 |
|
|---|
| 383 | if (!no_progress)
|
|---|
| 384 | cout << "\rByte " << input.tellg() << " ";
|
|---|
| 385 | }
|
|---|
| 386 |
|
|---|
| 387 | if (no_progress)
|
|---|
| 388 | cout << "Reached " << input.tellg() << '\n';
|
|---|
| 389 |
|
|---|
| 390 | // ------------------------------------------------------------
|
|---|
| 391 |
|
|---|
| 392 | // now write the updated catalog
|
|---|
| 393 | const uint64_t reserved_num_tiles = zheapptr / (num_cols*16);
|
|---|
| 394 | const uint32_t one_catalog_row_size = num_cols*16;
|
|---|
| 395 | const uint32_t total_catalog_size = reserved_num_tiles*one_catalog_row_size;
|
|---|
| 396 |
|
|---|
| 397 | vector<char> swapped_catalog(total_catalog_size);
|
|---|
| 398 |
|
|---|
| 399 | uint32_t shift = 0;
|
|---|
| 400 | for (auto it=catalog.cbegin(); it!=catalog.cend(); it++)
|
|---|
| 401 | {
|
|---|
| 402 | revcpy<sizeof(int64_t)>(swapped_catalog.data() + shift, (char*)(it->data()), num_cols*2);
|
|---|
| 403 | shift += one_catalog_row_size;
|
|---|
| 404 | }
|
|---|
| 405 |
|
|---|
| 406 | if (num_tiles < reserved_num_tiles)
|
|---|
| 407 | memset(swapped_catalog.data()+shift, 0, total_catalog_size - shift);
|
|---|
| 408 |
|
|---|
| 409 | output.write(swapped_catalog.data(), total_catalog_size);
|
|---|
| 410 |
|
|---|
| 411 | // ------------------------------------------------------------
|
|---|
| 412 |
|
|---|
| 413 | // we are now at the beginning of the heap in the output file. Move there in the input file
|
|---|
| 414 | input.seekg(output_heap_start);
|
|---|
| 415 |
|
|---|
| 416 | uint64_t num_heap_bytes_written = 0;
|
|---|
| 417 | uint64_t total_heap_bytes_to_write = output_heap_end - output_heap_start;
|
|---|
| 418 |
|
|---|
| 419 | cout << "\nCatalog updated.\nCopying " << total_heap_bytes_to_write << " of data now." << endl;
|
|---|
| 420 |
|
|---|
| 421 | while (num_heap_bytes_written != total_heap_bytes_to_write)
|
|---|
| 422 | {
|
|---|
| 423 | uint64_t bytes_to_write = 2048;
|
|---|
| 424 | if (total_heap_bytes_to_write - num_heap_bytes_written < 2048)
|
|---|
| 425 | bytes_to_write = total_heap_bytes_to_write - num_heap_bytes_written;
|
|---|
| 426 |
|
|---|
| 427 | input.read(buffer, bytes_to_write);
|
|---|
| 428 | output.write(buffer, bytes_to_write);
|
|---|
| 429 | num_heap_bytes_written += bytes_to_write;
|
|---|
| 430 |
|
|---|
| 431 | if (!no_progress)
|
|---|
| 432 | cout << "\rByte " << input.tellg() << " ";
|
|---|
| 433 | }
|
|---|
| 434 | if (no_progress)
|
|---|
| 435 | cout << "Reached " << input.tellg() << '\n';
|
|---|
| 436 |
|
|---|
| 437 | cout << "\nData written. Adding FITS padding. " << endl;
|
|---|
| 438 |
|
|---|
| 439 | // ------------------------------------------------------------
|
|---|
| 440 |
|
|---|
| 441 | //now add the FITS padding at the end
|
|---|
| 442 | while (output.tellp() % 2880 != 0)
|
|---|
| 443 | output.write("\0", 1);
|
|---|
| 444 | }
|
|---|
| 445 | else
|
|---|
| 446 | cout << " ... skipped ...\n";
|
|---|
| 447 |
|
|---|
| 448 | const auto time_write = Time().UnixTime()-start_write.UnixTime();
|
|---|
| 449 |
|
|---|
| 450 | cout << "File recovered!\n";
|
|---|
| 451 |
|
|---|
| 452 | // ------------------------------------------------------------
|
|---|
| 453 |
|
|---|
| 454 | cout << "\nValid num tiles : " << setw(12) << num_tiles;
|
|---|
| 455 | cout << "\nNAXIS2 : " << setw(12) << num_tiles;
|
|---|
| 456 | cout << "\nZNAXIS2 : " << setw(12) << num_tiles;
|
|---|
| 457 | cout << "\nCatalog start : " << setw(12) << output_catalog_start;
|
|---|
| 458 | cout << "\nCatalog end : " << setw(12) << output_catalog_end;
|
|---|
| 459 | cout << "\nZHEAPPTR : " << setw(12) << zheapptr;
|
|---|
| 460 | cout << "\nTHEAP : " << setw(12) << theap;
|
|---|
| 461 | cout << "\nHeap start : " << setw(12) << output_heap_start;
|
|---|
| 462 | cout << "\nHeap end : " << setw(12) << output_heap_end;
|
|---|
| 463 | cout << "\nPCOUNT : " << setw(12) << output_heap_end - output_catalog_end;
|
|---|
| 464 | cout << '\n';
|
|---|
| 465 | cout << "\nInput file size : " << setw(12) << fs::file_size(input_name);
|
|---|
| 466 | if (!dry_run)
|
|---|
| 467 | {
|
|---|
| 468 | cout << "\nOutput file size : " << setw(12) << fs::file_size(output_name);
|
|---|
| 469 | cout << "\nLost bytes : " << setw(12) << fs::file_size(input_name)-fs::file_size(output_name);
|
|---|
| 470 | cout << "\nLost fraction : " << setw(12) << 1-double(fs::file_size(output_name))/fs::file_size(input_name);
|
|---|
| 471 | }
|
|---|
| 472 | cout << "\n";
|
|---|
| 473 |
|
|---|
| 474 | cout << "\nExecution [read] : " << time_read << "s, " << fs::file_size(input_name)/1024./1024/time_read << "Mb/s";
|
|---|
| 475 | cout << "\nExecution [write] : " << time_write << "s, " << fs::file_size(output_name)/1024./1024/time_write << "Mb/s";
|
|---|
| 476 |
|
|---|
| 477 | if (0)
|
|---|
| 478 | return 0;
|
|---|
| 479 |
|
|---|
| 480 | factfits fits(output_name);
|
|---|
| 481 |
|
|---|
| 482 | cout << "\nNew file contains " << fits.GetNumRows() << " events.";
|
|---|
| 483 | cout << "\nChecking for raw data contents." << endl;
|
|---|
| 484 |
|
|---|
| 485 | if (fits.GetStr("TELESCOP")!="FACT" || fits.GetStr("ORIGIN")!="FACT" || fits.GetStr("PACKAGE")!="FACT++" || fits.GetStr("EXTNAME")!="Events" || !fits.HasKey("DRSCALIB"))
|
|---|
| 486 | {
|
|---|
| 487 | cerr << "Header incomplete." << endl;
|
|---|
| 488 | return 0;
|
|---|
| 489 | }
|
|---|
| 490 |
|
|---|
| 491 | if (!fits.HasColumn("UnixTimeUTC"))
|
|---|
| 492 | {
|
|---|
| 493 | cerr << "Column UnixTimeUTC missing." << endl;
|
|---|
| 494 | return 0;
|
|---|
| 495 | }
|
|---|
| 496 |
|
|---|
| 497 | cout << "\nRaw data file detected.";
|
|---|
| 498 | cout << "\nUpdating run-end with last event time." << endl;
|
|---|
| 499 |
|
|---|
| 500 | vector<uint32_t> utime(2);
|
|---|
| 501 | fits.SetVecAddress("UnixTimeUTC", utime);
|
|---|
| 502 | fits.GetRow(fits.GetNumRows()-1);
|
|---|
| 503 |
|
|---|
| 504 | const Time stop(utime[0], utime[1]);
|
|---|
| 505 |
|
|---|
| 506 | const uint32_t tstopi = floor(stop.UnixDate());
|
|---|
| 507 | const double tstopf = fmod(stop.UnixDate(), 1);
|
|---|
| 508 |
|
|---|
| 509 | fits.close();
|
|---|
| 510 |
|
|---|
| 511 | cout << setfill(' ');
|
|---|
| 512 | cout << "\nTSTOPI = " << right << setw(20) << tstopi << " / Time when last event received (integral part)";
|
|---|
| 513 | cout << "\nTSTOPF = " << right << setw(20) << tstopf << " / Time when last event received (fractional part)";
|
|---|
| 514 | cout << "\nDATE-END= '" << stop.Iso() << "' / Time when last event received";
|
|---|
| 515 |
|
|---|
| 516 | fstream fout(output_name);//, ios::binary);
|
|---|
| 517 | fout << setfill(' ');
|
|---|
| 518 |
|
|---|
| 519 | fout.seekp(header["DATE-END"], ios::beg);
|
|---|
| 520 | //fout.seekg(header["DATE-END"], ios::beg);
|
|---|
| 521 | fout << left << setw(20) << string("'" + stop.Iso() + "'") << " / Time when last event received";
|
|---|
| 522 |
|
|---|
| 523 | fout.seekp(header["TSTOPI "], ios::beg);
|
|---|
| 524 | //fout.seekg(header["TSTOPI "], ios::beg);
|
|---|
| 525 | fout << right << setw(20) << tstopi;
|
|---|
| 526 |
|
|---|
| 527 | fout.seekp(header["TSTOPF "], ios::beg);
|
|---|
| 528 | //fout.seekg(header["TSTOPF "], ios::beg);
|
|---|
| 529 | fout << right << setw(20) << tstopf;
|
|---|
| 530 | fout.flush();
|
|---|
| 531 |
|
|---|
| 532 | cout << "\nUpdating checksum." << endl;
|
|---|
| 533 |
|
|---|
| 534 | factfits fits2(output_name);
|
|---|
| 535 | fout.seekp(header["CHECKSUM"], ios::beg);
|
|---|
| 536 | //fout.seekg(header["CHECKSUM"], ios::beg);
|
|---|
| 537 | fout << left << setw(20) << string("'" + fits2.GetChecksum().str() + "'");
|
|---|
| 538 |
|
|---|
| 539 | fout.close();
|
|---|
| 540 | fits2.close();
|
|---|
| 541 |
|
|---|
| 542 | factfits fits3(output_name);
|
|---|
| 543 | if (!fits3.IsHeaderOk() || !fits3.IsFileOk())
|
|---|
| 544 | {
|
|---|
| 545 | cerr << "\nFAILED: The checksum is still invalid! :(" << endl;
|
|---|
| 546 | return 7;
|
|---|
| 547 | }
|
|---|
| 548 |
|
|---|
| 549 | cout << "\nFile header successfully updated!\n" << endl;
|
|---|
| 550 |
|
|---|
| 551 | return 0;
|
|---|
| 552 |
|
|---|
| 553 | }
|
|---|