source: trunk/FACT++/src/Converter.cc@ 11607

Last change on this file since 11607 was 11564, checked in by tbretz, 13 years ago
Added a function to allow the COnverter to be fed with FITS format data: ToFormat
File size: 29.1 KB
Line 
1// **************************************************************************
2/** @class Converter
3
4@brief A compiler for the DIM data format string
5
6The Converter class interprets arguments in a string accoring to the
7given format definition and produces a corresponding memory block from it
8which can be attached to an event later.
9
10The format is given according to the Dim format description:
11
12 The format parameter specifies the contents of the structure in the
13 form T:N[;T:N]*[;T] where T is the item type: (I)nteger, (C)haracter,
14 (L)ong, (S)hort, (F)loat, (D)ouble, X(tra long) and N is the
15 number of such items. The type alone at the end means all following items
16 are of the same type. Example: "I:3;F:2;C" means 3 Integers, 2 Floats and
17 characters until the end. The format parameter is used for
18 communicating between different platforms.
19
20Note, that the strange notation T:N[;T:N]*[;T] is meant to be a regular
21expression. An Xtra-long is a 'long long'.
22
23Since Dim itself never really interpretes the format string, the programmer
24is responsible to make sure that the delivered data and the interpretation
25is consistent. Therefore the provided class can be of some help.
26
27For example:
28
29\code
30 Converter c(cout, "I:1;F:2;I:2", );
31 vector<char> v = c.GetVector("COMMAND 1 2.5 4.2 3 4");
32\endcode
33
34would produce a 20 byte data block with the integers 1, the floats
352.5 and 4.2, and the intergers 3 and 4, in this order.
36
37The opposite direction is also possible
38
39\code
40 Converter c(cout, "I:1;F:2;I:2");
41 cout << c.GetString(pointer, size) << endl;
42 \endcode
43
44Other conversion functions also exist.
45
46To check if the compilation of the format string was successfull
47the valid() member functio is provided.
48
49The format parameter \b W(ord) is dedicated to this kind of conversion and
50not understood by Dim. In addition there are \b O(ptions) which are like
51Words but can be omitted. They should only be used at the end of the string.
52Both can be encapsulated in quotationmarks '"'. Nested quotationmarks
53are not supported. \b B(ool) is also special. It evaluates true/false,
54yes/no, on/off, 1/0.
55
56The non-DIM like format options can be switched on and off by using the
57strict argument in the constructor. In general DimCommands can use these
58options, but DimServices not.
59
60@remark Note that all values are interpreted as signed, except the single
61char (e.g. C:5)
62
63*/
64// **************************************************************************
65#include "Converter.h"
66
67#include <iostream>
68#include <iomanip>
69#include <sstream>
70
71#include <cctype> // std::tolower
72#include <algorithm> // std::transform
73
74#include <boost/regex.hpp>
75
76#include "Readline.h"
77#include "WindowLog.h"
78
79using namespace std;
80
81// --------------------------------------------------------------------------
82//
83//! This function is supposed to remove all whitespaces from the format
84//! string to allow easier regular expressions later.
85//!
86//! @param s
87//! string to be cleaned
88//!
89//! @returns
90//! string cleaned from whitespaces
91//
92std::string Converter::Clean(std::string s)
93{
94 while (1)
95 {
96 const size_t pos = s.find_last_of(' ');
97 if (pos==string::npos)
98 break;
99 s.erase(pos, pos+1);
100 }
101
102 return s;
103}
104
105// --------------------------------------------------------------------------
106//
107//! This is just a simplification. For the time being it is used to output
108//! the interpreted contents to the logging stream. Its main purpose
109//! is to add the contents of val in a binary representation to the
110//! vector v
111//!
112//! @tparam
113//! data type of the variable which should be added
114//!
115//! @param val
116//! reference to the data
117//!
118//! @param v
119//! vector<char> to which the binary copy should be added
120//!
121template <class T>
122void Converter::GetBinImp(std::vector<char> &v, const T &val) const
123{
124 wout << " (" << val << ")";
125
126 v.insert(v.end(),
127 reinterpret_cast<const char*>(&val),
128 reinterpret_cast<const char*>(&val+1));
129}
130
131// --------------------------------------------------------------------------
132//
133//! This is just a simplification. For the time being it is used to output
134//! the interpreted contents to the logging stream. Its main purpose
135//! is to add the contents of val as a boost::any object to the
136//! vector v
137//!
138//! @tparam
139//! data type of the variable which should be added
140//!
141//! @param val
142//! reference to the data
143//!
144//! @param v
145//! vector<boost::any> to which the value should be added
146//!
147template <class T>
148void Converter::GetBinImp(std::vector<boost::any> &v, const T &val) const
149{
150 wout << " (" << val << ")";
151
152 v.push_back(val);
153}
154
155// --------------------------------------------------------------------------
156//
157//! This is just a simplification. For the time being it is used to output
158//! the interpreted contents to the logging stream. Its main purpose
159//! is to add the contents of the provided string at the end of the vector v.
160//! vector v
161//!
162//! @param val
163//! reference to the string
164//!
165//! @param v
166//! vector<char> to which the value should be added
167//!
168void Converter::GetBinString(std::vector<char> &v, const string &val) const
169{
170 wout << " (" << val << ")";
171
172 v.insert(v.end(), val.begin(), val.end()+1);
173}
174
175// --------------------------------------------------------------------------
176//
177//! This is just a simplification. For the time being it is used to output
178//! the interpreted contents to the logging stream. Its main purpose
179//! is to add the contents of the provided string at the end of the vector v.
180//! vector v
181//!
182//! @param val
183//! reference to the string
184//!
185//! @param v
186//! vector<boost::any> to which the value should be added
187//!
188void Converter::GetBinString(std::vector<boost::any> &v, const string &val) const
189{
190 wout << " (" << val << ")";
191
192 v.push_back(val);
193 v.push_back('\n');
194}
195
196// --------------------------------------------------------------------------
197//
198//! Converts from the stringstream into the provided type.
199//!
200//! @param line
201//! reference to the stringstream from which the data should be
202//! interpreted
203//!
204//! @tparam
205//! Type of the data to be returned
206//!
207//! @returns
208//! The interpreted data
209//!
210template <class T>
211T Converter::Get(std::stringstream &line) const
212{
213 char c;
214 line >> c;
215
216 if (c=='0')
217 {
218 if (line.peek()==-1)
219 {
220 line.clear(ios::eofbit);
221 return 0;
222 }
223
224 if (line.peek()=='x')
225 {
226 line >> c;
227 line >> hex;
228 }
229 else
230 {
231 line.unget();
232 line >> oct;
233 }
234 }
235 else
236 {
237 line.unget();
238 line >> dec;
239 }
240
241
242 T val;
243 line >> val;
244 return val;
245}
246
247// --------------------------------------------------------------------------
248//
249//! Converts from the stringstream into bool. It allows to use lexical
250//! boolean representations like yes/no, on/off, true/false and of
251//! course 0/1. If the conversion fails the failbit is set.
252//!
253//! @param line
254//! reference to the stringstream from which the data should be
255//! interpreted
256//!
257//! @returns
258//! The boolean. 0 in case of failure
259//!
260bool Converter::GetBool(std::stringstream &line) const
261{
262 string buf;
263 line >> buf;
264 transform(buf.begin(), buf.end(), buf.begin(), (int(*)(int)) std::tolower);
265
266 if (buf=="yes" || buf=="true" || buf=="on" || buf=="1")
267 return true;
268
269 if (buf=="no" || buf=="false" || buf=="off" || buf=="0")
270 return false;
271
272 line.clear(ios::failbit);
273
274 return false;
275}
276
277// --------------------------------------------------------------------------
278//
279//! Converts from the stringstream into a string. Leading whitespaces are
280//! skipped. Everything up to the next whitespace is returned.
281//! strings can be encapsulated into escape characters ("). Note, that
282//! they cannot be nested.
283//!
284//! @param line
285//! reference to the stringstream from which the data should be
286//! interpreted
287//!
288//! @returns
289//! The string
290//!
291string Converter::GetString(std::stringstream &line) const
292{
293 while (line.peek()==' ')
294 line.get();
295
296 string buf;
297 if (line.peek()=='\"')
298 {
299 line.get();
300 getline(line, buf, '\"');
301 if (line.peek()==-1)
302 line.clear(ios::eofbit);
303 }
304 else
305 line >> buf;
306
307 return buf;
308}
309
310// --------------------------------------------------------------------------
311//
312//! Converts from the stringstream into a string. Leading whitespaces are
313//! skipped. Everything until the end-of-line is returned. A trailing
314//! \0 is added.
315//!
316//! @param line
317//! reference to the stringstream from which the data should be
318//! interpreted
319//!
320//! @returns
321//! The string
322//!
323string Converter::GetStringEol(stringstream &line) const
324{
325 // Remove leading whitespaces
326 while (line.peek()==' ')
327 line.get();
328
329 line >> noskipws;
330
331 const istream_iterator<char> eol; // end-of-line iterator
332 const string s(istream_iterator<char>(line), eol);
333 return s + '\0';
334}
335
336// --------------------------------------------------------------------------
337//
338//! Converts from a binary block into a string. The type of the expected
339//! value is defined by the template parameter.
340//!
341//! @param ptr
342//! A refrenece to the pointer of the binary representation to be
343//! interpreted. The pointer is incremented by the sizeof the type.
344//!
345//! @tparam T
346//! Expected type
347//!
348//! @returns
349//! The string
350//!
351template<class T>
352string Converter::GetString(const char* &ptr) const
353{
354 const T &t = *reinterpret_cast<const T*>(ptr);
355
356 ostringstream stream;
357 stream << (int64_t)t;
358 ptr += sizeof(T);
359
360 return stream.str();
361}
362
363// --------------------------------------------------------------------------
364//
365//! Convert the pointer using GetString into a string and add it (prefixed
366//! by a whaitespace) to the given string.
367//!
368//! @param str
369//! Reference to the string to which the ptr should be added
370//!
371//! @param ptr
372//! Pointer to the binary representation. It will be incremented
373//! according to the sze of the template argument
374//!
375//! @tparam T
376//! Type as which the binary data should be interpreted
377//!
378template<class T>
379void Converter::Add(string &str, const char* &ptr) const
380{
381 str += ' ' + GetString<T>(ptr);
382}
383
384// --------------------------------------------------------------------------
385//
386//! Convert the pointer into a boost::any object and add it to the
387//! provided vector
388//!
389//! @param vec
390//! Vector to which the boost::any object should be added
391//!
392//! @param ptr
393//! Pointer to the binary representation. It will be incremented
394//! according to the size of the template argument
395//!
396//! @tparam T
397//! Type as which the binary data should be interpreted
398//!
399template<class T>
400void Converter::Add(vector<boost::any> &vec, const char* &ptr) const
401{
402 vec.push_back(*reinterpret_cast<const T*>(ptr));
403 ptr += sizeof(T);
404}
405
406// --------------------------------------------------------------------------
407//
408//! Add the string pointed to by ptr to the given string.
409//!
410//! @param str
411//! Reference to the string to which the ptr should be added
412//!
413//! @param ptr
414//! Pointer to the binary representation. It will be incremented
415//! according to the size of the template argument
416//!
417void Converter::AddString(string &str, const char* &ptr) const
418{
419 const string txt(ptr);
420 str += ' '+txt;
421 ptr += txt.length()+1;
422}
423
424// --------------------------------------------------------------------------
425//
426//! Add the string pointed to by ptr as boost::any to the provided vector
427//!
428//! @param vec
429//! Vector to which the boost::any object should be added
430//!
431//! @param ptr
432//! Pointer to the binary representation. It will be incremented
433//! according to the size of the template argument
434//!
435void Converter::AddString(vector<boost::any> &vec, const char* &ptr) const
436{
437 const string txt(ptr);
438 vec.push_back(txt);
439 ptr += txt.length()+1;
440}
441
442// --------------------------------------------------------------------------
443//
444//! Compiles the format string into fList. See Compile() for more details.
445//!
446//! @param out
447//! Output stream to which possible logging is redirected
448//!
449//! @param fmt
450//! Format to be compiled. For details see class reference
451//!
452//! @param strict
453//! Setting this to true allows non DIM options, whiel false
454//! will restrict the possible format strings to the ones also
455//! understood by DIM.
456//!
457Converter::Converter(std::ostream &out, const std::string &fmt, bool strict)
458: wout(out), fFormat(Clean(fmt)), fList(Compile(out, fmt, strict))
459{
460}
461
462// --------------------------------------------------------------------------
463//
464//! Compiles the format string into fList.
465//!
466//! Output by default is redirected to cout.
467//!
468//! @param fmt
469//! Format to be compiled. For details see class reference
470//!
471//! @param strict
472//! Setting this to true allows non DIM options, whiel false
473//! will restrict the possible format strings to the ones also
474//! understood by DIM.
475//!
476Converter::Converter(const std::string &fmt, bool strict)
477: wout(cout), fFormat(Clean(fmt)), fList(Compile(fmt, strict))
478{
479}
480
481// --------------------------------------------------------------------------
482//
483//! Converts the provided format string into a vector.
484//!
485//! @tparam T
486//! Kind of data to be returned. This can either be boost::any objects
487//! or a bnary data-block (char).
488//!
489//! @param str
490//! Data to be converted. For details see class reference
491//!
492//! @returns
493//! A vector of the given template type containing the arguments. In
494//! case of failure an empty vector is returned.
495//!
496//! @throws
497//! std::runtime_error if the conversion was not successfull
498//!
499template <class T>
500vector<T> Converter::Get(const std::string &str) const
501{
502 if (!valid())
503 throw runtime_error("Compiled format invalid!");
504
505 // If the format is empty we are already done
506 if (empty() && str.empty())
507 {
508 wout << endl;
509 return vector<T>();
510 }
511
512 int arg = 0;
513 stringstream line(str);
514
515 vector<T> data;
516
517 for (Converter::FormatList::const_iterator i=fList.begin(); i<fList.end()-1; i++)
518 {
519 if (*i->first.first == typeid(string))
520 {
521 GetBinString(data, GetStringEol(line));
522 line.clear(ios::eofbit);
523 continue;
524 }
525
526 // Get as many items from the input line as requested
527 for (int j=0; j<i->second.first; j++)
528 {
529 switch (i->first.first->name()[0])
530 {
531 case 'b': GetBinImp(data, GetBool(line)); break;
532 case 's': GetBinImp(data, Get<short> (line)); break;
533 case 'i': GetBinImp(data, Get<int> (line)); break;
534 case 'l': GetBinImp(data, Get<long> (line)); break;
535 case 'f': GetBinImp(data, Get<float> (line)); break;
536 case 'd': GetBinImp(data, Get<double> (line)); break;
537 case 'x': GetBinImp(data, Get<long long>(line)); break;
538 case 'c':
539 {
540 const unsigned short val = Get<unsigned short>(line);
541 if (val>255)
542 line.setstate(ios::failbit);
543 GetBinImp(data, static_cast<unsigned char>(val));
544 }
545 break;
546 case 'N':
547 GetBinString(data, GetString(line));
548 if (*i->first.first == typeid(O))
549 line.clear(ios::goodbit|(line.rdstate()&ios::eofbit));
550 break;
551 default:
552 // This should never happen!
553 throw runtime_error("Format '"+string(i->first.first->name())+" not supported!");
554 }
555
556 arg++;
557 }
558
559 if (!line)
560 break;
561 }
562 wout << endl;
563
564 // Something wrong with the conversion (e.g. 5.5 for an int)
565 if (line.fail() && !line.eof())
566 {
567 line.clear(); // This is necesasary to get a proper response from tellg()
568
569 ostringstream err;
570 err << "Error converting argument at " << arg << " [fmt=" << fFormat << "]!\n";
571 err << line.str() << "\n";
572 err << setw(int(line.tellg())) << " " << "^\n";
573 throw runtime_error(err.str());
574 }
575
576 // Not enough arguments, we have not reached the end
577 if (line.fail() && line.eof())
578 {
579 line.clear();
580
581 ostringstream err;
582 err << "Not enough arguments [fmt=" << fFormat << "]!\n";
583 err << line.str() << "\n";
584 err << setw(int(line.tellg())+1) << " " << "^\n";
585 throw runtime_error(err.str());
586 }
587
588 // Too many arguments, we have not reached the end
589 // Unfortunately, this can also mean that there is something
590 // wrong with the last argument
591 if (line.good() && !line.eof())
592 {
593 ostringstream err;
594 err << "More arguments available than expected [fmt=" << fFormat << "]!\n";
595 err << line.str() << "\n";
596 err << setw(int(line.tellg())+1) << " " << "^\n";
597 throw runtime_error(err.str());
598 }
599
600 return data;
601
602}
603
604std::vector<boost::any> Converter::GetAny(const std::string &str) const
605{
606 return Get<boost::any>(str);
607}
608
609std::vector<char> Converter::GetVector(const std::string &str) const
610{
611 return Get<char>(str);
612}
613
614// --------------------------------------------------------------------------
615//
616//! Converts the provided data block into a vector of boost::any or
617//! a string.
618//!
619//! @tparam T
620//! Kind of data to be returned. This can either be boost::any objects
621//! or a string
622//!
623//! @returns
624//! A vector of the given template type containing the arguments. In
625//! case of failure an empty vector is returned.
626//!
627//! @throws
628//! std::runtime_error if the conversion was not successfull
629//!
630template<class T>
631T Converter::Get(const void *dat, size_t size) const
632{
633 if (!valid())
634 throw runtime_error("Compiled format invalid!");
635
636 if (dat==0)
637 throw runtime_error("Data pointer == NULL!");
638
639 const char *ptr = reinterpret_cast<const char *>(dat);
640
641 T text;
642 for (Converter::FormatList::const_iterator i=fList.begin(); i<fList.end()-1; i++)
643 {
644 if (ptr-size>dat)
645 {
646 ostringstream err;
647 err << "Format description [fmt=" << fFormat << "] exceeds available data size (" << size << ")";
648 throw runtime_error(err.str());
649 }
650
651 if (*i->first.first == typeid(string))
652 {
653 if (size>0)
654 AddString(text, ptr);
655 if (ptr-size<=dat)
656 return text;
657 break;
658 }
659
660 // Get as many items from the input line as requested
661 for (int j=0; j<i->second.first; j++)
662 {
663 switch (i->first.first->name()[0])
664 {
665 case 'b': Add<bool> (text, ptr); break;
666 case 'c': Add<char> (text, ptr); break;
667 case 's': Add<short> (text, ptr); break;
668 case 'i': Add<int> (text, ptr); break;
669 case 'l': Add<long> (text, ptr); break;
670 case 'f': Add<float> (text, ptr); break;
671 case 'd': Add<double> (text, ptr); break;
672 case 'x': Add<long long>(text, ptr); break;
673 case 'N': AddString(text, ptr); break;
674
675 case 'v':
676 // This should never happen!
677 throw runtime_error("Type 'void' not supported!");
678 default:
679 throw runtime_error("TypeId '"+string(i->first.first->name())+"' not known!");
680 }
681 }
682 }
683
684 if (ptr-size!=dat)
685 {
686 ostringstream err;
687 err << "Data block size (" << size << ") doesn't fit format description [fmt=" << fFormat << "]";
688 throw runtime_error(err.str());
689 }
690
691 return text;
692}
693
694std::vector<boost::any> Converter::GetAny(const void *dat, size_t size) const
695{
696 return Get<vector<boost::any>>(dat, size);
697}
698
699std::vector<char> Converter::GetVector(const void *dat, size_t size) const
700{
701 const string ref = GetString(dat, size);
702
703 vector<char> data;
704 data.insert(data.begin(), ref.begin()+1, ref.end());
705 data.push_back(0);
706
707 return data;
708}
709
710string Converter::GetString(const void *dat, size_t size) const
711{
712 const string s = Get<string>(dat, size);
713 return s.empty() ? s : s.substr(1);
714}
715
716template<class T>
717Converter::Type Converter::GetType()
718{
719 Type t;
720 t.first = &typeid(T);
721 t.second = sizeof(T);
722 return t;
723}
724
725template<class T>
726Converter::Type Converter::GetVoid()
727{
728 Type t;
729 t.first = &typeid(T);
730 t.second = 0;
731 return t;
732}
733
734// --------------------------------------------------------------------------
735//
736//! static function to compile a format string.
737//!
738//! @param out
739//! Output stream to which possible logging is redirected
740//!
741//! @param fmt
742//! Format to be compiled. For details see class reference
743//!
744//! @param strict
745//! Setting this to true allows non DIM options, whiel false
746//! will restrict the possible format strings to the ones also
747//! understood by DIM.
748//!
749Converter::FormatList Converter::Compile(std::ostream &out, const std::string &fmt, bool strict)
750{
751 ostringstream text;
752
753 // Access both, the data and the format through a stringstream
754 stringstream stream(fmt);
755
756 // For better performance we could use sregex
757 static const boost::regex expr1("^([CSILFDXBOW])(:([1-9]+[0-9]*))?$");
758 static const boost::regex expr2("^([CSILFDX])(:([1-9]+[0-9]*))?$");
759
760 FormatList list;
761 Format format;
762
763 // Tokenize the format
764 string buffer;
765 while (getline(stream, buffer, ';'))
766 {
767 boost::smatch what;
768 if (!boost::regex_match(buffer, what, strict?expr2:expr1))
769 {
770 out << kRed << "Wrong format string '" << buffer << "'!" << endl;
771 return FormatList();
772 }
773
774 const string t = what[1]; // type id
775 const string n = what[3]; // counter
776
777 const int cnt = n.empty() ? 0 : stoi(n);
778
779 // if the :N part was not given assume 1
780 format.second.first = cnt == 0 ? 1 : cnt;
781
782 /*
783 if (strict && t[0]=='C' && cnt>0)
784 {
785 out << kRed << "Dim doesn't support the format C with N>0!" << endl;
786 return FormatList();
787 }*/
788
789 // Check if the format is just C (without a number)
790 // That would mean that it is a \0 terminated string
791 if (t[0]=='C' && cnt==0)
792 {
793 format.first = GetType<string>();
794 list.push_back(format);
795 format.second.second = 0; // end position not known
796 break;
797 }
798
799 // Get as many items from the input line as requested
800 switch (t[0])
801 {
802 case 'B': format.first = GetType<bool>(); break;
803 case 'C': format.first = GetType<char>(); break;
804 case 'S': format.first = GetType<short>(); break;
805 case 'I': format.first = GetType<int>(); break;
806 case 'L': format.first = GetType<long>(); break;
807 case 'F': format.first = GetType<float>(); break;
808 case 'D': format.first = GetType<double>(); break;
809 case 'X': format.first = GetType<long long>(); break;
810 case 'O': format.first = GetVoid<O>(); break;
811 case 'W': format.first = GetVoid<W>(); break;
812 default:
813 // This should never happen!
814 out << kRed << "Format '" << t[0] << " not known!" << endl;
815 return list;
816 }
817
818 list.push_back(format);
819 format.second.second += format.first.second * format.second.first;
820 }
821
822 format.first = GetVoid<void>();
823 format.second.first = 0;
824
825 list.push_back(format);
826
827 return list;
828}
829
830// --------------------------------------------------------------------------
831//
832//! Same as Compile(ostream&,string&,bool) but cout is used as the default
833//! output stream.
834//!
835//!
836Converter::FormatList Converter::Compile(const std::string &fmt, bool strict)
837{
838 return Compile(cout, fmt, strict);
839}
840
841vector<string> Converter::Regex(const string &expr, const string &line)
842{
843 const boost::regex reg(expr);
844
845 boost::smatch what;
846 if (!boost::regex_match(line, what, reg, boost::match_extra))
847 return vector<string>();
848
849 vector<string> ret;
850 for (unsigned int i=0; i<what.size(); i++)
851 ret.push_back(what[i]);
852
853 return ret;
854}
855
856// --------------------------------------------------------------------------
857//
858//! @param dest
859//! Array to which the destination data is written
860//! @param src
861//! Array with the source data according to the format stored in the
862//! Converter
863//! @param size
864//! size of the destination data in bytes
865//!
866void Converter::ToFits(void *dest, const void *src, size_t size) const
867{
868 // crawl through the src buffer and copy the data appropriately to the
869 // destination buffer
870 // Assumption: the string is always last. This way we
871 // use the provided size to determine the number
872 // of character to copy
873
874 char *charDest = static_cast<char*>(dest);
875 const char *charSrc = static_cast<const char*>(src);
876
877 // We skip the last element 'v'
878 for (Converter::FormatList::const_iterator i=fList.begin(); i!=fList.end()-1; i++)
879 {
880 /*
881 // For speed reasons we don't do a check in the loop
882 if (charDest-size>dest || charSrc-size>src)
883 {
884 ostringstream err;
885 err << "Format description [fmt=" << fFormat << "] exceeds available data size (" << size << ")";
886 throw runtime_error(err.str());
887 }
888 */
889
890 // Skip strings (must be the last, so we could just skip it)
891 const char type = i->first.first->name()[0];
892 if (type=='S')
893 {
894 charSrc += strlen(charSrc)+1;
895 continue;
896 }
897
898 const int s = i->first.second; // size of element
899 const int n = i->second.first; // number of elements
900
901 // Check if there are types with unknown sizes
902 if (s==0 || n==0)
903 throw runtime_error(string("Type '")+type+"' not supported converting to FITS.");
904
905 // Let the compiler do some optimization
906 switch (s)
907 {
908 case 1: memcpy(charDest, charSrc, s*n); charSrc+=s*n; charDest+=s*n; break;
909 case 2: for (int j=0; j<n; j++) { reverse_copy(charSrc, charSrc+2, charDest); charSrc+=2; charDest+=2; } break;
910 case 4: for (int j=0; j<n; j++) { reverse_copy(charSrc, charSrc+4, charDest); charSrc+=4; charDest+=4; } break;
911 case 8: for (int j=0; j<n; j++) { reverse_copy(charSrc, charSrc+8, charDest); charSrc+=8; charDest+=8; } break;
912 }
913 }
914
915 if (charDest-size!=dest/* || charSrc-size!=src*/)
916 {
917 ostringstream err;
918 err << "ToFits - Data block size (" << size << ") doesn't fit format description [fmt=" << fFormat << "]";
919 throw runtime_error(err.str());
920 }
921}
922
923vector<string> Converter::ToStrings(const void *src/*, size_t size*/) const
924{
925 const char *charSrc = static_cast<const char*>(src);
926
927 vector<string> rc;
928
929 for (Converter::FormatList::const_iterator i=fList.begin(); i!=fList.end(); i++)
930 {
931 /*
932 if (charSrc-size>src)
933 {
934 ostringstream err;
935 err << "Format description [fmt=" << fFormat << "] exceeds available data size (" << size << ")";
936 throw runtime_error(err.str());
937 }*/
938
939 const char type = i->first.first->name()[0];
940 if (type=='v')
941 break;
942
943 if (type=='S')
944 {
945 const string str(charSrc);
946 rc.push_back(str);
947 charSrc += str.length()+1;
948 continue;
949 }
950
951 // string types
952 //if (string("bsilfdxc").find_first_of(type)==string::npos)
953 // throw runtime_error(string("Type '")+type+"' not supported converting to FITS.");
954
955 const int s = i->first.second; // size of element
956 const int n = i->second.first; // number of elements
957
958 charSrc += s*n;
959 }
960
961 return rc;
962
963 /*
964 if (charSrc-size!=src)
965 {
966 ostringstream err;
967 err << "Data block size (" << size << ") doesn't fit format description [fmt=" << fFormat << "]";
968 throw runtime_error(err.str());
969 }*/
970}
971
972vector<char> Converter::ToFits(const void *src, size_t size) const
973{
974 vector<char> dest(size);
975 ToFits(dest.data(), src, size);
976 return dest;
977}
978
979string Converter::ToFormat(const vector<string> &fits)
980{
981 ostringstream str;
982 for (vector<string>::const_iterator it=fits.begin(); it!=fits.end(); it++)
983 {
984 size_t id=0;
985 int n;
986
987 try
988 {
989 n = stoi(*it, &id);
990 }
991 catch (exception&)
992 {
993 n = 1;
994 }
995
996 if (n==0)
997 continue;
998
999 switch ((*it)[id])
1000 {
1001 case 'L':
1002 case 'B': str << ";C:" << n; break;
1003 case 'J': str << ";I:" << n; break;
1004 case 'I': str << ";S:" << n; break;
1005 case 'K': str << ";X:" << n; break;
1006 case 'E': str << ";F:" << n; break;
1007 case 'D': str << ";D:" << n; break;
1008 default:
1009 throw runtime_error("ToFormat - id not known.");
1010 }
1011 }
1012
1013 return str.str().substr(1);
1014}
1015
1016
1017void Converter::Print(std::ostream &out) const
1018{
1019 for (FormatList::const_iterator i=fList.begin(); i!=fList.end(); i++)
1020 {
1021 out << "Type=" << i->first.first->name() << "[" << i->first.second << "] ";
1022 out << "N=" << i->second.first << " ";
1023 out << "offset=" << i->second.second << endl;
1024 }
1025}
1026
1027void Converter::Print() const
1028{
1029 return Print(cout);
1030}
Note: See TracBrowser for help on using the repository browser.