Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
MetaData.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 
26 #include <iostream>
27 #include "MetaData.hh"
28 #include <Base/Debug/Error.hh>
29 #include <cstring>
30 
31 using namespace BIAS;
32 using namespace std;
33 
34 // #define DEBUG_METADATA
35 
36 ////////////////////////////////////////////////////////////////////////
37 // AppData
38 ///////////////////////////////////////////////////////////////////////
39 
41 {
42  data = NULL;
43  Clear();
44 }
45 
47 {
48  if (data != NULL) { delete[] data; data = NULL; }
49 }
50 
52 {
53  data = NULL;
54  (*this) = app;
55 }
56 
58 {
59  tag = app.tag;
60  length = app.length;
61  stag = app.stag;
62  sdata = app.sdata;
63  if (data != NULL) delete[] data;
64  if (length>0) {
65  data = new char[length];
66  memcpy(data, app.data, length);
67  }
68  else data = NULL;
69  return (*this);
70 }
71 
73 {
74  tag=MD_Invalid;
75  if (data) delete[] data; data=NULL;
76  data=NULL;
77  length=0;
78  stag=sdata="";
79 }
80 
82 {
83  //cerr <<"checking meta data format for "<<stag<<" sdata\n";
84  if (tag==MD_USE_ASCII){
85  string::size_type pos;
86  string::size_type last=sdata.length()-1;
87 
88  //cerr << "checking sdata\n";
89 
90  // check if sdata contains only \n followed by '#'
91  pos=0;
92  while ((pos=sdata.find('\n', (pos==0)?0:pos+1))!=string::npos){
93  if (pos==last || sdata[pos+1]!='#'){
94  BIASERR("there should be no CR without an immediatly following '#' in "
95  <<"ascii meta data "<<sdata);
96  return -1;
97  }
98  };
99  // check if sdata only contains '#' with a leading '\n'
100  pos=0;
101  while ((pos=sdata.find('#', (pos==0)?0:pos+1))!=string::npos){
102  if (pos==0 || sdata[pos-1]!='\n'){
103  BIASERR("there should be no '#' without a leading CR in "
104  <<"ascii meta data\nthe first '#' is added automatically "
105  <<stag<<endl<<sdata<<" "<<pos);
106  return -2;
107  }
108  }
109 
110  //cerr << "checking stag\n";
111  last=stag.length()-1;
112  if (last<3){
113  BIASERR("stag too short, stag should look like this: "
114  <<"'#[a tag]': "<<last+1<<" "<<stag);
115  return -3;
116  }
117  if (stag[0]!='#'){
118  BIASERR("wrong stag format, stag should start with '#[' "<<stag);
119  return -4;
120  }
121  if (stag[1]!='['){
122  BIASERR("wrong stag format, stag should start with '#[' "<<stag);
123  return -5;
124  }
125  if (stag[last]!=']'){
126  BIASERR("wrong stag format, stag should end with ']' "<<stag);
127  return -6;
128  }
129  } else {
130  if (stag!="" || sdata!=""){
131  BIASERR("stag or sdata is set but tag is not MD_USE_ASCII");
132  return -7;
133  }
134  if (length<0){
135  BIASERR("invalid length "<<length);
136  return -8;
137  }
138  }
139  //cerr << "CheckFormat finished\n";
140  return 0;
141 }
142 
143 ostream& BIAS::operator<<(ostream& os, const AppData::TAppData& ta)
144 {
145  switch(ta){
146  case AppData::MD_PMatrix:
147  os << "MD_PMatrix ("<<(int)AppData::MD_PMatrix<<")"; break;
149  os << "MD_Orientation ("<<(int)AppData::MD_Orientation<<")"; break;
151  os << "MD_TimeStamp ("<<(int)AppData::MD_TimeStamp<<")"; break;
152  case AppData::MD_PTU_Data:
153  os << "MD_PTU_Data ("<<(int)AppData::MD_PTU_Data<<")"; break;
155  os << "MD_Inertial_Sensor ("<<(int)AppData::MD_Inertial_Sensor<<")"; break;
157  os << "MD_ASCII_DATA ("<<(int)AppData::MD_ASCII_DATA<<")"; break;
158  case AppData::MD_RMatrix:
159  os << "MD_RMatrix ("<<(int)AppData::MD_RMatrix<<")"; break;
160  case AppData::MD_KMatrix:
161  os << "MD_KMatrix ("<<(int)AppData::MD_KMatrix<<")"; break;
162  case AppData::MD_CVector:
163  os << "MD_CVector ("<<(int)AppData::MD_CVector<<")"; break;
165  os << "MD_HomgPoint2D ("<<(int)AppData::MD_HomgPoint2D<<")"; break;
166  case AppData::MD_Invalid:
167  os << "MD_Invalid ("<<(int)AppData::MD_Invalid<<")"; break;
168  case AppData::MD_UUID:
169  os << "MD_UUID ("<<(int)AppData::MD_UUID<<")"; break;
170  case AppData::MD_USE_ASCII:
171  os << "MD_USE_ASCII ("<<(int)AppData::MD_USE_ASCII<<")"; break;
173  os << "MD_Focal_Length ("<<(int)AppData::MD_Focal_Length<<")"; break;
174  default: os <<"unknown TAppData.tag: "<<(int)ta; break;
175  }
176  return os;
177 }
178 
179 ostream& BIAS::operator<<(ostream& os, const AppData& ad)
180 {
181  if (ad.tag!=AppData::MD_USE_ASCII){
182 #ifdef DEBUG_METADATA
183  cerr << "writing binary: "<<ad.tag<<" length "<<ad.length
184  << " at pos: "<<(int)os.tellp()<<endl;
185 #endif
186  os.write((char*)&ad.tag, sizeof(AppData::TAppData));
187  os.write((char*)&ad.length, sizeof(int));
188  os.write(ad.data, ad.length);
189  } else {
190 #ifdef DEBUG_METADATA
191  cerr << "writing ascii: "<< ad.stag << "\n# "<<ad.sdata;
192  cerr<<"read binary AppData, type: "<<ad.tag<<" length: "<<ad.length<<endl;
193  cout << "length "<<ad.sdata.length();
194  if (ad.sdata.length()>0)
195  cout <<" first "<<ad.sdata.c_str()[0];
196  cout <<endl;
197  cout << "tag: '"<< ad.stag <<"'\ndata : '"<< ad.sdata<<"'\n";
198 #endif
199  if (ad.sdata.length()>0 && ad.sdata.c_str()[0]=='#'){
200  os << ad.stag << "\n"<<ad.sdata;
201  } else {
202  os << ad.stag << "\n# "<<ad.sdata;
203 #ifdef DEBUG_METADATA
204  cout << "added #\n";
205 #endif
206  }
207  }
208  return os;
209 }
210 
211 #define MD_LINE_LENGTH 4096
212 
213 istream& BIAS::operator>>(istream& is, AppData& ad)
214 {
215  char id[2]={' ',' '};
216  is.read(id, 2*sizeof(char));
217  if (is.fail() && is.eof()){
218  return is;
219  }
220  is.putback(id[1]);// Since OpenSuse 12.2 'putback' seems to unset the eof bit
221  is.putback(id[0]);// even when 0 bytes were read
222  if (id[0]=='#' && id[1]=='[') { // ascii data
224  // read stag
225  char c;
226  char line[MD_LINE_LENGTH];
227  do {
228  is.get(c);
229  ad.stag+=c;
230  } while (c!=']');
231  is.getline(line, MD_LINE_LENGTH);
232  string checkString(line);
233  if(checkString.size() == MD_LINE_LENGTH) {
234  BIASERR("you supposedly ran out of line length!");
235  BIASABORT;
236  }
237  //cout << "line: "<<line<<endl;
238  ad.sdata+=line;
239  ad.sdata+="\n";
240  // read sdata
241  do {
242  if (is.peek()!='#') break;
243  is.read(line, 2);
244  if (line[0]=='#' && line[1]=='[') {
245  is.putback(line[1]);
246  is.putback(line[0]);
247  break;
248  }
249  is.putback(line[1]);
250  is.putback(line[0]);
251  is.getline(line, MD_LINE_LENGTH);
252  //cout << "line: "<<line<<endl;
253  ad.sdata+=line;
254  ad.sdata+="\n";
255  } while (is);
256  if (ad.stag!="#[PTU Data]" && ad.stag!="#[Inertial Sensor]"){
257  //cerr << " now removing whitespace from "<<ad.stag<<endl;
258  // now remove leading '#', CRs, and whitespace
259  while (ad.sdata.length()>0 && (ad.sdata[0]=='#' || ad.sdata[0]==' ' ||
260  ad.sdata[0]=='\n'))
261  ad.sdata.erase(0, 1);
262  } else {
263  while (ad.sdata.length()>0 && (ad.sdata[0]==' ' || ad.sdata[0]=='\n'))
264  ad.sdata.erase(0, 1);
265  }
266  // remove appended CRs
267  while (ad.sdata[ad.sdata.length()-1]=='\n')
268  ad.sdata.erase(ad.sdata.length()-1, 1);
269 #ifdef DEBUG_METADATA
270  cerr << "read ascii AppData : stag: "<<ad.stag<<"\t:"<<ad.sdata<<endl;
271 #endif
272  } else { // binary data
273 #ifdef BIAS_DEBUG
274  if (is.peek()=='#'){
275  BIASERR("this image contains probably MetaData in old format"
276  <<"\n use '/usr/net/bin/convasciidata' to convert it");
277 #if __GNU_C__ < 3
278  is.setstate(ios::badbit | ios::failbit);
279 #else
280  is.setstate(ios_base::badbit | ios_base::failbit);
281 #endif
282  return is;
283  }
284 #endif
285 #ifdef DEBUG_METADATA
286  cerr<<"read binary AppData at pos: "<<(int)is.tellg()<<endl;
287 #endif
288  ad.stag="";
289  ad.sdata="";
290  is.read((char*)&ad.tag, sizeof(ad.tag));
291  if (!is) return is;
292 
293  is.read((char*)&ad.length, sizeof(ad.length));
294  if (!is) return is;
295 
296 #ifdef DEBUG_METADATA
297  cerr<<"read binary AppData, type: "<<ad.tag<<" length: "<<ad.length<<endl;
298 #endif
299  char *data = new char[ad.length];
300  is.read(data, ad.length);
301  ad.data = data;
302  }
303  return is;
304 }
305 
306 ////////////////////////////////////////////////////////////////////////
307 // MetaData
308 ///////////////////////////////////////////////////////////////////////
309 
310 MetaData::MetaData() //: Debug()
311  : vector<AppData>()
312 {}
313 
315 {}
316 
317 void MetaData::Add(enum AppData::TAppData ID, unsigned int length, char *data)
318 {
319  AppData ad;
320  if (Find(ID, ad)>=0)
321  Delete(ID);
322  ad.Clear();
323  ad.tag=ID;
324  ad.length=length;
325  ad.data=new char[ad.length];
326  memcpy(ad.data, data, ad.length);
327  push_back(ad);
328 }
329 
331 {
332  AppData ad2;
333  if (ad.tag==AppData::MD_USE_ASCII){
334  if (Find(ad.stag, ad2)>=0)
335  Delete(ad.stag);
336 #ifdef BIAS_DEBUG
337  ad.CheckFormat();
338 #endif
339  push_back(ad);
340  } else {
341  if (Find(ad.tag, ad2)>=0)
342  Delete(ad.tag);
343  push_back(ad);
344  }
345 }
346 
347 void MetaData::Add(const string &tag, const string& data)
348 {
349  AppData ad;
350  if (Find(tag, ad)>=0)
351  Delete(tag);
352  ad.Clear();
354  ad.stag=tag;
355  ad.sdata=data;
356 #ifdef BIAS_DEBUG
357  ad.CheckFormat();
358 #endif
359  push_back(ad);
360 }
361 
362 
363 int MetaData::Find(const AppData::TAppData tag, AppData &data) const
364 {
365  MetaData::const_iterator it;
366  int i;
367  bool ascii_present=false;
368  for (i=0, it=begin(); it!=end(); it++, i++){
369  if ((*it).tag == AppData::MD_USE_ASCII) ascii_present=true;
370  if ((*it).tag == tag) {
371  data = (*it);
372  return i;
373  }
374  }
375  // not found yet
376  data.Clear();
377  if (ascii_present)
378  return -2;
379  else
380  return -1;
381  //return -5; // just to please the compiler. NO, unreachable... (jw)
382 }
383 
384 int MetaData::Find(const string &tag, AppData &data) const
385 {
386  MetaData::const_iterator it;
387  int i;
388  bool binary_present=false;
389  for (i=0, it=begin(); it!=end(); it++, i++){
390  if ((*it).tag != AppData::MD_USE_ASCII &&
391  (*it).tag != AppData::MD_Invalid) binary_present=true;
392  if ((*it).stag == tag) {
393  data = (*it);
394  // cerr << "tag: "<< data.tag << endl;
395  return i;
396  }
397  }
398  // not found yet
399  data.Clear();
400  if (binary_present)
401  return -2;
402  else
403  return -1;
404  //return -5; // just to please the compiler. NO unreachable
405 }
406 
407 
408 int MetaData::Find(const AppData::TAppData tag, const string &stag,
409  AppData &data) const
410 {
411  int res;
412  if ((res=Find(tag, data))==-2)
413  res=Find(stag, data);
414  return res;
415 }
416 
418 {
419  MetaData::iterator it;
420  for (it=begin(); it!=end(); it++){
421  if ((*it).tag == tag) {
422  erase(it);
423  break;
424  }
425  }
426 }
427 
428 void MetaData::Delete(const std::string &tag)
429 {
430  MetaData::iterator it;
431  for (it=begin(); it!=end(); it++){
432  if ((*it).stag == tag) {
433  erase(it);
434  break;
435  }
436  }
437 }
438 
439 ostream &MetaData::WriteBinary(ostream& os) const
440 {
441  MetaData::const_iterator it;
442  for (it=begin(); it!=end(); it++){
443  if ((*it).tag!=AppData::MD_USE_ASCII)
444  os << (*it);
445  }
446  return os;
447 }
448 
449 ostream &MetaData::WriteAscii(ostream& os) const
450 {
451  MetaData::const_iterator it;
452  for (it=begin(); it!=end(); it++){
453  if ((*it).tag==AppData::MD_USE_ASCII)
454  os << (*it) << endl;
455  }
456  return os;
457 }
458 
459 
460 void MetaData::Dump(ostream& os)
461 {
462  for (unsigned int i=0; i<size(); i++)
463  switch ((*this)[i].tag) {
464  case AppData::MD_PMatrix:{
465  os <<"PMatrix ("<<(*this)[i].length<<"): ";
466  double *d = (double*)(*this)[i].data;
467  for (int i=0; i<12; i++) os <<" "<<d[i];
468  os <<endl;
469  break;}
471  os<< "MD_Projection("<<(*this)[i].length<<"): ";
472  os <<(*this)[i].data;
473  os<<endl;
474  break;
476  os << "MD_Orientation("<<(*this)[i].length<<"): ";
477  os <<endl;
478  break;
480  os << "MD_TimeStamp("<<(*this)[i].length<<"): ";
481  os <<endl;
482  break;
484  os << "MD_PTU_Data("<<(*this)[i].length<<"): ";
485  os <<endl;
486  break;
488  os << "MD_Inertial_Sensor("<<(*this)[i].length<<"): ";
489  os <<endl;
490  break;
492  os << "MD_ASCII_DATA: "<<(*this)[i].data<<endl;
493  break;
494  case AppData::MD_RMatrix:
495  os << "MD_RMatrix("<<(*this)[i].length<<"): ";
496  os <<endl;
497  break;
498  case AppData::MD_KMatrix:
499  os << "MD_KMatrix("<<(*this)[i].length<<"): ";
500  os <<endl;
501  break;
502  case AppData::MD_CVector:
503  os << "MD_CVector("<<(*this)[i].length<<"): ";
504  os <<endl;
505  break;
507  os << "MD_HomgPoint2D: [";
508  double *d = (double*)(*this)[i].data;
509  for (int i=0; i<3; i++) os <<" "<<d[i];
510  os << "]\n";
511  break;}
512  case AppData::MD_Invalid:
513  os << "MD_Invalid("<<(*this)[i].length<<"): ";
514  os <<endl;
515  break;
516  case AppData::MD_UUID:
517  os <<"MD_UUID("<<(*this)[i].length<<"): "<< (char*)(*this)[i].data<<endl;
518  break;
520  os << (*this)[i].stag << " - " << (*this)[i].sdata << endl;
521  break;
523  os << "MD_Focal_Length("<<(*this)[i].length<<"): " << " - "
524  <<*((double*)(*this)[i].data)<<endl;
525  break;
526  default:
527  BIASERR("unknown tag: "<<(int)(*this)[i].tag);
528  break;
529  }
530 
531 }
532 
533 
534 istream& BIAS::operator>>(istream& is, MetaData& md)
535 {
536 #ifdef DEBUG_METADATA
537  cerr << "A reading binary MetaDatas at pos: "<<is.tellg() << endl;
538 #endif
539  AppData ad;
540  bool binary=true;
541  if (is.peek()=='#') binary=false;
542 #ifdef DEBUG_METADATA
543  cerr << "B reading binary MetaDatas at pos: "<<is.tellg() << endl;
544 #endif
545  if (binary){
546 #ifdef DEBUG_METADATA
547  cerr << "reading binary MetaDatas" << endl;
548 #endif
549  while(is){
550  ad.Clear();
551  is >> ad;
552  if (is)
553  md.push_back(ad);
554  }
555  } else {
556 #ifdef DEBUG_METADATA
557  cerr << "reading ascii MetaDatas" << endl;
558 #endif
559  char id[2];
560  char line[MD_LINE_LENGTH];
561  while(is && is.peek()=='#'){
562  is.read(id, 2*sizeof(char));
563  is.putback(id[1]);
564  is.putback(id[0]);
565  if (id[0]=='#' && id[1]=='[') { // ascii data
566  ad.Clear();
567  is >> ad;
568  if (is)
569  md.push_back(ad);
570  //cerr << "meta datum : "<<ad.stag<<endl;
571  } else {
572  is.getline(line, MD_LINE_LENGTH);
573 #ifdef BIAS_DEBUG
574 #ifdef BIAS_EXTRA_WARN
575  BIASERR("skipping non-meta data image comments: "<<line);
576 #endif
577 #endif
578  }
579  }
580  }
581  return is;
582 }
583 
584 ostream& BIAS::operator<<(ostream& os, const MetaData& md)
585 {
586  if (!os) {
587  BIASERR("MetaData::AppendToOStream(): ostream not writable!");
588  return os;
589  }
590  MetaData::const_iterator it;
591  for (it=md.begin(); it!=md.end(); it++){
592  os << (*it);
593  }
594  return os;
595 }
596 
597 
std::ostream & WriteAscii(std::ostream &os) const
Writes only the meta datas where AppData::tag==MD_USE_ASCII to os.
Definition: MetaData.cpp:449
std::string stag
the tag as given in ascii meta data
Definition: MetaData.hh:100
void Delete(enum AppData::TAppData tag)
Delete the meta datum identified by tag.
Definition: MetaData.cpp:417
int length
number of bytes used by the data block
Definition: MetaData.hh:96
void Add(enum AppData::TAppData ID, unsigned int length, char *data)
Add a new binary meta datum.
Definition: MetaData.cpp:317
void Clear()
Resets all members.
Definition: MetaData.cpp:72
std::string sdata
the data as given in ascii meta data
Definition: MetaData.hh:102
char * data
pointer to block of data
Definition: MetaData.hh:98
int Find(const enum AppData::TAppData tag, AppData &data) const
searches for tag in binary coded AppDatas.
Definition: MetaData.cpp:363
std::ostream & WriteBinary(std::ostream &os) const
Writes only the meta datas where AppData::tag!=MD_USE_ASCII to os.
Definition: MetaData.cpp:439
enum TAppData tag
The tag defines the type of data, e.g.
Definition: MetaData.hh:94
std::ostream & operator<<(std::ostream &os, const Array2D< T > &arg)
Definition: Array2D.hh:260
TAppData
Type of AppData.
Definition: MetaData.hh:72
AppData & operator=(const AppData &app)
Definition: MetaData.cpp:57
this class collects all additional data chunks of type AppData to be written into/read from an image ...
Definition: MetaData.hh:121
void Dump(std::ostream &os=std::cout)
dumps this to cout, unfinished piece of code
Definition: MetaData.cpp:460
BIASCommon_EXPORT std::istream & operator>>(std::istream &is, BIAS::TimeStamp &ts)
Standard input operator for TimeStamps.
Definition: TimeStamp.cpp:157
int CheckFormat()
checks if stag and sdata have the correct format
Definition: MetaData.cpp:81
this is a chunk of metadata, also see MetaData
Definition: MetaData.hh:49