/* -*- Mode: C++ ; Coding: euc-japan -*- */
/* Time-stamp: <2014-05-08 03:14:18 cyamauch> */
/**
* @file fits_header.cc
* @brief FITS ヘッダ全体を表現するクラス fits_header のコード
*/
#define CLASS_NAME "fits_header"
#include "config.h"
#include "fits_header.h"
#include "fits_hdu.h"
#include "private/err_report.h"
#include "private/rm_side_spaces.h"
#include "private/c_memcpy.h"
namespace sli
{
static const tstring END = "END";
#include "private/parse_a_header_record.h"
#include "private/initialize_csum.h"
#include "private/encode_csum.h"
#include "private/write_stream_or_get_csum.h"
/**
* @brief システム側で書いてしまう予約キーワード
*
* @note 予約キーワードに '.' が入るとややこしい事になるので入れない事.
* ('HOGE DEATH' のようなキーワードが指定された時,fits_header_record
* では ' ' を '.' に置き換えるため)
*/
static const char *Header_reserved_keys[] = {
"SIMPLE",
"BITPIX","NAXIS","EXTEND", "XTENSION",
"PCOUNT","GCOUNT","TFIELDS","TXFLDKWD","EXTNAME","EXTVER","EXTLEVEL",
"BSCALE","BZERO",
#ifdef BUNIT_IS_SPECIAL
"BUNIT",
#endif
"BLANK", "THEAP",
#ifdef FMTTYPE_IS_SPECIAL
"FMTTYPE","FTYPEVER",
#endif
NULL };
/**
* @brief システム側で書いてしまう予約キーワード (末尾に数字がつくもの)
*/
static const char *Header_reserved_keys_with_digit[] = {
"NAXIS",
"TTYPE","TUNIT","TDISP","TBCOL","TFORM","TDIM",
"TNULL","TZERO","TSCAL",
"TELEM","TALAS",
NULL };
/**
* @brief システム側で予約しているキーワードかどうかを判定 (内部用)
*
* @note private な関数です.
*/
static bool is_header_reserved_key( const char *keyword )
{
int j;
const char **reserved_keys;
tstring keywd;
if ( keyword == NULL ) return false;
keywd.assign(keyword).strtrim();
if ( keywd.length() == 0 ) return false;
/* SIMPLE とかをチェックする */
reserved_keys = Header_reserved_keys;
for ( j=0 ; reserved_keys[j] != NULL ; j++ ) {
if ( keywd.strcmp(reserved_keys[j]) == 0 ) break;
}
if ( reserved_keys[j] != NULL ) return true;
/* TTYPE99 とかをチェックする */
reserved_keys = Header_reserved_keys_with_digit;
for ( j=0 ; reserved_keys[j] != NULL ; j++ ) {
tstring rkeys;
size_t len_reserved;
len_reserved = rkeys.assign(reserved_keys[j]).length();
/* reserved_keys[j] に続く数字がない場合は,reserved としない */
if ( len_reserved < keywd.length() ) {
if ( keywd.strncmp(reserved_keys[j], len_reserved) == 0 ) {
size_t p0 = len_reserved;
if ( keywd.strpbrk(p0, "[0-9]") == (ssize_t)p0 ) {
p0 += keywd.strspn(p0, "[0-9]");
/* 最後までいってたら… */
if ( p0 == keywd.length() ) break;
}
}
}
}
if ( reserved_keys[j] != NULL ) return true;
return false;
}
/* constructor */
/**
* @brief コンストラクタ
*/
fits_header::fits_header()
{
this->num_records_rec = 0;
this->records_rec.init(sizeof(fits_header_record *), true);
this->records_rec.register_extptr(&this->records_ptr_rec); /* [void **] */
c_memcpy(this->encoded_chksum_rec,"0000000000000000",17);
this->sysrecords_prohibition_rec = false;
this->suppress_dupkey_warning_rec = false;
this->manager = NULL;
this->shallow_copy_ok = false;
this->shallow_copy_dest_obj = NULL;
this->shallow_copy_src_obj = NULL;
this->__copying = false;
return;
}
/* copy constructor */
/**
* @brief コピーコンストラクタ
*/
fits_header::fits_header(const fits_header &obj)
{
this->num_records_rec = 0;
this->records_rec.init(sizeof(fits_header_record *), true);
this->records_rec.register_extptr(&this->records_ptr_rec); /* [void **] */
c_memcpy(this->encoded_chksum_rec,"0000000000000000",17);
this->sysrecords_prohibition_rec = false;
this->suppress_dupkey_warning_rec = false;
this->manager = NULL;
this->shallow_copy_ok = false;
this->shallow_copy_dest_obj = NULL;
this->shallow_copy_src_obj = NULL;
this->__copying = false;
this->init(obj);
return;
}
/* destructor */
/**
* @brief デストラクタ
*/
fits_header::~fits_header()
{
if ( this->records_ptr_rec != NULL ) {
long i;
for ( i=0 ; i < this->num_records_rec ; i++ ) {
if ( this->records_ptr_rec[i] != NULL ) {
delete this->records_ptr_rec[i];
}
}
}
return;
}
/**
* @brief オブジェクトのコピー
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)を持つレコードはコピーされません.
*/
fits_header &fits_header::operator=(const fits_header &obj)
{
return this->init(obj);
}
/* 注意: このクラスからの this->manager->setup_sys_header() の呼び出しは */
/* 1メンバ関数につき,1度限りとなるようにしなければならない. */
/* 2回呼び出すようになっていると,無限ループに陥いる. */
/* protected */
/**
* @brief オブジェクトの初期化 (低レベル)
*
* @note これは,this->manager->setup_sys_header() を呼び出さない.
* このクラスから init() を使いたい場合に使う.
* このメンバ関数は protected です.
*/
fits_header &fits_header::_init()
{
//err_report(__FUNCTION__,"DEBUG","this is fits_header::_init()");
/* clear! */
if ( this->records_ptr_rec != NULL ) {
long i;
for ( i=0 ; i < this->num_records_rec ; i++ ) {
if ( this->records_ptr_rec[i] != NULL ) {
delete this->records_ptr_rec[i];
}
}
this->records_rec.init(sizeof(fits_header_record *), true);
}
this->num_records_rec = 0;
c_memcpy(this->encoded_chksum_rec,"0000000000000000",17);
this->suppress_dupkey_warning_rec = false;
this->index_rec.init();
this->formatted_rec.init();
return *this;
}
/**
* @brief オブジェクトの初期化
*/
fits_header &fits_header::init()
{
//err_report(__FUNCTION__,"DEBUG","this is fits_header::init()");
this->fits_header::_init();
/* 消去されても Data Unit に関連するレコードはすぐに復活させる */
if ( this->sysrecords_prohibition_rec == true && this->manager != NULL ) {
/* this will call an overridden function */
//err_report(__FUNCTION__,"DEBUG","called ...... from [A]");
this->manager->setup_sys_header();
}
return *this;
}
/**
* @brief オブジェクトのコピー
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)を持つレコードはコピーされません.
*/
fits_header &fits_header::init(const fits_header &obj)
{
if ( &obj == this ) return *this;
//err_report(__FUNCTION__,"DEBUG","this is fits_header::init(...)");
this->fits_header::_init();
if ( obj.records_ptr_rec != NULL ) {
long i;
try {
this->records_rec.resize( obj.num_records_rec + 1 ).clean();
}
catch (...) {
err_throw(__FUNCTION__,"FATAL","records_rec.resize() failed");
}
try {
for ( i=0 ; i < obj.num_records_rec ; i++ ) {
this->records_ptr_rec[i] = new fits_header_record;
/* これでうまくいくのか??? */
*(this->records_ptr_rec[i]) = (*(obj.records_ptr_rec[i]));
this->records_ptr_rec[i]->register_manager(this);
}
this->records_ptr_rec[i] = NULL;
}
catch (...) {
for ( i=0 ; i < obj.num_records_rec ; i++ ) {
if ( this->records_ptr_rec[i] != NULL ) delete this->records_ptr_rec[i];
}
this->records_rec.init(sizeof(fits_header_record *), true);
err_throw(__FUNCTION__,"FATAL","'new' or '=' failed");
}
this->num_records_rec = obj.num_records_rec;
}
try {
this->index_rec = obj.index_rec;
}
catch (...) {
this->fits_header::_init();
err_throw(__FUNCTION__,"FATAL","'=' failed");
}
this->suppress_dupkey_warning_rec = obj.suppress_dupkey_warning_rec;
/* システムヘッダが禁止されている場合,あれば削除する */
if ( this->sysrecords_prohibition_rec == true ) {
long i;
for ( i = 0 ; i < this->length() ; i++ ) {
if ( this->is_sysrecord(i) == true ) {
//err_report1(__FUNCTION__,"WARNING",
// "keyword '%s' cannot be appended by the user",
// this->record_cs(i).keyword());
this->fits_header::_erase_records(i,1);
i--;
}
}
}
/* 消去されても Data Unit に関連するレコードはすぐに復活させる */
if ( this->sysrecords_prohibition_rec == true && this->manager != NULL ) {
/* this will call an overridden function */
//err_report(__FUNCTION__,"DEBUG","called ...... from [B]");
this->manager->setup_sys_header();
}
//try {
// this->formatted_rec = obj.formatted_rec;
//}
//catch (...) {
// err_throw(__FUNCTION__,"FATAL","'=' failed");
//}
return *this;
}
/**
* @brief オブジェクトの初期化 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::init( const fits::header_def defs[] )
{
this->fits_header::_init();
if ( defs != NULL ) {
this->append_records(defs);
}
/* 消去されても Data Unit に関連するレコードはすぐに復活させる */
if ( this->sysrecords_prohibition_rec == true && this->manager != NULL ) {
/* this will call an overridden function */
//err_report(__FUNCTION__,"DEBUG","called ...... from [C]");
this->manager->setup_sys_header();
}
return *this;
}
/**
* @brief 2つのオブジェクト間での内容のスワップ
*
* 指定されたオブジェクト obj の内容と自身の内容を入れ替えます.
*
* @param obj fits_header クラスのオブジェクト
* @return 自身の参照
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)を持つレコードは入れ替わりません.
*/
/* 注: chksum はここでは扱わない */
fits_header &fits_header::swap( fits_header &obj )
{
long tmp_num_records_rec = obj.num_records_rec;
bool tmp_suppress_dupkey_warning_rec = obj.suppress_dupkey_warning_rec;
if ( &obj == this ) return *this;
obj.num_records_rec = this->num_records_rec;
this->num_records_rec = tmp_num_records_rec;
this->records_rec.swap(obj.records_rec);
this->index_rec.swap(obj.index_rec);
this->formatted_rec.swap(obj.formatted_rec);
obj.suppress_dupkey_warning_rec = this->suppress_dupkey_warning_rec;
this->suppress_dupkey_warning_rec = tmp_suppress_dupkey_warning_rec;
/* システムヘッダが禁止されている場合,あれば削除する */
if ( this->sysrecords_prohibition_rec == true ) {
long i;
for ( i = 0 ; i < this->length() ; i++ ) {
if ( this->is_sysrecord(i) == true ) {
//err_report1(__FUNCTION__,"WARNING",
// "keyword '%s' cannot be appended by the user",
// this->record_cs(i).keyword());
this->fits_header::_erase_records(i,1);
i--;
}
}
}
if ( obj.sysrecords_prohibition_rec == true ) {
long i;
for ( i = 0 ; i < obj.length() ; i++ ) {
if ( obj.is_sysrecord(i) == true ) {
//err_report1(__FUNCTION__,"WARNING",
// "keyword '%s' cannot be appended by the user",
// obj.record_cs(i).keyword());
obj.fits_header::_erase_records(i,1);
i--;
}
}
}
/* 消去されても Data Unit に関連するレコードはすぐに復活させる */
if ( this->sysrecords_prohibition_rec == true && this->manager != NULL ) {
/* this will call an overridden function */
this->manager->setup_sys_header();
}
if ( obj.sysrecords_prohibition_rec == true && obj.manager != NULL ) {
/* this will call an overridden function */
obj.manager->setup_sys_header();
}
return *this;
}
/*
* ファイル入出力 : 読み書きしたバイト数を返す
*/
/**
* @brief ストリームから Header Unit を読み込む
*
* @param sref 読み込み対象のストリーム (cstreamioの継承クラス)
* @param max_bytes_read 読み込まれるべき最大のバイト数
* @return 非負値: 読み込んだバイト数
* 負値: エラー
*/
ssize_t fits_header::read_stream( cstreamio &sref, size_t max_bytes_read )
{
if ( this->sysrecords_prohibition_rec == false ) {
return this->header_load(sref,&max_bytes_read);
}
else {
err_report(__FUNCTION__,"ERROR",
"cannot use this member function.");
return -1;
}
}
/**
* @brief ストリームから Header Unit を読み込む
*
* @param sref 読み込み対象のストリーム (cstreamioの継承クラス)
* @return 非負値: 読み込んだバイト数
* 負値: エラー
*/
ssize_t fits_header::read_stream( cstreamio &sref )
{
if ( this->sysrecords_prohibition_rec == false ) {
return this->header_load(sref,NULL);
}
else {
err_report(__FUNCTION__,"ERROR",
"cannot use this member function.");
return -1;
}
}
/**
* @brief 文字列バッファから Header Unit を読み込む
*
* @param buffer 読み込み対象のバッファ
* @return 非負値: 読み込んだバイト数
* 負値: エラー
*/
ssize_t fits_header::read_buffer( const char *buffer )
{
if ( this->sysrecords_prohibition_rec == false ) {
return this->header_load(buffer);
}
else {
err_report(__FUNCTION__,"ERROR",
"cannot use this member function.");
return -1;
}
}
/**
* @brief ストリームにアクセスし,Data Unit を読み飛ばす
*
* @param sref 読み飛ばし対象のストリーム (cstreamioの継承クラス)
* @param max_bytes_skip 読み飛ばされるべき最大のバイト数
* @return 非負値: 読み飛ばしたバイト数
* 負値: エラー
*/
ssize_t fits_header::skip_data_stream( cstreamio &sref, size_t max_bytes_skip )
{
return this->data_skip(sref,&max_bytes_skip);
}
/**
* @brief ストリームにアクセスし,Data Unit を読み飛ばす
*
* @param sref 読み飛ばし対象のストリーム (cstreamioの継承クラス)
* @return 非負値: 読み飛ばしたバイト数
* 負値: エラー
*/
ssize_t fits_header::skip_data_stream( cstreamio &sref )
{
return this->data_skip(sref,NULL);
}
/**
* @brief ストリームへの Header Unit の書き込み
*
* @param sref 書き込み対象のストリーム (cstreamioの継承クラス)
* @param end_and_blank 「END」キーワードと2880バイトアラインのための余白を
* 追加する場合は true
* @return 非負値: 書き込んだバイト数
* 負値: エラー
*/
ssize_t fits_header::write_stream( cstreamio &sref, bool end_and_blank )
{
return this->header_save( &sref, NULL, end_and_blank );
}
/* discard original 80-char record, and reformat all records */
/**
* @brief 全ヘッダレコードの再フォーマットを行なう
*
* 各 fits_header_record が現在保持している 80文字のフォーマット済み文字列を,
* 現在のキーワード,値,コメントの内容から作りなおします.
*/
fits_header &fits_header::reformat()
{
long i;
for ( i=0 ; i < this->length() ; i++ ) {
this->record(i).reformat();
}
return *this;
}
/**
* @brief 全ヘッダレコードのフォーマット済み文字列(80×n文字)を取得
*
* オブジェクト内で生成された,全ヘッダレコードのフォーマット済み文字列
* (80×n文字)を返します.改行文字は含まれず,文字列は '\0' で終端しています.
*
* @return フォーマット済み文字列(80×n文字)
*/
const char *fits_header::formatted_string()
{
long i;
size_t pos = 0;
for ( i=0 ; i < this->length() ; i++ ) {
tstring tmp_str;
size_t len;
tmp_str = this->record(i).formatted_string();
if ( 0 < (len=tmp_str.length()) ) {
if ( this->formatted_rec.length() < pos + len ) {
size_t to_add;
/* ざっくり確保する */
to_add = FITS::HEADER_RECORD_UNIT * this->length() * 2;
this->formatted_rec.resizeby(to_add);
}
this->formatted_rec.put(pos,tmp_str);
pos += len;
}
}
/* 最終的な長さ調整 */
this->formatted_rec.resize(pos);
return this->formatted_rec.cstr();
}
/**
* @brief 全ヘッダレコードのフォーマット済み文字列(80×n文字)の長さを取得
*
* @note '\0' は長さに含まれません.
*/
size_t fits_header::formatted_length()
{
long i;
size_t len_all = 0;
for ( i=0 ; i < this->length() ; i++ ) {
len_all += this->record(i).formatted_length();
}
return len_all;
}
/* 複数行での編集 */
/**
* @brief 複数のヘッダレコードの追加,更新
*
* キーワードが存在しない場合は追加し,同一のキーワードが存在する場合は
* 指定された内容で上書きします.
*
* @param obj 源泉値
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::update_records( const fits_header &obj )
{
long i, n_new = 0;
/* keyrowd, value, length */
fits::header_def *tmp_defs;
mdarray tmp_defs_rec(sizeof(*tmp_defs), true, &tmp_defs); /* [void **] */
/* formatted 80-char string */
const char **tmp_formatted;
mdarray tmp_formatted_rec(sizeof(*tmp_formatted), true,
&tmp_formatted); /* [void **] */
tmp_defs_rec.resize(obj.length());
tmp_formatted_rec.resize(obj.length());
for ( i=0 ; i < obj.length() ; i++ ) {
const fits_header_record &robj = obj.record_cs(i);
if ( robj.status() == FITS::NORMAL_RECORD ) {
long idx;
/* description でない index を探す */
idx = this->index(robj.keyword());
if ( 0 <= idx ) this->assign(idx, robj);
}
}
for ( i=0 ; i < obj.length() ; i++ ) {
const fits_header_record &robj = obj.record_cs(i);
if ( robj.status() == FITS::NORMAL_RECORD ) {
long idx;
/* description でない index を探す */
idx = this->index(robj.keyword());
if ( idx < 0 ) {
tmp_defs[n_new] = robj.raw_record();
tmp_formatted[n_new] = robj.a_formatted_rec.cstr();
n_new ++;
}
}
}
this->append_header_records(tmp_defs, tmp_formatted, n_new, true);
return *this;
}
/**
* @brief 予約キーワード(BITPIX 等)を却下するための内部用の関数 (内部用)
*
* @note private な関数です.
*/
static long reject_sysheader( const fits::header_def defs[],
const char *formatted_str[], long num_defs,
mdarray *tmp_defs_rec,
mdarray *tmp_formatted_str,
const char *fncnam, bool warn )
{
long i;
bool ok_all = true;
fits::header_def *tmp_defs = NULL;
const char **tmp_formatted = NULL;
/* システム用キーワードはリジェクトする */
for ( i=0 ; i < num_defs ; i++ ) {
if ( defs[i].value != NULL && defs[i].comment != NULL &&
is_header_reserved_key(defs[i].keyword) == true )
ok_all = false;
}
if ( ok_all == false ) {
long j;
tmp_defs_rec->resize(num_defs);
tmp_defs = (fits::header_def *)tmp_defs_rec->data_ptr();
if ( formatted_str != NULL ) {
tmp_formatted_str->resize(num_defs);
tmp_formatted = (const char **)tmp_formatted_str->data_ptr();
}
for ( i=0, j=0 ; i < num_defs ; i++ ) {
if ( defs[i].value != NULL && defs[i].comment != NULL &&
is_header_reserved_key(defs[i].keyword) == true ) {
if ( warn == true ) {
err_report1(fncnam,"WARNING",
"keyword '%s' cannot be appended by the user",
defs[i].keyword);
}
}
else {
tmp_defs[j].keyword = defs[i].keyword;
tmp_defs[j].value = defs[i].value;
tmp_defs[j].comment = defs[i].comment;
if ( formatted_str != NULL ) {
tmp_formatted[j] = formatted_str[i];
}
j++;
}
}
num_defs = j;
}
return num_defs;
}
/* private */
/**
* @brief 複数のヘッダレコードの追加 (内部実装用)
*
* @note このメンバ関数は private です.
*/
fits_header &fits_header::append_header_records( const fits::header_def defs[],
const char *formatted_str[],
long num_defs, bool warn )
{
long i;
fits_header_record *tmp_rec_ptr;
long begin_index;
mdarray tmp_defs_rec(sizeof(fits::header_def), true);
mdarray tmp_formatted_str(sizeof(const char *), true);
const fits::header_def *defs_ptr = defs;
begin_index = this->num_records_rec;
/* 引数チェック */
if ( num_defs < 0 ) goto quit;
if ( defs == NULL || num_defs == 0 ) {
goto quit;
}
/* システムヘッダが禁止されている場合,入れられないものをリジェクトする */
if ( this->sysrecords_prohibition_rec == true ) {
long n = reject_sysheader(defs, formatted_str, num_defs,
&tmp_defs_rec, &tmp_formatted_str, __FUNCTION__, warn);
if ( n < num_defs ) {
num_defs = n;
defs_ptr = (fits::header_def *)tmp_defs_rec.data_ptr();
if ( formatted_str != NULL ) {
formatted_str = (const char **)tmp_formatted_str.data_ptr();
}
}
}
/* アドレステーブルを広げる */
try {
this->records_rec.resize(this->num_records_rec + num_defs + 1);
}
catch (...) {
err_throw(__FUNCTION__,"FATAL","records_rec.resize() failed");
}
/* 1つ1つ new する */
for ( i=0 ; i < num_defs ; i++ ) {
bool register_index = true;
//fprintf(stderr,"debug: idx=%d\n",i);
try {
tmp_rec_ptr = new fits_header_record;
tmp_rec_ptr->register_manager(this);
}
catch (...) {
err_throw(__FUNCTION__,"FATAL","'new' failed");
}
try {
tmp_rec_ptr->assign_any(defs_ptr[i]);
if ( formatted_str != NULL ) {
tmp_rec_ptr->a_formatted_rec = formatted_str[i];
}
}
catch (...) {
delete tmp_rec_ptr;
err_throw(__FUNCTION__,"FATAL","tmp_rec_ptr->assign_any() failed");
}
if ( tmp_rec_ptr->status() != FITS::NORMAL_RECORD ) {
register_index = false; /* normal 以外では index を作成しない */
}
else {
if ( 0 <= this->index(tmp_rec_ptr->keyword()) ) {
if ( warn == true ) {
if ( this->suppress_dupkey_warning_rec == false ) {
err_report1(__FUNCTION__,"WARNING",
"duplicated keyword '%s' is appended",
tmp_rec_ptr->keyword());
}
}
}
}
if ( register_index == true ) { /* インデックスを作成する */
int s;
/*
[注意]
index_rec への keyword 登録は fits_header_record オブジェクトに
登録済みのものを追加すること(FITS規格に適合しないキーワードの
場合,文字を置き換える場合があるので)
duplicated keyword で警告を出す場合も同様.
*/
s = this->index_rec.append( tmp_rec_ptr->keyword(),
begin_index + i );
if ( s < 0 ) {
delete tmp_rec_ptr;
err_throw(__FUNCTION__,"FATAL",
"this->index_rec.append() failed");
}
}
this->records_ptr_rec[begin_index + i] = tmp_rec_ptr;
tmp_rec_ptr = NULL;
this->num_records_rec ++;
}
quit:
return *this;
}
/* public */
/**
* @brief 複数のヘッダレコードの追加 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::append_records( const fits::header_def defs[] )
{
long num_defs = 0;
if ( defs == NULL ) {
return this->append_records( defs, num_defs, true );
}
for ( num_defs=0 ; defs[num_defs].keyword != NULL ; num_defs++ ) {
if ( END.strcmp(defs[num_defs].keyword) == 0 &&
defs[num_defs].value == NULL &&
defs[num_defs].comment == NULL ) break;
}
return this->append_records( defs, num_defs, true );
}
/**
* @brief 複数のヘッダレコードの追加 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::append_records( const fits::header_def defs[],
long num_defs, bool warn )
{
return this->append_header_records(defs, NULL, num_defs, warn);
}
/**
* @brief 複数のヘッダレコードの追加 (fits_header オブジェクトで指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::append_records( const fits_header &obj, bool warn )
{
if ( 0 < obj.length() ) {
long i;
/* keyword, value, comment */
fits::header_def *tmp_defs;
mdarray tmp_defs_rec(sizeof(*tmp_defs),true,&tmp_defs); /* [void **] */
/* formatted 80-char string */
const char **tmp_formatted;
mdarray tmp_formatted_rec(sizeof(*tmp_formatted),true,
&tmp_formatted); /* [void **] */
tmp_defs_rec.resize(obj.length());
tmp_formatted_rec.resize(obj.length());
for ( i=0 ; i < obj.length() ; i++ ) {
tmp_defs[i] = obj.record_cs(i).raw_record();
tmp_formatted[i] = obj.record_cs(i).a_formatted_rec.cstr();
}
this->append_header_records(tmp_defs, tmp_formatted, obj.length(), warn);
}
return *this;
}
/* private */
/**
* @brief 複数のヘッダレコードの挿入 (内部実装用)
*
* @note このメンバ関数は private です.
*/
fits_header &fits_header::insert_header_records( long index0,
const fits::header_def defs[],
const char *formatted_str[],
long num_defs, bool warn )
{
fits_header_record *tmp_rec_ptr;
long i;
mdarray tmp_defs_rec(sizeof(fits::header_def), true);
mdarray tmp_formatted_str(sizeof(const char *), true);
const fits::header_def *defs_ptr = defs;
/* 引数チェック */
if ( index0 < 0 ) index0 = 0;
if ( this->num_records_rec < index0 ) index0 = this->num_records_rec;
if ( this->num_records_rec == index0 ) {
return append_records(defs,num_defs,warn);
}
if ( num_defs < 0 ) goto quit;
if ( defs == NULL || num_defs == 0 ) {
goto quit;
}
/* システムヘッダが禁止されている場合,入れられないものをリジェクトする */
if ( this->sysrecords_prohibition_rec == true ) {
long n = reject_sysheader(defs, formatted_str, num_defs,
&tmp_defs_rec, &tmp_formatted_str, __FUNCTION__, warn);
if ( n < num_defs ) {
num_defs = n;
defs_ptr = (fits::header_def *)tmp_defs_rec.data_ptr();
if ( formatted_str != NULL ) {
formatted_str = (const char **)tmp_formatted_str.data_ptr();
}
}
}
/* アドレステーブルを広げる */
try {
this->records_rec.resize(this->num_records_rec + num_defs + 1);
}
catch (...) {
err_throw(__FUNCTION__,"FATAL","records_rec.resize() failed");
}
/* 1つ1つ new する */
for ( i=0 ; i < num_defs ; i++ ) {
bool register_index = true;
long j;
try {
tmp_rec_ptr = new fits_header_record;
tmp_rec_ptr->register_manager(this);
}
catch (...) {
err_throw(__FUNCTION__,"FATAL","'new' failed");
}
try {
tmp_rec_ptr->assign_any(defs_ptr[i]);
if ( formatted_str != NULL ) {
tmp_rec_ptr->a_formatted_rec = formatted_str[i];
}
}
catch (...) {
delete tmp_rec_ptr;
err_throw(__FUNCTION__,"FATAL","tmp_rec_ptr->assign_any() failed");
}
if ( tmp_rec_ptr->status() != FITS::NORMAL_RECORD ) {
register_index = false; /* normal 以外では index を作成しない */
}
else {
if ( 0 <= this->index(tmp_rec_ptr->keyword()) ) {
if ( warn == true ) {
if ( this->suppress_dupkey_warning_rec == false ) {
err_report1(__FUNCTION__,"WARNING",
"duplicated keyword '%s' is inserted",
tmp_rec_ptr->keyword());
}
}
}
}
/* ←ここで insert しようとするのんの index を作成すると */
/* duplicated keyword の時に,重複する index を作成しようとして */
/* 失敗する */
/* ↓ここは失敗しない */
/* ずらして(終端のNULLの分も),隙間に登録する */
this->records_rec.move( index0 + i,
this->num_records_rec - i - index0 + 1,
index0 + i + 1, false );
this->records_ptr_rec[index0 + i] = tmp_rec_ptr;
this->num_records_rec ++;
//fprintf(stderr,"debug: i=%ld\n",i);
/* ずらしたところの index を作りなおす */
for ( j = index0 + i + 1 ; j < this->num_records_rec ; j++ ) {
if ( this->records_ptr_rec[j] != NULL &&
this->records_ptr_rec[j]->status() == FITS::NORMAL_RECORD ) {
int s;
//fprintf(stderr,"debug: updated A i=%ld [%ld]\n",i,j);
s= this->index_rec.update(this->records_ptr_rec[j]->keyword(), j-1, j);
if ( s < 0 ) {
err_throw(__FUNCTION__,"FATAL",
"Internal ERROR: this->index_rec.update() failed");
}
}
}
/* insert しようとするのんのインデックスを作成する */
if ( register_index == true ) {
int s;
s = this->index_rec.append(tmp_rec_ptr->keyword(),
index0 + i);
if ( s < 0 ) {
delete tmp_rec_ptr;
err_throw(__FUNCTION__,"FATAL",
"this->index_rec.append() failed");
}
}
}
quit:
return *this;
}
/* public */
/**
* @brief 複数のヘッダレコードの挿入 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert_records( long index0,
const fits::header_def defs[] )
{
long num_defs = 0;
if ( defs == NULL ) {
return this->insert_records( index0, defs, num_defs, true );
}
for ( num_defs=0 ; defs[num_defs].keyword != NULL ; num_defs++ ) {
if ( END.strcmp(defs[num_defs].keyword) == 0 &&
defs[num_defs].value == NULL &&
defs[num_defs].comment == NULL ) break;
}
return this->insert_records( index0, defs, num_defs, true );
}
/**
* @brief 複数のヘッダレコードの挿入 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert_records( long index0,
const fits::header_def defs[],
long num_defs, bool warn )
{
return this->insert_header_records( index0, defs, NULL, num_defs, warn );
}
/**
* @brief 複数のヘッダレコードの挿入 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert_records( const char *keyword0,
const fits::header_def defs[] )
{
return this->insert_records( this->index(keyword0), defs );
}
/**
* @brief 複数のヘッダレコードの挿入 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert_records( const char *keyword0,
const fits::header_def defs[], long num_defs, bool warn )
{
return this->insert_records( this->index(keyword0), defs, num_defs, warn );
}
/**
* @brief 複数のヘッダレコードの挿入 (fits_header オブジェクトで指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert_records( long index0, const fits_header &obj,
bool warn )
{
if ( 0 < obj.length() ) {
long i;
/* keyword, value, comment */
fits::header_def *tmp_defs;
mdarray tmp_defs_rec(sizeof(*tmp_defs),true,&tmp_defs); /* [void **] */
/* formatted 80-char string */
const char **tmp_formatted;
mdarray tmp_formatted_rec(sizeof(*tmp_formatted),true,
&tmp_formatted); /* [void **] */
tmp_defs_rec.resize(obj.length());
tmp_formatted_rec.resize(obj.length());
for ( i=0 ; i < obj.length() ; i++ ) {
tmp_defs[i] = obj.record_cs(i).raw_record();
tmp_formatted[i] = obj.record_cs(i).a_formatted_rec.cstr();
}
this->insert_header_records( index0,
tmp_defs, tmp_formatted, obj.length(),
warn);
}
return *this;
}
/**
* @brief 複数のヘッダレコードの挿入 (fits_header オブジェクトで指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert_records( const char *keyword0,
const fits_header &obj, bool warn )
{
return this->insert_records( this->index(keyword0), obj, warn );
}
/* protected */
/**
* @brief 複数のヘッダレコードの削除 (低レベル)
*
* @note これは,this->manager->setup_sys_header() を呼び出さない.
* このクラスから erase_records() を使いたい場合に使う.
* このメンバ関数は protected です.
*/
bool fits_header::_erase_records( long index0, long num_records )
{
long i, num_rm;
long idx_to_rm;
bool found_sys_record = false;
/* 引数チェック */
if ( index0 < 0 || this->num_records_rec <= index0 ) {
goto quit;
}
if ( this->num_records_rec < index0 + num_records ) {
num_records = this->num_records_rec - index0;
}
if ( num_records < 0 ) {
goto quit;
}
if ( num_records == 0 ) {
goto quit;
}
num_rm = 0;
idx_to_rm = index0;
/* まず削除された状態を作る */
for ( i=0 ; i < num_records ; i++ ) {
//fprintf(stderr,"debug: idx=%d\n",i);
if ( this->records_ptr_rec[idx_to_rm] == NULL ||
this->records_ptr_rec[idx_to_rm]->keyword_protected() == false ) {
long sz;
if ( this->records_ptr_rec[idx_to_rm] != NULL ) {
/* index を削除 */
if (this->records_ptr_rec[idx_to_rm]->status() == FITS::NORMAL_RECORD){
int s;
//fprintf(stderr,"debug: erase: [%s]\n",
// this->records_ptr_rec[idx_to_rm]->keyword());
s = this->index_rec.erase(
this->records_ptr_rec[idx_to_rm]->keyword(),
idx_to_rm + num_rm);
if ( s < 0 ) {
/* 内部でreallocエラーがおこると s=-1 がくるが、
インデックス自体は正常に削除されている */
err_throw(__FUNCTION__,"FATAL",
"this->index_rec.erase() failed");
}
/* sys record かどうかチェック */
if ( is_header_reserved_key(
this->records_ptr_rec[idx_to_rm]->keyword()) == true ) {
found_sys_record = true;
}
}
/* 本体を削除 */
delete this->records_ptr_rec[idx_to_rm];
}
/* NULL の部分も含めて移動 */
sz = this->num_records_rec - idx_to_rm - num_rm;
//fprintf(stderr,"debug: sz=%ld\n",sz);
this->records_rec.move( idx_to_rm + 1, sz, idx_to_rm, false );
num_rm ++;
}
else {
/* index を張りなおす */
if ( this->records_ptr_rec[idx_to_rm]->status() == FITS::NORMAL_RECORD ) {
int s;
//fprintf(stderr,"debug: re-assigned A [%ld]\n",idx_to_rm);
s = this->index_rec.update(this->records_ptr_rec[idx_to_rm]->keyword(),
idx_to_rm + num_rm, idx_to_rm);
if ( s < 0 ) {
err_throw(__FUNCTION__,"FATAL",
"Internal ERROR: this->index_rec.update() failed");
}
}
err_report1(__FUNCTION__,"WARNING","keyword='%s' is protected; "
"cannot erase", this->records_ptr_rec[idx_to_rm]->keyword());
idx_to_rm ++;
}
}
this->num_records_rec -= num_rm;
/* index を張りなおす */
for ( i=idx_to_rm ; i < this->num_records_rec ; i++ ) {
if ( this->records_ptr_rec[i] != NULL &&
this->records_ptr_rec[i]->status() == FITS::NORMAL_RECORD ) {
int s;
//fprintf(stderr,"debug: re-assigned B [%ld]\n",i);
s = this->index_rec.update( this->records_ptr_rec[i]->keyword(),
i + num_rm, i );
if ( s < 0 ) {
err_throw(__FUNCTION__,"FATAL",
"Internal ERROR: this->index_rec.update() failed");
}
}
}
/* アドレステーブルを狭める */
try {
this->records_rec.resize( this->num_records_rec + 1 );
}
catch (...) {
err_throw(__FUNCTION__,"FATAL","records_rec.resize() failed");
}
quit:
return found_sys_record;
}
/**
* @brief 複数のヘッダレコードの削除
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::erase_records( long index0, long num_records )
{
bool found_sys_record;
found_sys_record = this->fits_header::_erase_records(index0, num_records);
/* sys record が消去された場合 */
if ( found_sys_record == true ) {
/* 消去されても Data Unit に関連するレコードはすぐに復活させる */
if ( this->sysrecords_prohibition_rec == true &&
this->manager != NULL ) {
/* this will call an overridden function */
//err_report(__FUNCTION__,"DEBUG","called ...... from [F]");
this->manager->setup_sys_header();
}
}
return *this;
}
/**
* @brief 複数のヘッダレコードの削除
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::erase_records( const char *keyword0, long num_records )
{
return this->erase_records( this->index(keyword0), num_records );
}
//fits_header &fits_header::erase_all_sysrecords()
//{
// long i;
// for ( i = this->length() ; 0 < i ; ) {
// i--;
// if ( this->is_sysrecord(i) == true ) this->erase(i);
// }
// return *this;
//}
/*
*/
/* 1行での追加とか */
/**
* @brief 1つのヘッダレコードを追加,更新
*
* キーワードが存在しない場合は追加し,同一のキーワードが存在する場合は
* 指定された内容で上書きします.
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::update( const char *keyword, const char *value,
const char *comment )
{
fits::header_def defs[] = { {NULL,NULL,NULL}, {NULL} };
long idx;
if ( keyword == NULL ) return this->append_records(defs);
defs[0].keyword = keyword;
defs[0].value = value;
defs[0].comment = comment;
/* description でない index を探す */
idx = this->index(keyword);
if ( idx < 0 ) {
if ( value == NULL ) defs[0].value = "";
if ( comment == NULL ) defs[0].comment = "";
return this->append_records(defs);
}
else {
this->assign(idx,defs[0]);
return *this;
}
}
/**
* @brief 1つのヘッダレコードを追加,更新(fits_header_recordオブジェクトで指定)
*
* キーワードが存在しない場合は追加し,同一のキーワードが存在する場合は
* 指定された内容で上書きします.
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::update( const fits_header_record &obj )
{
if ( obj.status() == FITS::NORMAL_RECORD ) {
long idx;
/* description でない index を探す */
idx = this->index(obj.keyword());
if ( idx < 0 ) {
this->append(obj);
}
else {
this->assign(idx, obj);
}
}
return *this;
}
/**
* @brief 1つのヘッダレコードを追加 (キーワードのみ指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::append( const char *keyword )
{
if ( keyword != NULL ) {
fits_header_record rec;
rec.assign(keyword,"","").assign_default_comment(this->hdutype());
this->append(rec.raw_record());
}
return *this;
}
/**
* @brief 1つのヘッダレコードを追加
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::append( const char *keyword, const char *value,
const char *comment )
{
if ( keyword != NULL ) {
fits_header_record rec;
bool flg = false;
if ( value == NULL ) value = "";
if ( comment == NULL ) {
comment = "";
flg = true;
}
rec.assign(keyword,value,comment);
if ( flg == true ) rec.assign_default_comment(this->hdutype());
this->append(rec.raw_record());
}
return *this;
}
/**
* @brief 1つの記述式ヘッダレコード(HISTORYやCOMMENT)を追加
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::append(const char *keyword, const char *description)
{
fits::header_def defs[] = { {NULL,NULL,NULL}, {NULL} };
defs[0].keyword = keyword;
defs[0].value = description;
return this->append_records(defs);
}
/**
* @brief 1つのヘッダレコードを追加 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::append( const fits::header_def &def )
{
fits::header_def defs[] = { {NULL,NULL,NULL}, {NULL} };
defs[0] = def;
return this->append_records(defs);
}
/**
* @brief 1つのヘッダレコードを追加 (キーワードのみ指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::append( const fits_header_record &obj )
{
const fits::header_def &def = obj.raw_record();
const char *formatted = obj.a_formatted_rec.cstr();
/* use private member function */
return this->append_header_records(&def, &formatted, 1, true);
}
/**
* @brief 1つのヘッダレコードを挿入 (キーワードのみ指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert( long index0, const char *keyword )
{
if ( keyword != NULL ) {
fits_header_record rec;
rec.assign(keyword,"","").assign_default_comment(this->hdutype());
this->insert(index0, rec);
}
return *this;
}
/**
* @brief 1つのヘッダレコードを挿入 (キーワードのみ指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert( const char *keyword0, const char *keyword )
{
if ( keyword != NULL ) {
fits_header_record rec;
rec.assign(keyword,"","").assign_default_comment(this->hdutype());
this->insert(keyword0, rec);
}
return *this;
}
/**
* @brief 1つのヘッダレコードを挿入
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert( long index0,
const char *k, const char *v, const char *c )
{
if ( k != NULL ) {
fits_header_record rec;
bool flg = false;
if ( v == NULL ) v = "";
if ( c == NULL ) {
c = "";
flg = true;
}
rec.assign(k, v, c);
if ( flg == true ) rec.assign_default_comment(this->hdutype());
this->insert(index0, rec.raw_record());
}
return *this;
}
/**
* @brief 1つのヘッダレコードを挿入
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert( const char *keyword0,
const char *k, const char *v, const char *c )
{
if ( k != NULL ) {
fits_header_record rec;
bool flg = false;
if ( v == NULL ) v = "";
if ( c == NULL ) {
c = "";
flg = true;
}
rec.assign(k, v, c);
if ( flg == true ) rec.assign_default_comment(this->hdutype());
this->insert(keyword0, rec.raw_record());
}
return *this;
}
/**
* @brief 1つの記述式ヘッダレコード(HISTORYやCOMMENT)を挿入
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert( long index0,
const char *keywd, const char *description )
{
fits::header_def defs[] = { {NULL,NULL,NULL}, {NULL} };
defs[0].keyword = keywd;
defs[0].value = description;
return this->insert_records(index0,defs);
}
/**
* @brief 1つの記述式ヘッダレコード(HISTORYやCOMMENT)を挿入
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert( const char *keyword0,
const char *keywd, const char *description )
{
fits::header_def defs[] = { {NULL,NULL,NULL}, {NULL} };
defs[0].keyword = keywd;
defs[0].value = description;
return this->insert_records(keyword0,defs);
}
/**
* @brief 1つのヘッダレコードを挿入 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert( long index0, const fits::header_def &def )
{
fits::header_def defs[] = { {NULL,NULL,NULL}, {NULL} };
defs[0] = def;
return this->insert_records(index0,defs);
}
/**
* @brief 1つのヘッダレコードを挿入 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert( const char *keyword0,
const fits::header_def &def )
{
fits::header_def defs[] = { {NULL,NULL,NULL}, {NULL} };
defs[0] = def;
return this->insert_records(keyword0,defs);
}
/**
* @brief 1つのヘッダレコードを挿入 (fits_header_record オブジェクトで指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert( long index0, const fits_header_record &obj )
{
const fits::header_def &def = obj.raw_record();
const char *formatted = obj.a_formatted_rec.cstr();
/* use private member function */
return this->insert_header_records( index0, &def, &formatted, 1, true );
}
/**
* @brief 1つのヘッダレコードを挿入 (fits_header_record オブジェクトで指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::insert( const char *keyword0,
const fits_header_record &obj )
{
const fits::header_def &def = obj.raw_record();
const char *formatted = obj.a_formatted_rec.cstr();
/* use private member function */
return this->insert_header_records( this->index(keyword0),
&def, &formatted, 1, true );
}
/**
* @brief 1つのヘッダキーワード名の変更
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::rename( long index0, const char *new_name )
{
fits::header_def def = {new_name,NULL,NULL};
/* check args */
if ( index0 < 0 || this->num_records_rec <= index0 ) goto quit;
if ( new_name == NULL ) goto quit;
/* rename */
this->assign(index0, def);
quit:
return *this;
}
/**
* @brief 1つのヘッダキーワード名の変更
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::rename( const char *keyword0, const char *new_name )
{
return this->rename( this->index(keyword0), new_name );
}
/**
* @brief 1つのヘッダレコードの消去
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::erase( long index0 )
{
this->erase_records(index0,1);
return *this;
}
/**
* @brief 1つのヘッダレコードの消去
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::erase( const char *keyword0 )
{
this->erase_records(keyword0,1);
return *this;
}
/*
* wrappers for low-level member functions
*/
/**
* @brief 1つのヘッダレコードを更新 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assign( long index0, const fits::header_def &def )
{
//err_report(__FUNCTION__,"DEBUG","called!!");
int s;
tstring old_key;
fits_header_record tmp_hrec;
fits::header_def tmp_def = {NULL,def.value,def.comment};
if ( index0 < 0 || this->num_records_rec <= index0 ) {
err_report(__FUNCTION__,"WARNING","invalid index0");
goto quit;
}
if ( this->records_ptr_rec[index0] == NULL ) goto quit;
//fprintf(stderr,"debug : def.comment = [%s]\n",def.comment);
/* キーワードに空白が与えられ,かつ値かコメントに空白が与えられた場合は */
/* レコードの初期化を行なう */
if ( (def.keyword != NULL && def.keyword[0]=='\0') &&
( (def.value != NULL && def.value[0]=='\0') ||
(def.comment != NULL && def.comment[0]=='\0') ) ) {
/* description でない場合,keyword を保存しておく */
if ( this->records_ptr_rec[index0]->status() == FITS::NORMAL_RECORD ) {
old_key = this->records_ptr_rec[index0]->keyword();
}
/* 初期化を試みる */
this->records_ptr_rec[index0]->assign_any(def);
/* index */
if ( old_key.cstr() != NULL ) { /* description でない場合 */
/* キーワードに変更があった場合は登録する */
/* (keyword protected な場合は,変更できない) */
if ( this->records_ptr_rec[index0]->status() != FITS::NORMAL_RECORD ||
old_key.strcmp(this->records_ptr_rec[index0]->keyword()) != 0 ) {
s = this->index_rec.erase(old_key.cstr(),index0);
if ( s < 0 ) {
err_throw(__FUNCTION__,"FATAL",
"this->index_rec.erase() failed");
}
}
}
goto quit;
}
/* システムヘッダが禁止されている場合,警告を出してエラーとする */
if ( this->sysrecords_prohibition_rec == true ) {
if ( def.keyword != NULL &&
is_header_reserved_key(def.keyword) == true ) {
err_report1(__FUNCTION__,"WARNING",
"keyword '%s' cannot be assigned by the user",
def.keyword);
goto quit;
}
}
/* 一旦,テンポラリに書き出してみる(キーワードの文字列置換のため) */
if ( def.keyword != NULL ) {
tmp_hrec.assign_any(def);
tmp_def.keyword = tmp_hrec.keyword();
}
/* 当該のレコードが description でない場合 */
if ( this->records_ptr_rec[index0]->status() == FITS::NORMAL_RECORD ) {
/* keyword を保存しておく */
old_key = this->records_ptr_rec[index0]->keyword();
/* 登録済みの keyword を入れようとした場合,警告する */
if ( tmp_def.keyword != NULL && 0 <= this->index(tmp_def.keyword) ) {
if ( this->index(tmp_def.keyword) != index0 ) {
if ( this->suppress_dupkey_warning_rec == false ) {
err_report1(__FUNCTION__,"WARNING",
"duplicated keyword '%s' is appended",tmp_def.keyword);
}
}
}
}
/* 登録する */
try {
this->records_ptr_rec[index0]->assign_any(def);
}
catch (...) {
this->fits_header::_erase_records(index0,1);
err_throw(__FUNCTION__,"FATAL",
"this->records_ptr_rec[index0]->assign_any(def) failed");
}
if ( old_key.cstr() == NULL ) { /* 新規の場合 */
if ( this->records_ptr_rec[index0]->status() == FITS::NORMAL_RECORD ) {
s= this->index_rec.append(this->records_ptr_rec[index0]->keyword(),index0);
if ( s < 0 ) {
this->fits_header::_erase_records(index0,1);
err_throw(__FUNCTION__,"FATAL",
"this->index_rec.append() failed");
}
}
}
else { /* 更新前のが description でない場合 */
/* description になった場合,キーワードに変更があった場合は消去する */
if ( this->records_ptr_rec[index0]->status() != FITS::NORMAL_RECORD ||
old_key.strcmp(this->records_ptr_rec[index0]->keyword()) != 0) {
s= this->index_rec.erase(old_key.cstr(),index0);
if ( s < 0 ) {
err_throw(__FUNCTION__,"FATAL","this->index_rec.erase() failed");
}
}
/* description ではなく,キーワードに変更があった場合は消去する */
if ( this->records_ptr_rec[index0]->status() == FITS::NORMAL_RECORD &&
old_key.strcmp(this->records_ptr_rec[index0]->keyword()) != 0) {
s= this->index_rec.append(this->records_ptr_rec[index0]->keyword(),index0);
if ( s < 0 ) {
this->fits_header::_erase_records(index0,1);
err_throw(__FUNCTION__,"FATAL",
"this->index_rec.append() failed");
}
}
}
quit:
return *this;
}
/**
* @brief 1つのヘッダレコードを更新 (fits::header_def 構造体で指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assign( const char *keyword0, const fits::header_def &def )
{
return this->assign( this->index(keyword0), def );
}
/**
* @brief 1つのヘッダレコードを更新 (fits_header_record オブジェクトで指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assign( long index0, const fits_header_record &obj )
{
fits::header_def tmp_def = {"","",""};
if ( index0 < 0 || this->num_records_rec <= index0 ) {
err_report(__FUNCTION__,"WARNING","invalid index0");
return *this;
}
/* objがすでに管理下にないかチェック */
fits_header_record &dest = this->at(index0);
if ( &dest == &obj ) return *this;
this->assign( index0, tmp_def ); /* 消去 */
if ( this->records_ptr_rec[index0]->status() == FITS::NULL_RECORD ||
this->records_ptr_rec[index0]->status() == obj.status() ) {
this->assign(index0, obj.raw_record());
this->at(index0).a_formatted_rec = obj.a_formatted_rec;
}
return *this;
}
/**
* @brief 1つのヘッダレコードを更新 (fits_header_record オブジェクトで指定)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assign( const char *keyword0,
const fits_header_record &obj )
{
return this->assign( this->index(keyword0), obj );
}
/**
* @brief 1つのヘッダレコードを更新
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assign( long index0,
const char *keyword, const char *value,
const char *comment )
{
if ( index0 < 0 || this->num_records_rec <= index0 ) {
err_report(__FUNCTION__,"WARNING","invalid index0");
return *this;
}
if ( this->records_ptr_rec[index0]->status() == FITS::NORMAL_RECORD ) {
fits::header_def def = {keyword,value,comment};
this->assign( index0, def );
}
else if ( keyword != NULL && keyword[0] != '\0' ) {
fits::header_def tmp_def = {"","",""};
this->assign( index0, tmp_def ); /* 消去 */
if ( value == NULL ) value = "";
if ( comment == NULL ) comment = "";
if ( this->records_ptr_rec[index0]->status() == FITS::NULL_RECORD ) {
fits::header_def def = {keyword,value,comment};
this->assign( index0, def );
}
}
else if ( keyword != NULL && keyword[0] == '\0' &&
( (value != NULL && value[0] == '\0') ||
(comment != NULL && comment[0] == '\0') ) ) {
fits::header_def tmp_def = {"","",""};
this->assign( index0, tmp_def ); /* 消去 */
}
return *this;
}
/**
* @brief 1つのヘッダレコードを更新
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assign( const char *keyword0,
const char *keyword, const char *value,
const char *comment )
{
return this->assign( this->index(keyword0), keyword, value, comment );
}
/**
* @brief 1つのヘッダレコードを記述式レコードで更新
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assign( long index0,
const char *keyword, const char *description )
{
if ( index0 < 0 || this->num_records_rec <= index0 ) {
err_report(__FUNCTION__,"WARNING","invalid index0");
return *this;
}
if ( this->records_ptr_rec[index0]->status() == FITS::DESCRIPTION_RECORD ) {
fits::header_def def = {keyword,description,NULL};
this->assign( index0, def );
}
else if ( (keyword != NULL && keyword[0] != '\0') ||
(description != NULL && description[0] != '\0') ) {
fits::header_def tmp_def = {"","",""};
this->assign( index0, tmp_def ); /* 消去 */
if ( keyword == NULL ) keyword = "";
if ( description == NULL ) description = "";
if ( this->records_ptr_rec[index0]->status() == FITS::NULL_RECORD ) {
fits::header_def def = {keyword,description,NULL};
this->assign( index0, def );
}
}
else if ( keyword != NULL && keyword[0] == '\0' &&
description != NULL && description[0] == '\0' ) {
fits::header_def tmp_def = {"","",""};
this->assign( index0, tmp_def ); /* 消去 */
}
return *this;
}
/**
* @brief 1つのヘッダレコードを記述式レコードで更新
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assign( const char *keyword0,
const char *keyword, const char *description )
{
return this->assign( this->index(keyword0), keyword, description );
}
/* value */
/**
* @brief 1つのヘッダレコードの値を更新 (低レベル・printf()の記法)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::vassignf_value( long index0, const char *format,
va_list ap )
{
if ( index0 < 0 || this->num_records_rec <= index0 ) {
err_report(__FUNCTION__,"WARNING","invalid index0");
}
else this->records_ptr_rec[index0]->vassignf_value(format,ap);
return *this;
}
/**
* @brief 1つのヘッダレコードの値を更新 (低レベル・printf()の記法)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::vassignf_value( const char *keyword0,
const char *format, va_list ap )
{
return this->vassignf_value( this->index(keyword0), format, ap );
}
/**
* @brief 1つのヘッダレコードの値を更新 (低レベル・printf()の記法)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assignf_value( long index0, const char *format, ... )
{
if ( index0 < 0 || this->num_records_rec <= index0 ) {
err_report(__FUNCTION__,"WARNING","invalid index0");
}
else {
va_list ap;
va_start(ap,format);
try {
this->vassignf_value(index0,format,ap);
}
catch (...) {
va_end(ap);
err_throw(__FUNCTION__,"FATAL","this->vassignf_value() failed");
}
va_end(ap);
}
return *this;
}
/**
* @brief 1つのヘッダレコードの値を更新 (低レベル・printf()の記法)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assignf_value( const char *keyword0,
const char *format, ... )
{
va_list ap;
va_start(ap,format);
try {
this->vassignf_value(keyword0,format,ap);
}
catch (...) {
va_end(ap);
err_throw(__FUNCTION__,"FATAL","this->vassignf_value() failed");
}
va_end(ap);
return *this;
}
/* comment */
/**
* @brief 1つのヘッダレコードのコメントを更新 (printf()の記法)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::vassignf_comment( long index0, const char *format,
va_list ap )
{
tstring tstr;
fits::header_def rv = {NULL,NULL,NULL};
if ( index0 < 0 || this->num_records_rec <= index0 ) {
err_report(__FUNCTION__,"WARNING","invalid index0");
goto quit;
}
if ( format == NULL ) {
this->assign(index0,rv);
goto quit;
}
tstr.vassignf(format,ap);
rv.comment = tstr.cstr();
this->assign(index0,rv);
quit:
return *this;
}
/**
* @brief 1つのヘッダレコードのコメントを更新 (printf()の記法)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::vassignf_comment( const char *keyword0,
const char *format, va_list ap )
{
return this->vassignf_comment( this->index(keyword0), format, ap );
}
/**
* @brief 1つのヘッダレコードのコメントを更新 (printf()の記法)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assignf_comment( long index0, const char *format, ... )
{
if ( index0 < 0 || this->num_records_rec <= index0 ) {
err_report(__FUNCTION__,"WARNING","invalid index0");
return *this;
}
else {
va_list ap;
va_start(ap,format);
try {
this->vassignf_comment(index0,format,ap);
}
catch (...) {
va_end(ap);
err_throw(__FUNCTION__,"FATAL","this->vassignf_comment()");
}
va_end(ap);
return *this;
}
}
/**
* @brief 1つのヘッダレコードのコメントを更新 (printf()の記法)
*
* @note 自身が fits_hdu オブジェクトの管理下にある場合,Data Unit に関係する
* 予約キーワード(BITPIX 等)は指定できません.
*/
fits_header &fits_header::assignf_comment( const char *keyword0,
const char *format, ... )
{
va_list ap;
va_start(ap,format);
try {
this->vassignf_comment(keyword0,format,ap);
}
catch (...) {
va_end(ap);
err_throw(__FUNCTION__,"FATAL","this->vassignf_comment()");
}
va_end(ap);
return *this;
}
/*
*/
/* Overwrite all header comments with SFITSIO built-in comment strings */
/**
* @brief コメントの存在にかかわらず,現在のヘッダコメント辞書の内容で埋める
*
* 全てのヘッダレコードのうち,現在のコメント辞書とキーワードが一致する場合,
* それらのレコードのコメントを現在のコメント辞書が持つコメント文で上書きし
* ます.
*/
fits_header &fits_header::assign_default_comments( int hdutype )
{
long i;
for ( i=0 ; i < this->length() ; i++ ) {
if ( this->records_ptr_rec[i]->status() == FITS::NORMAL_RECORD ) {
this->records_ptr_rec[i]->assign_default_comment(hdutype);
}
}
return *this;
}
/* Fill all blank comments with SFITSIO built-in comment strings */
/**
* @brief コメントが存在しない場合,現在のヘッダコメント辞書の内容で埋める
*
* 全てのヘッダレコードのコメントが空白なものについて,現在のコメント辞書と
* キーワードが一致する場合,それらのレコードに現在のコメント辞書が持つ
* コメント文をセットします.
*/
fits_header &fits_header::fill_blank_comments( int hdutype )
{
long i;
for ( i=0 ; i < this->length() ; i++ ) {
if ( this->records_ptr_rec[i]->status() == FITS::NORMAL_RECORD &&
this->records_ptr_rec[i]->comment_length() == 0 ) {
this->records_ptr_rec[i]->assign_default_comment(hdutype);
}
}
return *this;
}
/*
*/
/**
* @brief fits_header_record オブジェクトへの参照を取得
*
* @note fits_header::at() との違いはありません.
*/
fits_header_record &fits_header::record( long index0 )
{
if ( index0 < 0 || this->num_records_rec <= index0 ) {
err_throw(__FUNCTION__,"ERROR","Invalid record index");
}
return *(this->records_ptr_rec[index0]);
}
/**
* @brief fits_header_record オブジェクトへの参照を取得
*
* @note fits_header::at() との違いはありません.
*/
fits_header_record &fits_header::record( const char *keyword0 )
{
long index0 = this->index(keyword0);
#if 1
if ( index0 < 0 ) {
this->append(keyword0);
index0 = this->index(keyword0);
}
#endif
if ( index0 < 0 ) {
err_throw1(__FUNCTION__,"ERROR","keyword '%s' is not found",keyword0);
}
return this->record( index0 );
}
#ifdef SLI__OVERLOAD_CONST_AT
/**
* @brief fits_header_record オブジェクトへの参照を取得 (読取専用)
*
* @note fits_header::at() との違いはありません.
*/
const fits_header_record &fits_header::record( long index0 ) const
{
return this->record_cs(index0);
}
/**
* @brief fits_header_record オブジェクトへの参照を取得 (読取専用)
*
* @note fits_header::at() との違いはありません.
*/
const fits_header_record &fits_header::record( const char *keyword0 ) const
{
return this->record_cs(keyword0);
}
#endif
/**
* @brief fits_header_record オブジェクトへの参照を取得 (読取専用)
*
* @note fits_header::at_cs() との違いはありません.
*/
const fits_header_record &fits_header::record_cs( long index0 ) const
{
if ( index0 < 0 || this->num_records_rec <= index0 ) {
err_throw(__FUNCTION__,"ERROR","Invalid record index");
}
return *(this->records_ptr_rec[index0]);
}
/**
* @brief fits_header_record オブジェクトへの参照を取得 (読取専用)
*
* @note fits_header::at_cs() との違いはありません.
*/
const fits_header_record &fits_header::record_cs( const char *keyword0 ) const
{
long idx = this->index(keyword0);
if ( idx < 0 ) {
err_throw1(__FUNCTION__,"ERROR","keyword '%s' is not found",keyword0);
}
return this->record_cs( idx );
}
/* same as fits_header::record() */
/**
* @brief fits_header_record オブジェクトへの参照を取得
*
* @note fits_header::record() との違いはありません.
*/
fits_header_record &fits_header::at( long index0 )
{
return this->record(index0);
}
/**
* @brief fits_header_record オブジェクトへの参照を取得
*
* @note fits_header::record() との違いはありません.
*/
fits_header_record &fits_header::at( const char *keyword0 )
{
return this->record(keyword0);
}
#ifdef SLI__OVERLOAD_CONST_AT
/**
* @brief fits_header_record オブジェクトへの参照を取得 (読取専用)
*
* @note fits_header::record() との違いはありません.
*/
const fits_header_record &fits_header::at( long index0 ) const
{
return this->record_cs(index0);
}
/**
* @brief fits_header_record オブジェクトへの参照を取得 (読取専用)
*
* @note fits_header::record() との違いはありません.
*/
const fits_header_record &fits_header::at( const char *keyword0 ) const
{
return this->record_cs(keyword0);
}
#endif
/**
* @brief fits_header_record オブジェクトへの参照を取得 (読取専用)
*
* @note fits_header::record_cs() との違いはありません.
*/
const fits_header_record &fits_header::at_cs( long index0 ) const
{
return this->record_cs(index0);
}
/**
* @brief fits_header_record オブジェクトへの参照を取得 (読取専用)
*
* @note fits_header::record_cs() との違いはありません.
*/
const fits_header_record &fits_header::at_cs( const char *keyword0 ) const
{
return this->record_cs(keyword0);
}
/*
* 読み取り
*/
/**
* @brief キーワードに対応するヘッダレコード番号を取得 (記述式レコードは除外)
*/
long fits_header::index( const char *keyword0 ) const
{
return this->index(keyword0,false);
}
/**
* @brief キーワードに対応するヘッダレコード番号を取得
*/
long fits_header::index( const char *keyword0, bool is_description ) const
{
long return_index = -1;
long i;
const char *str_beg;
size_t j,len;
char kwd[FITS::HEADER_KEYWORD_MAX_LENGTH + 1];
if ( keyword0 == NULL ) goto quit;
/* keyword0 の両サイドのスペースを除去 */
rm_side_spaces(keyword0," ",&str_beg,&len);
for ( j=0 ; j < FITS::HEADER_KEYWORD_MAX_LENGTH && j < len ; j++ ) {
kwd[j] = str_beg[j];
}
kwd[j] = '\0';
if ( is_description == true ) {
/* HISTORY とか COMMENT は単に前から検索するだけ */
for ( i=0 ; i < this->num_records_rec ; i++ ) {
if ( this->records_ptr_rec[i] != NULL &&
this->records_ptr_rec[i]->status() == FITS::DESCRIPTION_RECORD ) {
if ( this->records_ptr_rec[i]->keyword_cs().strcmp(kwd) == 0 ) {
return_index = i;
break;
}
}
}
}
else {
return_index = this->index_rec.index(kwd,0);
}
quit:
return return_index;
}
/**
* @brief POSIX拡張正規表現でキーワードを検索
*/
long fits_header::regmatch( const char *keypat,
ssize_t *rpos, size_t *rlen ) const
{
return this->regmatch(0L,keypat,rpos,rlen);
}
/**
* @brief POSIX拡張正規表現でキーワードを連続的に検索
*/
long fits_header::regmatch( long index0, const char *keypat,
ssize_t *rpos, size_t *rlen ) const
{
long i;
for ( i=index0 ; i < this->length() ; i++ ) {
ssize_t pos;
size_t len;
if ( this->record_cs(i).status() == FITS::NORMAL_RECORD ) {
pos = this->record_cs(i).arr_cs().at_cs(0L).regmatch(keypat,&len);
if ( 0 <= pos ) {
if ( rpos != NULL ) *rpos = pos;
if ( rlen != NULL ) *rlen = len;
return i;
}
}
}
return -1;
}
/* returns length of raw value. More than 0 means NON-NULL. */
/**
* @brief キーワードに対応する生の文字列値の長さを取得 (存在チェックに使用可)
*
* @param keyword ヘッダキーワード
* @return 正の値: 生の文字列値(「'」を含む)の長さ
* 0: 値が存在しない場合
* 負の値: キーワードが存在しない場合
*/
long fits_header::value_length( const char *keyword ) const
{
long idx = this->index(keyword, false);
if ( 0 <= idx ) return this->at_cs(idx).value_length();
else return -1;
}
/**
* @brief キーワードに対応する生の文字列値の長さを取得 (存在チェックに使用可)
*
* @param index レコード番号
* @return 正の値: 生の文字列値(「'」を含む)の長さ
* 0: 値が存在しない場合
* 負の値: キーワードが存在しない場合
*/
long fits_header::value_length( long index ) const
{
if ( 0 <= index && index < this->length() ) {
const fits_header_record &h_rec = this->at_cs(index);
if (h_rec.status() == FITS::NORMAL_RECORD) return h_rec.value_length();
else return -1;
}
else return -1;
}
#if 0
long fits_header::num_records()
{
return this->num_records_rec;
}
#endif
/**
* @brief ヘッダレコードの長さを取得
*/
long fits_header::length() const
{
return this->num_records_rec;
}
/**
* @brief ヘッダレコードの長さを取得
*
* @note fits_header::length() との違いはありません.
*/
long fits_header::size() const
{
return this->num_records_rec;
}
/**
* @brief ヘッダの情報から HDU のタイプを判定して返す
*/
int fits_header::hdutype() const
{
int htype = FITS::ANY_HDU;
if ( this->index("SIMPLE") == 0 ) {
htype = FITS::IMAGE_HDU;
}
else if ( this->index("XTENSION") == 0 ) {
const tstring &xtension = this->record(0L).svalue_cs();
if ( xtension.strcmp("IMAGE") == 0 ) {
htype = FITS::IMAGE_HDU;
}
else if ( xtension.strcmp("BINTABLE") == 0 ) {
htype = FITS::BINARY_TABLE_HDU;
}
else if ( xtension.strcmp("TABLE") == 0 ) {
htype = FITS::ASCII_TABLE_HDU;
}
}
return htype;
}
/**
* @brief Data Unit に関係する予約キーワード(BITPIX 等)かどうかを返す
*/
bool fits_header::is_sysrecord( long index ) const
{
if ( index < 0 || this->num_records_rec <= index ) return false;
if ( this->record_cs(index).status() == FITS::NORMAL_RECORD ) {
return is_header_reserved_key(this->record_cs(index).keyword());
}
else return false;
}
/**
* @brief CHECKSUM を計算して返す
*/
unsigned long fits_header::checksum( unsigned long sum_in )
{
fitsio_csum csum_info;
/* init */
initialize_csum( &csum_info, sum_in );
/* get chksum */
this->header_save( NULL, (void *)&csum_info, true );
return csum_info.sum;
}
/**
* @brief エンコードされた CHECKSUM を計算して返す
*/
const char *fits_header::encoded_checksum( unsigned long sum_in )
{
fitsio_csum csum_info;
/* init */
initialize_csum( &csum_info, sum_in );
/* get chksum */
this->header_save( NULL, (void *)&csum_info, true );
encode_csum( csum_info, this->encoded_chksum_rec );
return this->encoded_chksum_rec;
}
/**
* @brief 重複キーワードの警告に関する設定
*
* これを true にすると,重複したキーワードをセットしても警告を出さなく
* なります.
*/
bool &fits_header::suppress_dupkey_warning()
{
return this->suppress_dupkey_warning_rec;
}
/**
* @brief fits_header::expand_continue_records() で使用 (内部用)
*
* @note private な関数です.
*/
static bool is_continue_record( const fits_header_record &ref )
{
if ( ref.status() == FITS::DESCRIPTION_RECORD &&
ref.keyword_cs().strcmp("CONTINUE") == 0 &&
1 <= ref.value_cs().length() ) return true;
else return false;
}
/**
* @brief CONTINUE レコードを展開
*
* @attention ほとんど内部実装用で,プログラマは使う必要が無いメンバ関数です.
* @note fitsccからも使われる.
*/
fits_header &fits_header::expand_continue_records()
{
fits_header *target_header = this;
long j;
//fprintf(stderr,"debug: expanding CONTINUE\n");
/*
* SFITSIO 'CONTINUE' convension:
*
* - Basic Convension:
*
* FOO = 'aaaaaaaaaaaa & '
* CONTINUE 'bbbbbbbbbbb&' / this is
* CONTINUE '' / a looooooooooooooooong
* CONTINUE / comment.
*
* - NOTE
*
* Most easy way to generate header records with long string + long
* comment is that we reserve byte 79-80 for "&'" string in a
* header record. We show an example:
*
* 70 80
* 12345678901234567890 ... 01234567890
* KEYWORD = '......... ... .................&'
* CONTINUE '......... ... .................&'
* CONTINUE '......... ... .................&'
* CONTINUE / this is a comment.
*
* Note that "''" should not be put on 78th column:
*
* CONTINUE '......... ... ................'&' <= No good
* CONTINUE ''........ ... .................&' <= No good
*
*/
for ( j=1 ; j < target_header->length() ; j++ ) {
if ( is_continue_record(target_header->record(j)) ) {
const long j0 = j - 1; /* master record */
long n_erase;
bool prev_value_amp_exists = false;
bool prev_comment_amp_exists = false;
tstring long_value;
tstring long_comment;
const tstring &v0_ref = target_header->record(j0).value_cs();
/* 右側の空白は除去されている */
const tstring &c0_ref = target_header->record(j0).comment_cs();
size_t v0_len = v0_ref.length();
size_t c0_len = c0_ref.length();
//err_report1(__FUNCTION__,"DEBUG","key = [%s]",
// target_header->record(j0).keyword());
//err_report1(__FUNCTION__,"DEBUG","val = [%s]", v0_ref.cstr());
//err_report1(__FUNCTION__,"DEBUG","com = [%s]", c0_ref.cstr());
/* まずは,v0 を処理(最後の "'" をつけないで代入) */
if ( target_header->record(j0).type() == FITS::STRING_T ) {
size_t s_pos;
/*
* 値
*/
/* 2文字以下の場合は,1文字だけ採用するだけ */
if ( v0_len <= 2 ) {
long_value.append(v0_ref,0,1);
}
/* 3文字以上の場合は,最後の "'"," ","&" の処理が必要 */
else {
size_t r_spn;
s_pos = v0_len - 1;
/* 最後の '&' をチェック(これは認めるべきではないが) */
if ( v0_ref.cchr(s_pos) == '&' ) {
s_pos --;
}
/* スペースをチェック */
r_spn = v0_ref.strrspn(s_pos,' ');
s_pos -= r_spn;
/* 最後のクォーテーションをチェック */
if ( v0_ref.cchr(s_pos) == '\'' ) {
s_pos --;
}
/* さらに内側のスペースもチェック */
r_spn = v0_ref.strrspn(s_pos,' ');
s_pos -= r_spn;
/* 最後に & をチェック */
if ( v0_ref.cchr(s_pos) == '&' ) {
prev_value_amp_exists = true;
s_pos --;
}
long_value.append(v0_ref, 0, s_pos + 1);
}
/*
* コメント
*/
/* 最後の '&' をチェック */
s_pos = c0_len - 1;
//if ( c0_ref.cchr(s_pos) == '&' ) {
// s_pos --;
// prev_comment_amp_exists = true;
//}
long_comment.append(c0_ref, 0, s_pos + 1);
}
else {
size_t s_pos;
long_value.append(v0_ref);
/* 最後の '&' をチェック */
s_pos = c0_len - 1;
//if ( c0_ref.cchr(s_pos) == '&' ) {
// s_pos --;
// prev_comment_amp_exists = true;
//}
long_comment.append(c0_ref, 0, s_pos + 1);
}
//err_report1(__FUNCTION__,"DEBUG","l_v = [%s]",long_value.cstr());
//err_report1(__FUNCTION__,"DEBUG","l_c = [%s]",long_comment.cstr());
/* 続く CONTINUE 文を全部やってしまう */
/* (処理済みの CONTINUE レコードは削除する) */
n_erase = 0;
while ( j < target_header->length() &&
is_continue_record(target_header->record(j)) == true ) {
bool curr_comment_amp_exists = false;
/* ナマの値.ここでは左右の空白はそのまま */
const tstring &vref = target_header->record(j).value_cs();
size_t l_spn, r_spn;
bool next_is_continue;
/* 次も CONTINUE かどうか */
next_is_continue = ( j+1 < target_header->length() &&
is_continue_record(target_header->record(j+1)) == true );
/* 左右のスペースをチェック */
l_spn = vref.strspn(' ');
if ( vref.length() == l_spn ) r_spn = 0;
else {
r_spn = vref.strrspn(' ');
/* 次も CONTINUE の場合は '&' をチェック */
//if ( next_is_continue ) {
// if (vref.cchr(vref.length() - r_spn - 1) == '&') {
// r_spn ++;
// curr_comment_amp_exists = true;
// }
//}
}
if (target_header->record(j0).type() == FITS::STRING_T) {
size_t s_pos = l_spn;
/* 前から順に "'" を探していく */
if ( prev_value_amp_exists == true &&
vref.cchr(s_pos) == '\'' ) {
size_t v_begin; /* 文字列値の開始点 */
s_pos ++;
v_begin = s_pos;
while ( 1 ) {
ssize_t f_pos;
if ( (f_pos=vref.find(s_pos,'\'')) < 0 ) {
size_t v_len;
/* 終端の "'" が無い場合は,全部値にする */
v_len = vref.length() - v_begin;
/* 最後のスペースの消去 */
if ( r_spn <= v_len ) v_len -= r_spn;
/* 最後に "&" があったらそのままにしとく */
if ( curr_comment_amp_exists == true ) v_len ++;
long_value.append(vref, v_begin, v_len);
prev_value_amp_exists = false;
break;
}
if ( vref.cchr(f_pos+1) == '\'' ) {
/* 「''」のための処理 */
s_pos = f_pos+2;
/* while() へ戻る */
}
else {
/* comment 文字列を探す */
/* "/" or '&' を探して,ダメなら再度
while() に戻る */
s_pos = f_pos + 1;
/* '&' も探すが,本来は来てはいけない*/
s_pos += vref.strspn(s_pos,' ');
if ( s_pos == vref.length() ||
vref.cchr(s_pos) == '/' ||
vref.cchr(s_pos) == '&' ) {
/* ようやく合格 */
size_t s_spn, v_len, c_len;
if ( s_pos < vref.length() ) {
s_pos++;
s_pos += vref.strspn(s_pos,' ');
}
/* register comment */
c_len = vref.length() - s_pos;
/* 最後のスペースと '&' の消去 */
if ( r_spn <= c_len ) c_len -= r_spn;
if ( 0 < c_len ) {
if ( 0 < long_comment.length() &&
prev_comment_amp_exists == false ) {
long_comment.append(" ");
}
long_comment.append(vref,
s_pos, c_len);
}
/* register value */
s_spn = vref.strrspn(f_pos-1,' ');
/* 次も CONTINUE の場合は '&' をチェック */
prev_value_amp_exists = false; /* reset */
if ( next_is_continue ) {
if ( vref.cchr(f_pos-s_spn-1) == '&') {
prev_value_amp_exists = true;
s_spn++;
}
}
v_len = f_pos - s_spn - v_begin;
long_value.append(vref, v_begin,v_len);
break;
}
s_pos = f_pos+1;
/* while() へ戻る */
}
}
}
else {
size_t c_len;
/* 文字列と判定できない場合はコメントとして処理 */
c_len = vref.length() - l_spn - r_spn;
if ( 0 < c_len ) {
if ( 0 < long_comment.length() &&
prev_comment_amp_exists == false ) {
long_comment.append(" ");
}
/* 先頭に「/」があれば除去 */
if ( 2 <= c_len && vref.cchr(l_spn) == '/' &&
vref.cchr(l_spn + 1) == ' ' ) {
long_comment.append(vref, l_spn+2, c_len-2);
}
else if ( 1 <= c_len && vref.cchr(l_spn) == '/' ) {
long_comment.append(vref, l_spn+1, c_len-1);
}
else {
long_comment.append(vref, l_spn, c_len);
}
}
}
}
else {
size_t c_len;
/* 文字列型以外の場合は単にコメントとして処理 */
c_len = vref.length() - l_spn - r_spn;
if ( 0 < c_len ) {
if ( 0 < long_comment.length() &&
prev_comment_amp_exists == false ) {
long_comment.append(" ");
}
/* 先頭に「/」があれば除去 */
if ( 2 <= c_len && vref.cchr(l_spn) == '/' &&
vref.cchr(l_spn + 1) == ' ' ) {
long_comment.append(vref, l_spn+2, c_len-2);
}
else if ( 1 <= c_len && vref.cchr(l_spn) == '/' ) {
long_comment.append(vref, l_spn+1, c_len-1);
}
else {
long_comment.append(vref, l_spn, c_len);
}
}
}
/* count CONTINUE records to erase */
n_erase ++;
j ++ ;
prev_comment_amp_exists = curr_comment_amp_exists;
} /* while ( ) ... */
/* 文字列値の場合は,最後の "'" を追加 */
if ( target_header->record(j0).type() == FITS::STRING_T ) {
long_value.append("'");
}
//err_report1(__FUNCTION__,"DEBUG","length of long_value = [%d]",
// (int)(long_value.length()));
//err_report1(__FUNCTION__,"DEBUG","long_value = [%s]",
// long_value.cstr());
//err_report1(__FUNCTION__,"DEBUG","long_comment = [%s]",
// long_comment.cstr());
//err_report1(__FUNCTION__,"DEBUG","%s","========");
/* オリジナルの 80-char を保存し,値を更新 */
{
fits_header_record &rec_j0 = target_header->at(j0);
tstring a_formatted_rec_bak;
long i;
/* a_formatted_rec をバックアップ */
a_formatted_rec_bak = rec_j0.a_formatted_rec;
/* 値を更新 (a_formatted_rec は消去される) */
target_header->assignf_comment(j0, "%s",long_comment.cstr());
target_header->assignf_value(j0, "%s", long_value.cstr());
/* fitscc から使われた場合,オリジナルの 80-char はない */
if ( a_formatted_rec_bak.cstr() != NULL ) {
/* 80 x n 文字の a_formatted_rec を保存 */
rec_j0.a_formatted_rec
.resize(FITS::HEADER_RECORD_UNIT * (1 + n_erase));
rec_j0.a_formatted_rec.put(0, a_formatted_rec_bak);
for ( i=0 ; i < n_erase ; i++ ) {
rec_j0.a_formatted_rec.put(
FITS::HEADER_RECORD_UNIT * (1 + i),
target_header->at(j0 + 1 + i).a_formatted_rec);
}
}
}
/* erase CONTINUE records */
target_header->erase_records(j0 + 1, n_erase);
/* important! */
j = j0;
} /* if ( is_continue_record(...) ) ... */
}
return *this;
}
/**
* @brief shallow copy を許可する場合に使用 (未実装)
* @note 一時オブジェクトの return の直前で使用する.
*/
/* 注意: 参照を返したいところだが,return 文でそれをやるとインスタンス */
/* を2回コピーされるというおかしな事になるので void になっている */
void fits_header::set_scopy_flag()
{
this->shallow_copy_ok = true;
return;
}
/*
* protected member functions
*/
/**
* @brief fits_header_record オブジェクトのアドレスを返す
*
* @note このメンバ関数は protected です.
*/
fits_header_record *fits_header::get_ptr( long index0 )
{
if ( index0 < 0 || this->num_records_rec <= index0 ) {
return NULL;
}
else return this->records_ptr_rec[index0];
}
/**
* @brief 指定されたヘッダレコードオブジェクトのアドレスを返す
*
* @note ユーザの拡張クラスで使用を想定.ポインタを張る場合に必要.
* このメンバ関数は protected です.
*/
fits_header_record *fits_header::get_ptr( const char *keyword0 )
{
return this->get_ptr( this->index(keyword0,false) );
}
/**
* @brief 指定されたヘッダレコードの保護に関する設定
*
* @note ポインタを張った時,消えないように保護するために必要.
* このメンバ関数は protected です.
*/
fits_header &fits_header::set_protections( long index0, bool keyword, bool value_type,
bool value, bool comment )
{
fits_header_record *sys_ptr;
sys_ptr = this->get_ptr(index0);
if ( sys_ptr == NULL ) {
err_report(__FUNCTION__,"WARNING","invalid index0; ignored");
return *this;
}
//bool tf = sys_ptr->keyword_protected_rec;
sys_ptr->set_protections(keyword,value_type,value,comment);
return *this;
}
/**
* @brief 自身を管理するためのオブジェクトを登録
*
* @note fits_hdu のコンストラクタで使用.
* このメンバ関数は protected です.
*/
fits_header &fits_header::register_manager( fits_hdu *ptr )
{
this->manager = ptr;
return *this;
}
/* fits_hdu から使う */
/**
* @brief Data Unit に関連するヘッダレコードの編集禁止フラグをセット
*
* true をセットすると,システム予約キーワードは登録不可になる.
*
* @note 継承クラスでシステムキーワードを書き込む場合に使用.
* このメンバ関数は protected です.
*/
fits_header &fits_header::set_sysrecords_prohibition( bool value )
{
this->sysrecords_prohibition_rec = value;
return *this;
}
/**
* @brief ストリームにアクセスし,Data Unit を読み飛ばす
*
* @param sref 読み飛ばし対象のストリーム (cstreamioの継承クラス)
* @param max_bytes_ptr 読み飛ばされるべき最大のバイト数.設定不要時はNULL.
* @return 非負値: 読み飛ばしたバイト数
* 負値: エラー
* @note このメンバ関数は private です.
*/
ssize_t fits_header::data_skip( cstreamio &sref, const size_t *max_bytes_ptr )
{
ssize_t return_len_skip = -1;
size_t len_data_part, len_all, len_skiped_all;
size_t len_to_skip[3];
long naxis;
long bytepix;
long idx,i;
int hdu_type;
bool extend = true;
hdu_type = this->hdutype();
if ( 0 <= this->index("SIMPLE") ) {
idx = this->index("EXTEND");
if ( 0 <= idx ) extend = this->record(idx).bvalue();
}
/* normal data area */
idx = this->index("BITPIX");
if ( idx < 0 ) goto quit;
bytepix = this->record(idx).llvalue();
if ( bytepix == 0 ) {
return_len_skip = 0;
goto quit;
}
if ( bytepix < 0 ) bytepix *= -1;
bytepix--;
bytepix /= 8;
bytepix++;
idx = this->index("NAXIS");
if ( idx < 0 ) goto quit;
naxis = this->record(idx).llvalue();
if ( naxis < 0 ) goto quit;
if ( naxis == 0 ) {
return_len_skip = 0;
goto quit;
}
len_to_skip[0] = bytepix;
for ( i=0 ; i < naxis ; i++ ) {
tstring kwd;
long long llv;
kwd.assignf("NAXIS%ld",i+1);
idx = this->index(kwd.cstr());
if ( idx < 0 ) goto quit;
llv = this->record(idx).llvalue();
if ( 0 <= llv ) len_to_skip[0] *= llv;
}
/* heap area of binary table HDU */
len_to_skip[1] = 0;
idx = this->index("PCOUNT");
if ( hdu_type == FITS::BINARY_TABLE_HDU && 0 <= idx ) {
long long llv;
llv = this->record(idx).llvalue();
if ( 0 <= llv ) len_to_skip[1] += llv;
}
if ( len_to_skip[0] == 0 && len_to_skip[1] == 0 ) {
return_len_skip = 0;
goto quit;
}
len_data_part = len_to_skip[0] + len_to_skip[1];
/* 2880 の倍々にする */
if ( len_data_part % FITS::FILE_RECORD_UNIT != 0 ) {
len_to_skip[2] =
FITS::FILE_RECORD_UNIT - (len_data_part % FITS::FILE_RECORD_UNIT);
}
len_all = len_to_skip[0] + len_to_skip[1] + len_to_skip[2];
/* max_bytes_ptr != NULL の制限処置 */
if ( max_bytes_ptr != NULL ) {
if ( (*max_bytes_ptr) < len_to_skip[0] ) {
len_to_skip[0] = (*max_bytes_ptr);
len_to_skip[1] = 0;
len_to_skip[2] = 0;
}
else if ( (*max_bytes_ptr) < len_data_part ) {
len_to_skip[1] = (*max_bytes_ptr) - len_to_skip[0];
len_to_skip[2] = 0;
}
else if ( (*max_bytes_ptr) < len_all ) {
len_to_skip[2] = (*max_bytes_ptr) - len_data_part;
}
}
/* EXTEND = F の場合で最後が 0 でパディングされていない場合も考え, */
/* len_to_skip[0], len_to_skip[1], len_to_skip[2] の順にskipする */
len_skiped_all = 0;
for ( i=0 ; i < 3 ; i++ ) {
size_t len_skiped = 0;
if ( 0 < len_to_skip[i] ) {
ssize_t sz;
/* Use seek when available :-) */
try {
sz = sref.rskip(len_to_skip[i]);
}
catch (...) {
err_throw(__FUNCTION__,"FATAL","unexpected exception");
}
if ( i == 2 && extend == false && sz == 0 ) {
/* EXTEND = F の場合で 0 パディングが無い場合: OK */
len_skiped = sz;
}
else if ( sz < 0 ) {
err_report(__FUNCTION__,"ERROR","sref.rskip() failed");
goto quit;
}
else if ( (size_t)sz != len_to_skip[i] ) {
err_report(__FUNCTION__,"ERROR","sref.rskip() failed");
goto quit;
}
else {
len_skiped = sz;
}
}
len_skiped_all += len_skiped;
}
//err_report1(__FUNCTION__,"DEBUG","len_skiped_all = %zd",len_skiped_all);
return_len_skip = len_skiped_all;
quit:
return return_len_skip;
}
/* Update: 2011/11/23 */
/**
* @brief ストリームから FITS ヘッダを読み込み,ヘッダオブジェクトを構成
*
* @param sref 読み込み対象のストリーム (cstreamioの継承クラス)
* @param max_bytes_ptr 読み込まれるべき最大のバイト数.設定不要時はNULL.
* @return 非負値: 読み込んだバイト数
* 負値: エラー
* @note 次の HDU があるかないかをチェックする場合にも使われる.
* このメンバ関数は private です.
*/
ssize_t fits_header::header_load(cstreamio &sref, const size_t *max_bytes_ptr)
{
ssize_t return_len_read = -1;
size_t len_read_all = 0;
bool flag_end = false;
char rec_buf[FITS::HEADER_RECORD_UNIT + 1];
tstring rec_str, header_all;
long rec_index = 0;
rec_buf[FITS::HEADER_RECORD_UNIT] = '\0';
/* initialize; erase all header records */
this->fits_header::_init();
/* read header records one by one ... */
while ( 1 ) {
ssize_t len_read;
/* END が見つかっていて,ピッタリの場合はループ抜け */
if ( flag_end == true ) {
if ( len_read_all % FITS::FILE_RECORD_UNIT == 0 ) break;
}
/* 読めるバイト数に制限がある場合のチェック */
if ( max_bytes_ptr != NULL ) {
if ( (*max_bytes_ptr) < len_read_all + FITS::HEADER_RECORD_UNIT ) {
/* 中途半端の場合は許されているとこまで読みきってしまう */
try {
len_read = sref.read(rec_buf, (*max_bytes_ptr) - len_read_all);
}
catch (...) {
err_throw(__FUNCTION__,"FATAL","unexpected exception");
}
if ( len_read < 0 ) {
err_report(__FUNCTION__,"ERROR","sref.read() failed");
goto quit;
}
len_read_all += len_read;
break;
}
}
/* read stream ... */
try {
len_read = sref.read(rec_buf, FITS::HEADER_RECORD_UNIT);
}
catch (...) {
err_throw(__FUNCTION__,"FATAL","unexpected exception");
}
if ( len_read < 0 ) {
err_report1(__FUNCTION__,"ERROR",
"sref.read() failed: len_read=%zd",len_read);
goto quit;
}
len_read_all += len_read;
if ( len_read != (ssize_t)FITS::HEADER_RECORD_UNIT ) break; /* EOF */
/* store a record to temp buffer */
rec_str.import_binary(rec_buf, len_read, ' ');
if ( flag_end == false ) {
/* When END is detected,set flag_end = true */
if ( rec_str.strncmp("END",3) == 0 &&
rec_str.strspn(3," \t\n\r\f\v") == FITS::HEADER_RECORD_UNIT - 3 ) {
flag_end = true;
}
}
/* append a record to header buffer */
if (header_all.length() < (rec_index + 1)*FITS::HEADER_RECORD_UNIT) {
if ( header_all.length() < FITS::FILE_RECORD_UNIT * 10 ) {
header_all.resizeby(FITS::FILE_RECORD_UNIT * 10);
} else {
header_all.resizeby( header_all.length() );
}
}
header_all.put(rec_index * FITS::HEADER_RECORD_UNIT, rec_str);
rec_index ++;
}
header_all.resize(rec_index * FITS::HEADER_RECORD_UNIT);
//err_report1(__FUNCTION__,"DEBUG","hdr length = %zd",header_all.length());
//err_report1(__FUNCTION__,"DEBUG","cstr = [%s]",header_all.cstr());
return_len_read = this->header_load(header_all.cstr());
quit:
return return_len_read;
}
/* Update: 2011/11/23 */
/**
* @brief 全ヘッダレコードを含んだ文字列を読み込み,ヘッダオブジェクトを構成
*
* @param header_all ヘッダの内容 ('\0' で終端した文字列)
* @note このメンバ関数は private です.
*/
ssize_t fits_header::header_load( const char *header_all )
{
ssize_t return_len_read = -1;
size_t len_read_all = 0;
bool flag_end = false;
tstring rec_str(FITS::HEADER_RECORD_UNIT); /* fixed-length mode */
long rec_index = 0;
/* initialize; erase all header records */
this->fits_header::_init();
/* read header records one by one ... */
while ( 1 ) {
ssize_t len_read;
if ( header_all == NULL ) break;
if ( flag_end == true ) {
if ( len_read_all % FITS::FILE_RECORD_UNIT == 0 ) break;
}
rec_str.assign(header_all + rec_index * FITS::HEADER_RECORD_UNIT,
FITS::HEADER_RECORD_UNIT);
len_read = rec_str.length();
len_read_all += len_read;
if ( len_read != (ssize_t)FITS::HEADER_RECORD_UNIT ) break; /* EOF */
if ( flag_end == false ) {
/* When END is detected,set flag_end = true */
if ( rec_str.strncmp("END",3) == 0 &&
rec_str.strspn(3," \t\n\r\f\v") == FITS::HEADER_RECORD_UNIT - 3 ) {
flag_end = true;
}
}
if ( flag_end == false ) {
fits_header_record a_record;
/* parse a line (private/parse_a_header_record.cc) */
if ( parse_a_header_record(rec_str, false, &a_record) < 0 ) {
if ( rec_index == 0 ) {
err_report(__FUNCTION__,"ERROR",
"This is not FITS header!");
goto quit;
}
}
/* オリジナルの 80-char を保存 */
a_record.a_formatted_rec = rec_str;
/* 追加 */
this->append( a_record );
}
rec_index ++;
}
//err_report(__FUNCTION__,"DEBUG","1st step parse end");
if ( this->length() < 1 ) {
return_len_read = len_read_all;
goto quit;
}
else {
/* CONTINUE を展開する */
this->expand_continue_records();
}
#if 0
for ( i=0 ; i < this->length() ; i++ ) {
fprintf(stderr,"debug1: [%s] = [%s] / [%s]\n",
this->record(i).keyword(),
this->record(i).value(),
this->record(i).comment());
}
#endif
//err_report(__FUNCTION__,"DEBUG","2st step parse end");
return_len_read = len_read_all;
quit:
return return_len_read;
}
/**
* @brief ヘッダの内容をストリームへ書き出す
*
* @note 注意: ここではチェックサムは初期化されない.呼び出し側で初期化する
* 事.
* このメンバ関数は private です.
*/
ssize_t fits_header::header_save( cstreamio *sptr, void *c_sum_info,
bool end_and_blank )
{
ssize_t return_size = -1;
size_t size_all = 0;
fitsio_csum *csum_info = (fitsio_csum *)c_sum_info;
ssize_t len;
if ( csum_info != NULL && end_and_blank == false ) {
err_report(__FUNCTION__,"WARNING",
"Invalid end_and_blank arg; ignored");
end_and_blank = true;
}
/* write formatted string to stream */
this->formatted_string();
len = this->formatted_rec.length();
if ( 0 < len ) {
ssize_t len_wrote;
try {
len_wrote = write_stream_or_get_csum( this->formatted_rec.cstr(),
len, sptr, csum_info );
}
catch (...) {
err_throw(__FUNCTION__,"FATAL",
"unexpected exception in write_stream_or_get_csum()");
}
if ( len_wrote != len ) {
err_report(__FUNCTION__,"ERROR",
"write_stream_or_get_csum() failed");
goto quit;
}
size_all += len;
}
/* write "END" string and white space to make total length 2880 x N */
if ( 0 < len && end_and_blank == true ) {
tstring tmp_str;
size_t block;
ssize_t len_wrote;
len = FITS::HEADER_RECORD_UNIT;
/* END を書く */
tmp_str.assign("END");
tmp_str.append(' ',len - 3);
try {
len_wrote = write_stream_or_get_csum( tmp_str.cstr(), len,
sptr, csum_info );
}
catch (...) {
err_throw(__FUNCTION__,"FATAL",
"unexpected exception in write_stream_or_get_csum()");
}
if ( len_wrote != len ) {
err_report(__FUNCTION__,"ERROR",
"write_stream_or_get_csum() failed");
goto quit;
}
size_all += len;
block = 1 + (size_all - 1) / FITS::FILE_RECORD_UNIT;
tmp_str.assign(' ',len);
while ( size_all < block * FITS::FILE_RECORD_UNIT ) {
try {
len_wrote = write_stream_or_get_csum( tmp_str.cstr(), len,
sptr, csum_info );
}
catch (...) {
err_throw(__FUNCTION__,"FATAL",
"unexpected exception in write_stream_or_get_csum()");
}
if ( len_wrote != len ) {
err_report(__FUNCTION__,"ERROR",
"write_stream_or_get_csum() failed");
goto quit;
}
size_all += len;
}
#if 0
try {
if ( 0 < size_all && sptr != NULL ) sptr->flush();
}
catch (...) {
err_throw(__FUNCTION__,"FATAL",
"unexpected exception in sptr->flush()");
}
#endif
}
return_size = size_all;
quit:
return return_size;
}
/**
* @brief shallow copy が可能かを返す (未実装)
*
* @return shallow copyが可能なら真
* それ以外の時は偽
* @note このメンバ関数は private です
*/
bool fits_header::request_shallow_copy( fits_header *from_obj ) const
{
return false;
}
/**
* @brief shallow copy をキャンセルする (未実装)
*
* @note このメンバ関数は private です
*/
void fits_header::cancel_shallow_copy( fits_header *from_obj ) const
{
return;
}
/**
* @brief 自身について,shallow copy 関係のクリーンアップを行なう (未実装)
*
* @note このメンバ関数は private です
*/
void fits_header::cleanup_shallow_copy( bool do_deep_copy_for_this ) const
{
return;
}
#include "private/parse_a_header_record.cc"
#include "private/initialize_csum.cc"
#include "private/encode_csum.cc"
#include "private/write_stream_or_get_csum.cc"
} /* namespace sli */
#include "private/rm_side_spaces.c"
#include "private/c_memcpy.cc"