Basic Image AlgorithmS Library 2.8.0

MetaData.cpp

00001 /* 
00002 This file is part of the BIAS library (Basic ImageAlgorithmS).
00003 
00004 Copyright (C) 2003-2009    (see file CONTACT for details)
00005   Multimediale Systeme der Informationsverarbeitung
00006   Institut fuer Informatik
00007   Christian-Albrechts-Universitaet Kiel
00008 
00009 
00010 BIAS is free software; you can redistribute it and/or modify
00011 it under the terms of the GNU Lesser General Public License as published by
00012 the Free Software Foundation; either version 2.1 of the License, or
00013 (at your option) any later version.
00014 
00015 BIAS is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU Lesser General Public License for more details.
00019 
00020 You should have received a copy of the GNU Lesser General Public License
00021 along with BIAS; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 */
00024 
00025 
00026 #include <iostream>
00027 #include "MetaData.hh"
00028 #include <Base/Debug/Error.hh>
00029 #include <cstring>
00030 
00031 using namespace BIAS;
00032 using namespace std;
00033 
00034 // #define DEBUG_METADATA
00035 
00036 ////////////////////////////////////////////////////////////////////////
00037 // AppData
00038 ///////////////////////////////////////////////////////////////////////
00039 
00040 AppData::AppData() 
00041 {
00042   data = NULL;
00043   Clear();
00044 }
00045 
00046 AppData::~AppData() 
00047 { 
00048   if (data != NULL) { delete[] data; data = NULL; } 
00049 }
00050 
00051 AppData::AppData(const AppData& app) 
00052 {
00053   data = NULL;
00054   (*this) = app;
00055 }
00056 
00057 AppData& AppData::operator=(const AppData& app)
00058 {
00059   tag = app.tag;
00060   length = app.length;
00061   stag = app.stag;
00062   sdata = app.sdata;
00063   if (data != NULL) delete[] data;
00064   if (length>0) {
00065     data = new char[length];
00066     memcpy(data, app.data, length);
00067   }
00068   else data = NULL;
00069   return (*this);
00070 }
00071 
00072 void AppData::Clear()
00073 {
00074   tag=MD_Invalid;
00075   if (data) delete[] data; data=NULL;
00076   data=NULL; 
00077   length=0;
00078   stag=sdata="";
00079 }
00080 
00081 int AppData::CheckFormat()
00082 {
00083   //cerr <<"checking meta data format for "<<stag<<" sdata\n";
00084   if (tag==MD_USE_ASCII){
00085     string::size_type pos;
00086     string::size_type last=sdata.length()-1;
00087  
00088     //cerr << "checking sdata\n";
00089     
00090     // check if sdata contains only \n followed by '#'
00091     pos=0;
00092     while ((pos=sdata.find('\n', (pos==0)?0:pos+1))!=string::npos){
00093       if (pos==last || sdata[pos+1]!='#'){
00094         BIASERR("there should be no CR without an immediatly following '#' in "
00095                 <<"ascii meta data "<<sdata);
00096         return -1;
00097       }
00098     };
00099     // check if sdata only contains '#' with a leading '\n'
00100     pos=0;
00101     while ((pos=sdata.find('#', (pos==0)?0:pos+1))!=string::npos){
00102       if (pos==0 || sdata[pos-1]!='\n'){
00103         BIASERR("there should be no '#' without a leading CR in "
00104                 <<"ascii meta data\nthe first '#' is added automatically "
00105                 <<stag<<endl<<sdata<<" "<<pos);
00106         return -2;
00107       }
00108     }
00109   
00110     //cerr << "checking stag\n";
00111     last=stag.length()-1;
00112     if (last<3){
00113       BIASERR("stag too short, stag should look like this: "
00114               <<"'#[a tag]': "<<last+1<<" "<<stag);
00115       return -3;
00116     }
00117     if (stag[0]!='#'){
00118       BIASERR("wrong stag format, stag should start with '#[' "<<stag);
00119       return -4;
00120     }
00121     if (stag[1]!='['){
00122       BIASERR("wrong stag format, stag should start with '#[' "<<stag);
00123       return -5;
00124     }
00125     if (stag[last]!=']'){
00126       BIASERR("wrong stag format, stag should end with ']' "<<stag);
00127       return -6;
00128     }
00129   } else {
00130     if (stag!="" || sdata!=""){
00131       BIASERR("stag or sdata is set but tag is not MD_USE_ASCII");
00132       return -7;
00133     }
00134     if (length<0){
00135       BIASERR("invalid length "<<length);
00136       return -8;
00137     }
00138   }
00139   //cerr << "CheckFormat finished\n";
00140   return 0;
00141 }
00142 
00143 ostream& BIAS::operator<<(ostream& os, const AppData::TAppData& ta)
00144 {
00145   switch(ta){
00146   case AppData::MD_PMatrix: 
00147     os << "MD_PMatrix ("<<(int)AppData::MD_PMatrix<<")"; break;
00148   case AppData::MD_Orientation: 
00149     os << "MD_Orientation ("<<(int)AppData::MD_Orientation<<")"; break;
00150   case AppData::MD_TimeStamp:
00151     os << "MD_TimeStamp ("<<(int)AppData::MD_TimeStamp<<")"; break;
00152   case AppData::MD_PTU_Data: 
00153     os << "MD_PTU_Data ("<<(int)AppData::MD_PTU_Data<<")"; break;
00154   case AppData::MD_Inertial_Sensor: 
00155     os << "MD_Inertial_Sensor ("<<(int)AppData::MD_Inertial_Sensor<<")"; break;
00156   case AppData::MD_ASCII_DATA: 
00157     os << "MD_ASCII_DATA ("<<(int)AppData::MD_ASCII_DATA<<")"; break;
00158   case AppData::MD_RMatrix: 
00159     os << "MD_RMatrix ("<<(int)AppData::MD_RMatrix<<")"; break;
00160   case AppData::MD_KMatrix: 
00161     os << "MD_KMatrix ("<<(int)AppData::MD_KMatrix<<")"; break;
00162   case AppData::MD_CVector: 
00163     os << "MD_CVector ("<<(int)AppData::MD_CVector<<")"; break;
00164   case AppData::MD_HomgPoint2D: 
00165     os << "MD_HomgPoint2D ("<<(int)AppData::MD_HomgPoint2D<<")"; break;
00166   case AppData::MD_Invalid: 
00167     os << "MD_Invalid ("<<(int)AppData::MD_Invalid<<")"; break;
00168   case AppData::MD_UUID: 
00169     os << "MD_UUID ("<<(int)AppData::MD_UUID<<")"; break;
00170   case AppData::MD_USE_ASCII: 
00171     os << "MD_USE_ASCII ("<<(int)AppData::MD_USE_ASCII<<")"; break;
00172   case AppData::MD_Focal_Length: 
00173     os << "MD_Focal_Length ("<<(int)AppData::MD_Focal_Length<<")"; break;
00174   default: os <<"unknown TAppData.tag: "<<(int)ta; break;
00175   }
00176   return os;
00177 }
00178 
00179 ostream& BIAS::operator<<(ostream& os, const AppData& ad)
00180 {
00181   if (ad.tag!=AppData::MD_USE_ASCII){
00182 #ifdef DEBUG_METADATA
00183     cerr << "writing binary: "<<ad.tag<<" length "<<ad.length
00184          << "   at pos: "<<(int)os.tellp()<<endl;
00185 #endif
00186     os.write((char*)&ad.tag, sizeof(AppData::TAppData));
00187     os.write((char*)&ad.length, sizeof(int));
00188     os.write(ad.data, ad.length);
00189   } else {
00190 #ifdef DEBUG_METADATA
00191     cerr << "writing ascii: "<< ad.stag << "\n# "<<ad.sdata;
00192     cerr<<"read binary AppData, type: "<<ad.tag<<" length: "<<ad.length<<endl;
00193     cout << "length "<<ad.sdata.length();
00194     if (ad.sdata.length()>0)
00195       cout <<"  first "<<ad.sdata.c_str()[0];
00196     cout <<endl;
00197       cout << "tag: '"<< ad.stag <<"'\ndata : '"<< ad.sdata<<"'\n";
00198 #endif
00199     if (ad.sdata.length()>0 && ad.sdata.c_str()[0]=='#'){
00200       os << ad.stag << "\n"<<ad.sdata;
00201     } else {
00202       os << ad.stag << "\n# "<<ad.sdata;
00203 #ifdef DEBUG_METADATA
00204       cout << "added #\n";
00205 #endif
00206     }
00207   }
00208   return os;
00209 }
00210 
00211 #define MD_LINE_LENGTH 4096
00212 
00213 istream& BIAS::operator>>(istream& is, AppData& ad)
00214 {
00215   char id[2]={' ',' '};
00216   is.read(id, 2*sizeof(char));
00217   if (is.fail() && is.eof()){
00218     return is;
00219   }
00220   is.putback(id[1]);// Since OpenSuse 12.2 'putback' seems to unset the eof bit
00221   is.putback(id[0]);// even when 0 bytes were read
00222   if (id[0]=='#' && id[1]=='[') { // ascii data
00223     ad.tag=AppData::MD_USE_ASCII;
00224     // read stag
00225     char c;
00226     char line[MD_LINE_LENGTH];
00227     do {
00228       is.get(c);
00229       ad.stag+=c;
00230     } while (c!=']');
00231     is.getline(line, MD_LINE_LENGTH);
00232     string checkString(line);
00233     if(checkString.size() == MD_LINE_LENGTH) {
00234       BIASERR("you supposedly ran out of line length!");
00235       BIASABORT;
00236     }
00237     //cout << "line: "<<line<<endl;
00238     ad.sdata+=line;
00239     ad.sdata+="\n";
00240     // read sdata
00241     do {
00242       if (is.peek()!='#') break;
00243       is.read(line, 2);
00244       if (line[0]=='#' && line[1]=='[') {
00245         is.putback(line[1]);
00246         is.putback(line[0]);
00247         break; 
00248       } 
00249       is.putback(line[1]);
00250       is.putback(line[0]);
00251       is.getline(line, MD_LINE_LENGTH);
00252       //cout << "line: "<<line<<endl;
00253       ad.sdata+=line;
00254       ad.sdata+="\n";
00255     } while (is);
00256     if (ad.stag!="#[PTU Data]" && ad.stag!="#[Inertial Sensor]"){
00257       //cerr << " now removing whitespace from "<<ad.stag<<endl;
00258       // now remove leading '#', CRs, and whitespace
00259       while (ad.sdata.length()>0 && (ad.sdata[0]=='#' || ad.sdata[0]==' ' ||
00260                                      ad.sdata[0]=='\n'))
00261         ad.sdata.erase(0, 1);
00262     } else {
00263       while (ad.sdata.length()>0 && (ad.sdata[0]==' ' || ad.sdata[0]=='\n'))
00264         ad.sdata.erase(0, 1);
00265     }
00266     // remove appended CRs
00267     while (ad.sdata[ad.sdata.length()-1]=='\n')
00268       ad.sdata.erase(ad.sdata.length()-1, 1);
00269 #ifdef DEBUG_METADATA
00270     cerr << "read ascii AppData : stag: "<<ad.stag<<"\t:"<<ad.sdata<<endl;
00271 #endif
00272   } else { // binary data
00273 #ifdef BIAS_DEBUG
00274     if (is.peek()=='#'){
00275       BIASERR("this image contains probably MetaData in old format"
00276               <<"\n use '/usr/net/bin/convasciidata' to convert it");
00277 #if __GNU_C__  < 3
00278       is.setstate(ios::badbit | ios::failbit);
00279 #else
00280       is.setstate(ios_base::badbit | ios_base::failbit);
00281 #endif
00282       return is;
00283     }
00284 #endif
00285 #ifdef DEBUG_METADATA
00286     cerr<<"read binary AppData at pos: "<<(int)is.tellg()<<endl;
00287 #endif
00288     ad.stag="";
00289     ad.sdata="";
00290     is.read((char*)&ad.tag, sizeof(ad.tag));
00291     if (!is) return is;
00292     
00293     is.read((char*)&ad.length, sizeof(ad.length));
00294     if (!is) return is;
00295     
00296 #ifdef DEBUG_METADATA
00297     cerr<<"read binary AppData, type: "<<ad.tag<<" length: "<<ad.length<<endl;
00298 #endif
00299     char *data = new char[ad.length];
00300     is.read(data, ad.length);
00301     ad.data = data;
00302   }
00303   return is;
00304 }
00305 
00306 ////////////////////////////////////////////////////////////////////////
00307 // MetaData
00308 ///////////////////////////////////////////////////////////////////////
00309 
00310 MetaData::MetaData() //: Debug()
00311   : vector<AppData>()
00312 {}
00313 
00314 MetaData::~MetaData()
00315 {}
00316 
00317 void MetaData::Add(enum AppData::TAppData ID, unsigned int length, char *data)
00318 {
00319   AppData ad;
00320   if (Find(ID, ad)>=0)
00321     Delete(ID);
00322   ad.Clear();
00323   ad.tag=ID;
00324   ad.length=length;
00325   ad.data=new char[ad.length];
00326   memcpy(ad.data, data, ad.length);
00327   push_back(ad);
00328 }
00329 
00330 void MetaData::Add(AppData& ad)
00331 {
00332   AppData ad2;
00333   if (ad.tag==AppData::MD_USE_ASCII){
00334     if (Find(ad.stag, ad2)>=0)
00335       Delete(ad.stag);
00336 #ifdef BIAS_DEBUG
00337     ad.CheckFormat();
00338 #endif
00339     push_back(ad);
00340   } else {
00341     if (Find(ad.tag, ad2)>=0)
00342       Delete(ad.tag);
00343     push_back(ad);
00344   }
00345 }
00346 
00347 void MetaData::Add(const string &tag, const string& data)
00348 {
00349   AppData ad;
00350   if (Find(tag, ad)>=0)
00351     Delete(tag);
00352   ad.Clear();
00353   ad.tag=AppData::MD_USE_ASCII;
00354   ad.stag=tag;
00355   ad.sdata=data;
00356 #ifdef BIAS_DEBUG
00357   ad.CheckFormat();
00358 #endif
00359   push_back(ad);
00360 }
00361 
00362 
00363 int MetaData::Find(const AppData::TAppData tag, AppData &data) const
00364 {
00365   MetaData::const_iterator it;
00366   int i;
00367   bool ascii_present=false;
00368   for (i=0, it=begin(); it!=end(); it++, i++){
00369     if ((*it).tag == AppData::MD_USE_ASCII) ascii_present=true;
00370     if ((*it).tag == tag) {
00371       data = (*it);
00372       return i;
00373     }
00374   }
00375   // not found yet
00376   data.Clear();
00377   if (ascii_present)
00378     return -2;
00379   else 
00380     return -1;
00381   //return -5; // just to please the compiler. NO, unreachable... (jw) 
00382 }
00383 
00384 int MetaData::Find(const string &tag, AppData &data) const
00385 {   
00386   MetaData::const_iterator it;
00387   int i;
00388   bool binary_present=false;
00389   for (i=0, it=begin(); it!=end(); it++, i++){
00390     if ((*it).tag != AppData::MD_USE_ASCII && 
00391         (*it).tag != AppData::MD_Invalid) binary_present=true;
00392     if ((*it).stag == tag) {
00393       data = (*it);
00394       // cerr << "tag: "<< data.tag << endl;
00395       return i;
00396     }
00397   }
00398   // not found yet
00399   data.Clear();
00400   if (binary_present)
00401     return -2;
00402   else 
00403     return -1;
00404   //return -5; // just to please the compiler. NO unreachable
00405 }
00406 
00407 
00408 int MetaData::Find(const AppData::TAppData tag, const string &stag, 
00409                    AppData &data) const
00410 {
00411   int res;
00412   if ((res=Find(tag, data))==-2)
00413     res=Find(stag, data);
00414   return res;
00415 }
00416 
00417 void MetaData::Delete(enum AppData::TAppData tag)
00418 {
00419   MetaData::iterator it;
00420   for (it=begin(); it!=end(); it++){
00421     if ((*it).tag == tag) {
00422       erase(it);
00423       break;
00424     }
00425   }
00426 }
00427 
00428 void MetaData::Delete(const std::string &tag)
00429 {
00430   MetaData::iterator it;
00431   for (it=begin(); it!=end(); it++){
00432     if ((*it).stag == tag) {
00433       erase(it);
00434       break;
00435     }
00436   }
00437 }
00438 
00439 ostream &MetaData::WriteBinary(ostream& os) const
00440 {
00441   MetaData::const_iterator it;
00442   for (it=begin(); it!=end(); it++){
00443     if ((*it).tag!=AppData::MD_USE_ASCII)
00444       os << (*it);
00445   }
00446   return os;
00447 }
00448     
00449 ostream &MetaData::WriteAscii(ostream& os) const
00450 {
00451   MetaData::const_iterator it;
00452   for (it=begin(); it!=end(); it++){
00453     if ((*it).tag==AppData::MD_USE_ASCII)
00454       os << (*it) << endl;
00455   }
00456   return os;
00457 }
00458 
00459 
00460 void MetaData::Dump(ostream& os)
00461 {
00462   for (unsigned int i=0; i<size(); i++)
00463     switch ((*this)[i].tag) {
00464     case AppData::MD_PMatrix:{
00465       os <<"PMatrix ("<<(*this)[i].length<<"): ";
00466       double *d = (double*)(*this)[i].data;
00467       for (int i=0; i<12; i++) os <<"  "<<d[i];
00468       os <<endl;
00469       break;}
00470     case AppData::MD_Projection:
00471       os<< "MD_Projection("<<(*this)[i].length<<"): ";
00472     os <<(*this)[i].data;
00473       os<<endl;
00474       break;
00475     case AppData::MD_Orientation:
00476       os << "MD_Orientation("<<(*this)[i].length<<"): ";
00477       os <<endl;
00478       break;
00479     case AppData::MD_TimeStamp:
00480       os << "MD_TimeStamp("<<(*this)[i].length<<"): ";
00481       os <<endl;
00482       break;
00483     case AppData::MD_PTU_Data:
00484       os << "MD_PTU_Data("<<(*this)[i].length<<"):  ";
00485       os <<endl;
00486       break;
00487     case AppData::MD_Inertial_Sensor:
00488       os << "MD_Inertial_Sensor("<<(*this)[i].length<<"): ";
00489       os <<endl;
00490       break;
00491     case AppData::MD_ASCII_DATA:
00492       os << "MD_ASCII_DATA: "<<(*this)[i].data<<endl;
00493       break;
00494     case AppData::MD_RMatrix:
00495       os << "MD_RMatrix("<<(*this)[i].length<<"): ";
00496       os <<endl;
00497       break;
00498     case AppData::MD_KMatrix:
00499       os << "MD_KMatrix("<<(*this)[i].length<<"): ";
00500       os <<endl;
00501       break;
00502     case AppData::MD_CVector:
00503       os << "MD_CVector("<<(*this)[i].length<<"): ";
00504       os <<endl;
00505       break;
00506     case AppData::MD_HomgPoint2D:{
00507       os << "MD_HomgPoint2D: [";
00508       double *d = (double*)(*this)[i].data;
00509       for (int i=0; i<3; i++) os <<" "<<d[i];
00510       os << "]\n";
00511       break;}
00512     case AppData::MD_Invalid:
00513       os << "MD_Invalid("<<(*this)[i].length<<"): ";
00514       os <<endl;
00515       break;
00516     case AppData::MD_UUID: 
00517       os <<"MD_UUID("<<(*this)[i].length<<"): "<< (char*)(*this)[i].data<<endl;
00518       break;
00519     case AppData::MD_USE_ASCII:
00520       os << (*this)[i].stag << " - " << (*this)[i].sdata << endl;
00521       break;
00522     case AppData::MD_Focal_Length:
00523       os << "MD_Focal_Length("<<(*this)[i].length<<"): " << " - " 
00524          <<*((double*)(*this)[i].data)<<endl;
00525       break;
00526     default:
00527       BIASERR("unknown tag: "<<(int)(*this)[i].tag);
00528       break;
00529     }
00530 
00531 }
00532 
00533 
00534 istream& BIAS::operator>>(istream& is, MetaData& md)
00535 {  
00536 #ifdef DEBUG_METADATA
00537   cerr << "A reading binary MetaDatas at pos: "<<is.tellg() << endl;
00538 #endif
00539   AppData ad;
00540   bool binary=true;
00541   if (is.peek()=='#') binary=false;
00542 #ifdef DEBUG_METADATA
00543   cerr << "B reading binary MetaDatas at pos: "<<is.tellg() << endl;
00544 #endif
00545   if (binary){
00546 #ifdef DEBUG_METADATA
00547     cerr << "reading binary MetaDatas" << endl;
00548 #endif
00549     while(is){
00550       ad.Clear();
00551       is >> ad;
00552       if (is)
00553         md.push_back(ad);
00554     }
00555   } else {
00556 #ifdef DEBUG_METADATA
00557     cerr << "reading ascii MetaDatas" << endl;
00558 #endif
00559     char id[2];
00560     char line[MD_LINE_LENGTH];
00561     while(is && is.peek()=='#'){
00562       is.read(id, 2*sizeof(char));
00563       is.putback(id[1]);
00564       is.putback(id[0]);
00565       if (id[0]=='#' && id[1]=='[') { // ascii data
00566         ad.Clear();
00567         is >> ad;
00568         if (is)
00569           md.push_back(ad);
00570         //cerr << "meta datum : "<<ad.stag<<endl;
00571       } else {
00572         is.getline(line, MD_LINE_LENGTH);
00573 #ifdef BIAS_DEBUG
00574 #ifdef BIAS_EXTRA_WARN
00575         BIASERR("skipping non-meta data image comments: "<<line);
00576 #endif
00577 #endif
00578       }
00579     }
00580   }
00581   return is;
00582 }
00583 
00584 ostream& BIAS::operator<<(ostream& os, const MetaData& md)
00585 {  
00586   if (!os) {
00587     BIASERR("MetaData::AppendToOStream(): ostream not writable!");
00588     return os;
00589   }
00590   MetaData::const_iterator it;
00591   for (it=md.begin(); it!=md.end(); it++){
00592     os << (*it);
00593   }
00594   return os;
00595 }
00596 
00597 
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends