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

Last change on this file since 12108 was 11735, checked in by tbretz, 13 years ago
If we are already at the end of the stream return a default rather than try to analyze the stream further.
File size: 30.2 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 if (!line)
216 return T();
217
218 if (c=='0')
219 {
220 if (line.peek()==-1)
221 {
222 line.clear(ios::eofbit);
223 return 0;
224 }
225
226 if (line.peek()=='x')
227 {
228 line >> c;
229 line >> hex;
230 }
231 else
232 {
233 line.unget();
234 line >> oct;
235 }
236 }
237 else
238 {
239 line.unget();
240 line >> dec;
241 }
242
243
244 T val;
245 line >> val;
246 return val;
247}
248
249// --------------------------------------------------------------------------
250//
251//! Converts from the stringstream into bool. It allows to use lexical
252//! boolean representations like yes/no, on/off, true/false and of
253//! course 0/1. If the conversion fails the failbit is set.
254//!
255//! @param line
256//! reference to the stringstream from which the data should be
257//! interpreted
258//!
259//! @returns
260//! The boolean. 0 in case of failure
261//!
262bool Converter::GetBool(std::stringstream &line) const
263{
264 string buf;
265 line >> buf;
266 transform(buf.begin(), buf.end(), buf.begin(), (int(*)(int)) std::tolower);
267
268 if (buf=="yes" || buf=="true" || buf=="on" || buf=="1")
269 return true;
270
271 if (buf=="no" || buf=="false" || buf=="off" || buf=="0")
272 return false;
273
274 line.clear(ios::failbit);
275
276 return false;
277}
278
279// --------------------------------------------------------------------------
280//
281//! Converts from the stringstream into a string. Leading whitespaces are
282//! skipped. Everything up to the next whitespace is returned.
283//! strings can be encapsulated into escape characters ("). Note, that
284//! they cannot be nested.
285//!
286//! @param line
287//! reference to the stringstream from which the data should be
288//! interpreted
289//!
290//! @returns
291//! The string
292//!
293string Converter::GetString(std::stringstream &line) const
294{
295 while (line.peek()==' ')
296 line.get();
297
298 string buf;
299 if (line.peek()=='\"')
300 {
301 line.get();
302 getline(line, buf, '\"');
303 if (line.peek()==-1)
304 line.clear(ios::eofbit);
305 }
306 else
307 line >> buf;
308
309 return buf;
310}
311
312// --------------------------------------------------------------------------
313//
314//! Converts from the stringstream into a string. Leading whitespaces are
315//! skipped. Everything until the end-of-line is returned. A trailing
316//! \0 is added.
317//!
318//! @param line
319//! reference to the stringstream from which the data should be
320//! interpreted
321//!
322//! @returns
323//! The string
324//!
325string Converter::GetStringEol(stringstream &line) const
326{
327 // Remove leading whitespaces
328 while (line.peek()==' ')
329 line.get();
330
331 line >> noskipws;
332
333 const istream_iterator<char> eol; // end-of-line iterator
334 const string s(istream_iterator<char>(line), eol);
335 return s + '\0';
336}
337
338// --------------------------------------------------------------------------
339//
340//! Converts from a binary block into a string. The type of the expected
341//! value is defined by the template parameter.
342//!
343//! @param ptr
344//! A refrenece to the pointer of the binary representation to be
345//! interpreted. The pointer is incremented by the sizeof the type.
346//!
347//! @tparam T
348//! Expected type
349//!
350//! @returns
351//! The string
352//!
353template<class T>
354string Converter::GetString(const char* &ptr) const
355{
356 const T &t = *reinterpret_cast<const T*>(ptr);
357
358 ostringstream stream;
359 stream << (int64_t)t;
360 ptr += sizeof(T);
361
362 return stream.str();
363}
364
365// --------------------------------------------------------------------------
366//
367//! Convert the pointer using GetString into a string and add it (prefixed
368//! by a whaitespace) to the given string.
369//!
370//! @param str
371//! Reference to the string to which the ptr should be added
372//!
373//! @param ptr
374//! Pointer to the binary representation. It will be incremented
375//! according to the sze of the template argument
376//!
377//! @tparam T
378//! Type as which the binary data should be interpreted
379//!
380template<class T>
381void Converter::Add(string &str, const char* &ptr) const
382{
383 str += ' ' + GetString<T>(ptr);
384}
385
386// --------------------------------------------------------------------------
387//
388//! Convert the pointer into a boost::any object and add it to the
389//! provided vector
390//!
391//! @param vec
392//! Vector to which the boost::any object should be added
393//!
394//! @param ptr
395//! Pointer to the binary representation. It will be incremented
396//! according to the size of the template argument
397//!
398//! @tparam T
399//! Type as which the binary data should be interpreted
400//!
401template<class T>
402void Converter::Add(vector<boost::any> &vec, const char* &ptr) const
403{
404 vec.push_back(*reinterpret_cast<const T*>(ptr));
405 ptr += sizeof(T);
406}
407
408// --------------------------------------------------------------------------
409//
410//! Add the string pointed to by ptr to the given string.
411//!
412//! @param str
413//! Reference to the string to which the ptr should be added
414//!
415//! @param ptr
416//! Pointer to the binary representation. It will be incremented
417//! according to the size of the template argument
418//!
419void Converter::AddString(string &str, const char* &ptr) const
420{
421 const string txt(ptr);
422 str += ' '+txt;
423 ptr += txt.length()+1;
424}
425
426// --------------------------------------------------------------------------
427//
428//! Add the string pointed to by ptr as boost::any to the provided vector
429//!
430//! @param vec
431//! Vector to which the boost::any object should be added
432//!
433//! @param ptr
434//! Pointer to the binary representation. It will be incremented
435//! according to the size of the template argument
436//!
437void Converter::AddString(vector<boost::any> &vec, const char* &ptr) const
438{
439 const string txt(ptr);
440 vec.push_back(txt);
441 ptr += txt.length()+1;
442}
443
444// --------------------------------------------------------------------------
445//
446//! Compiles the format string into fList. See Compile() for more details.
447//!
448//! @param out
449//! Output stream to which possible logging is redirected
450//!
451//! @param fmt
452//! Format to be compiled. For details see class reference
453//!
454//! @param strict
455//! Setting this to true allows non DIM options, whiel false
456//! will restrict the possible format strings to the ones also
457//! understood by DIM.
458//!
459Converter::Converter(std::ostream &out, const std::string &fmt, bool strict)
460: wout(out), fFormat(Clean(fmt)), fList(Compile(out, fmt, strict))
461{
462}
463
464// --------------------------------------------------------------------------
465//
466//! Compiles the format string into fList.
467//!
468//! Output by default is redirected to cout.
469//!
470//! @param fmt
471//! Format to be compiled. For details see class reference
472//!
473//! @param strict
474//! Setting this to true allows non DIM options, whiel false
475//! will restrict the possible format strings to the ones also
476//! understood by DIM.
477//!
478Converter::Converter(const std::string &fmt, bool strict)
479: wout(cout), fFormat(Clean(fmt)), fList(Compile(fmt, strict))
480{
481}
482
483// --------------------------------------------------------------------------
484//
485//! Converts the provided format string into a vector.
486//!
487//! @tparam T
488//! Kind of data to be returned. This can either be boost::any objects
489//! or a bnary data-block (char).
490//!
491//! @param str
492//! Data to be converted. For details see class reference
493//!
494//! @returns
495//! A vector of the given template type containing the arguments. In
496//! case of failure an empty vector is returned.
497//!
498//! @throws
499//! std::runtime_error if the conversion was not successfull
500//!
501template <class T>
502vector<T> Converter::Get(const std::string &str) const
503{
504 if (!valid())
505 throw runtime_error("Compiled format invalid!");
506
507 // If the format is empty we are already done
508 if (empty() && str.empty())
509 {
510 wout << endl;
511 return vector<T>();
512 }
513
514 int arg = 0;
515 stringstream line(str);
516
517 vector<T> data;
518
519 for (Converter::FormatList::const_iterator i=fList.begin(); i<fList.end()-1; i++)
520 {
521 if (*i->first.first == typeid(string))
522 {
523 GetBinString(data, GetStringEol(line));
524 line.clear(ios::eofbit);
525 continue;
526 }
527
528 // Get as many items from the input line as requested
529 for (int j=0; j<i->second.first; j++)
530 {
531 switch (i->first.first->name()[0])
532 {
533 case 'b': GetBinImp(data, GetBool(line)); break;
534 case 's': GetBinImp(data, Get<short> (line)); break;
535 case 'i': GetBinImp(data, Get<int> (line)); break;
536 case 'l': GetBinImp(data, Get<long> (line)); break;
537 case 'f': GetBinImp(data, Get<float> (line)); break;
538 case 'd': GetBinImp(data, Get<double> (line)); break;
539 case 'x': GetBinImp(data, Get<long long>(line)); break;
540 case 'c':
541 {
542 const unsigned short val = Get<unsigned short>(line);
543 if (val>255)
544 line.setstate(ios::failbit);
545 GetBinImp(data, static_cast<unsigned char>(val));
546 }
547 break;
548 case 'N':
549 GetBinString(data, GetString(line));
550 if (*i->first.first == typeid(O))
551 line.clear(ios::goodbit|(line.rdstate()&ios::eofbit));
552 break;
553 default:
554 // This should never happen!
555 throw runtime_error("Format '"+string(i->first.first->name())+" not supported!");
556 }
557
558 arg++;
559 }
560
561 if (!line)
562 break;
563 }
564 wout << endl;
565
566 // Something wrong with the conversion (e.g. 5.5 for an int)
567 if (line.fail() && !line.eof())
568 {
569 line.clear(); // This is necesasary to get a proper response from tellg()
570
571 ostringstream err;
572 err << "Error converting argument at " << arg << " [fmt=" << fFormat << "]!\n";
573 err << line.str() << "\n";
574 err << setw(int(line.tellg())) << " " << "^\n";
575 throw runtime_error(err.str());
576 }
577
578 // Not enough arguments, we have not reached the end
579 if (line.fail() && line.eof())
580 {
581 line.clear();
582
583 ostringstream err;
584 err << "Not enough arguments [fmt=" << fFormat << "]!\n";
585 err << line.str() << "\n";
586 err << setw(int(line.tellg())+1) << " " << "^\n";
587 throw runtime_error(err.str());
588 }
589
590 // Too many arguments, we have not reached the end
591 // Unfortunately, this can also mean that there is something
592 // wrong with the last argument
593 if (line.good() && !line.eof())
594 {
595 ostringstream err;
596 err << "More arguments available than expected [fmt=" << fFormat << "]!\n";
597 err << line.str() << "\n";
598 err << setw(int(line.tellg())+1) << " " << "^\n";
599 throw runtime_error(err.str());
600 }
601
602 return data;
603
604}
605
606std::vector<boost::any> Converter::GetAny(const std::string &str) const
607{
608 return Get<boost::any>(str);
609}
610
611std::vector<char> Converter::GetVector(const std::string &str) const
612{
613 return Get<char>(str);
614}
615
616// --------------------------------------------------------------------------
617//
618//! Converts the provided data block into a vector of boost::any or
619//! a string.
620//!
621//! @tparam T
622//! Kind of data to be returned. This can either be boost::any objects
623//! or a string
624//!
625//! @returns
626//! A vector of the given template type containing the arguments. In
627//! case of failure an empty vector is returned.
628//!
629//! @throws
630//! std::runtime_error if the conversion was not successfull
631//!
632template<class T>
633T Converter::Get(const void *dat, size_t size) const
634{
635 if (!valid())
636 throw runtime_error("Compiled format invalid!");
637
638 if (dat==0)
639 throw runtime_error("Data pointer == NULL!");
640
641 const char *ptr = reinterpret_cast<const char *>(dat);
642
643 T text;
644 for (Converter::FormatList::const_iterator i=fList.begin(); i<fList.end()-1; i++)
645 {
646 if (ptr-size>dat)
647 {
648 ostringstream err;
649 err << "Format description [fmt=" << fFormat << "|size=" << GetSize() << "] exceeds available data size (" << size << ")";
650 throw runtime_error(err.str());
651 }
652
653 if (*i->first.first == typeid(string))
654 {
655 if (size>0)
656 AddString(text, ptr);
657 if (ptr-size<=dat)
658 return text;
659 break;
660 }
661
662 // Get as many items from the input line as requested
663 for (int j=0; j<i->second.first; j++)
664 {
665 switch (i->first.first->name()[0])
666 {
667 case 'b': Add<bool> (text, ptr); break;
668 case 'c': Add<char> (text, ptr); break;
669 case 's': Add<short> (text, ptr); break;
670 case 'i': Add<int> (text, ptr); break;
671 case 'l': Add<long> (text, ptr); break;
672 case 'f': Add<float> (text, ptr); break;
673 case 'd': Add<double> (text, ptr); break;
674 case 'x': Add<long long>(text, ptr); break;
675 case 'N': AddString(text, ptr); break;
676
677 case 'v':
678 // This should never happen!
679 throw runtime_error("Type 'void' not supported!");
680 default:
681 throw runtime_error("TypeId '"+string(i->first.first->name())+"' not known!");
682 }
683 }
684 }
685
686 if (ptr-size!=dat)
687 {
688 ostringstream err;
689 err << "Data block size (" << size << ") doesn't fit format description [fmt=" << fFormat << "|size=" << GetSize() <<"]";
690 throw runtime_error(err.str());
691 }
692
693 return text;
694}
695
696std::vector<boost::any> Converter::GetAny(const void *dat, size_t size) const
697{
698 return Get<vector<boost::any>>(dat, size);
699}
700
701std::vector<char> Converter::GetVector(const void *dat, size_t size) const
702{
703 const string ref = GetString(dat, size);
704
705 vector<char> data;
706 data.insert(data.begin(), ref.begin()+1, ref.end());
707 data.push_back(0);
708
709 return data;
710}
711
712string Converter::GetString(const void *dat, size_t size) const
713{
714 const string s = Get<string>(dat, size);
715 return s.empty() ? s : s.substr(1);
716}
717
718template<class T>
719Converter::Type Converter::GetType()
720{
721 Type t;
722 t.first = &typeid(T);
723 t.second = sizeof(T);
724 return t;
725}
726
727template<class T>
728Converter::Type Converter::GetVoid()
729{
730 Type t;
731 t.first = &typeid(T);
732 t.second = 0;
733 return t;
734}
735
736// --------------------------------------------------------------------------
737//
738//! static function to compile a format string.
739//!
740//! @param out
741//! Output stream to which possible logging is redirected
742//!
743//! @param fmt
744//! Format to be compiled. For details see class reference
745//!
746//! @param strict
747//! Setting this to true allows non DIM options, whiel false
748//! will restrict the possible format strings to the ones also
749//! understood by DIM.
750//!
751Converter::FormatList Converter::Compile(std::ostream &out, const std::string &fmt, bool strict)
752{
753 ostringstream text;
754
755 // Access both, the data and the format through a stringstream
756 stringstream stream(fmt);
757
758 // For better performance we could use sregex
759 static const boost::regex expr1("^([CSILFDXBOW])(:([1-9]+[0-9]*))?$");
760 static const boost::regex expr2("^([CSILFDX])(:([1-9]+[0-9]*))?$");
761
762 FormatList list;
763 Format format;
764
765 // Tokenize the format
766 string buffer;
767 while (getline(stream, buffer, ';'))
768 {
769 boost::smatch what;
770 if (!boost::regex_match(buffer, what, strict?expr2:expr1))
771 {
772 out << kRed << "Wrong format string '" << buffer << "'!" << endl;
773 return FormatList();
774 }
775
776 const string t = what[1]; // type id
777 const string n = what[3]; // counter
778
779 const int cnt = n.empty() ? 0 : stoi(n);
780
781 // if the :N part was not given assume 1
782 format.second.first = cnt == 0 ? 1 : cnt;
783
784 /*
785 if (strict && t[0]=='C' && cnt>0)
786 {
787 out << kRed << "Dim doesn't support the format C with N>0!" << endl;
788 return FormatList();
789 }*/
790
791 // Check if the format is just C (without a number)
792 // That would mean that it is a \0 terminated string
793 if (t[0]=='C' && cnt==0)
794 {
795 format.first = GetType<string>();
796 list.push_back(format);
797 format.second.second = 0; // end position not known
798 break;
799 }
800
801 // Get as many items from the input line as requested
802 switch (t[0])
803 {
804 case 'B': format.first = GetType<bool>(); break;
805 case 'C': format.first = GetType<char>(); break;
806 case 'S': format.first = GetType<short>(); break;
807 case 'I': format.first = GetType<int>(); break;
808 case 'L': format.first = GetType<long>(); break;
809 case 'F': format.first = GetType<float>(); break;
810 case 'D': format.first = GetType<double>(); break;
811 case 'X': format.first = GetType<long long>(); break;
812 case 'O': format.first = GetVoid<O>(); break;
813 case 'W': format.first = GetVoid<W>(); break;
814 default:
815 // This should never happen!
816 out << kRed << "Format '" << t[0] << " not known!" << endl;
817 return list;
818 }
819
820 list.push_back(format);
821 format.second.second += format.first.second * format.second.first;
822 }
823
824 format.first = GetVoid<void>();
825 format.second.first = 0;
826
827 list.push_back(format);
828
829 return list;
830}
831
832// --------------------------------------------------------------------------
833//
834//! Same as Compile(ostream&,string&,bool) but cout is used as the default
835//! output stream.
836//!
837//!
838Converter::FormatList Converter::Compile(const std::string &fmt, bool strict)
839{
840 return Compile(cout, fmt, strict);
841}
842
843vector<string> Converter::Regex(const string &expr, const string &line)
844{
845 const boost::regex reg(expr);
846
847 boost::smatch what;
848 if (!boost::regex_match(line, what, reg, boost::match_extra))
849 return vector<string>();
850
851 vector<string> ret;
852 for (unsigned int i=0; i<what.size(); i++)
853 ret.push_back(what[i]);
854
855 return ret;
856}
857
858// --------------------------------------------------------------------------
859//
860//! @param dest
861//! Array to which the destination data is written
862//! @param src
863//! Array with the source data according to the format stored in the
864//! Converter
865//! @param size
866//! size of the destination data in bytes
867//!
868void Converter::ToFits(void *dest, const void *src, size_t size) const
869{
870 // crawl through the src buffer and copy the data appropriately to the
871 // destination buffer
872 // Assumption: the string is always last. This way we
873 // use the provided size to determine the number
874 // of character to copy
875
876 char *charDest = static_cast<char*>(dest);
877 const char *charSrc = static_cast<const char*>(src);
878
879 // We skip the last element 'v'
880 for (Converter::FormatList::const_iterator i=fList.begin(); i!=fList.end()-1; i++)
881 {
882 /*
883 // For speed reasons we don't do a check in the loop
884 if (charDest-size>dest || charSrc-size>src)
885 {
886 ostringstream err;
887 err << "Format description [fmt=" << fFormat << "] exceeds available data size (" << size << ")";
888 throw runtime_error(err.str());
889 }
890 */
891
892 // Skip strings (must be the last, so we could just skip it)
893 const char type = i->first.first->name()[0];
894 if (type=='S')
895 {
896 charSrc += strlen(charSrc)+1;
897 continue;
898 }
899
900 const int s = i->first.second; // size of element
901 const int n = i->second.first; // number of elements
902
903 // Check if there are types with unknown sizes
904 if (s==0 || n==0)
905 throw runtime_error(string("Type '")+type+"' not supported converting to FITS.");
906
907 // Let the compiler do some optimization
908 switch (s)
909 {
910 case 1: memcpy(charDest, charSrc, s*n); charSrc+=s*n; charDest+=s*n; break;
911 case 2: for (int j=0; j<n; j++) { reverse_copy(charSrc, charSrc+2, charDest); charSrc+=2; charDest+=2; } break;
912 case 4: for (int j=0; j<n; j++) { reverse_copy(charSrc, charSrc+4, charDest); charSrc+=4; charDest+=4; } break;
913 case 8: for (int j=0; j<n; j++) { reverse_copy(charSrc, charSrc+8, charDest); charSrc+=8; charDest+=8; } break;
914 }
915 }
916
917 if (charDest-size!=dest/* || charSrc-size!=src*/)
918 {
919 ostringstream err;
920 err << "ToFits - Data block size (" << size << ") doesn't fit format description [fmt=" << fFormat << "|size=" << GetSize() << "]";
921 throw runtime_error(err.str());
922 }
923}
924
925vector<string> Converter::ToStrings(const void *src/*, size_t size*/) const
926{
927 const char *charSrc = static_cast<const char*>(src);
928
929 vector<string> rc;
930
931 for (Converter::FormatList::const_iterator i=fList.begin(); i!=fList.end(); i++)
932 {
933 /*
934 if (charSrc-size>src)
935 {
936 ostringstream err;
937 err << "Format description [fmt=" << fFormat << "] exceeds available data size (" << size << ")";
938 throw runtime_error(err.str());
939 }*/
940
941 const char type = i->first.first->name()[0];
942 if (type=='v')
943 break;
944
945 if (type=='S')
946 {
947 const string str(charSrc);
948 rc.push_back(str);
949 charSrc += str.length()+1;
950 continue;
951 }
952
953 // string types
954 //if (string("bsilfdxc").find_first_of(type)==string::npos)
955 // throw runtime_error(string("Type '")+type+"' not supported converting to FITS.");
956
957 const int s = i->first.second; // size of element
958 const int n = i->second.first; // number of elements
959
960 charSrc += s*n;
961 }
962
963 return rc;
964
965 /*
966 if (charSrc-size!=src)
967 {
968 ostringstream err;
969 err << "Data block size (" << size << ") doesn't fit format description [fmt=" << fFormat << "]";
970 throw runtime_error(err.str());
971 }*/
972}
973
974vector<char> Converter::ToFits(const void *src, size_t size) const
975{
976 vector<char> dest(size);
977 ToFits(dest.data(), src, size);
978 return dest;
979}
980
981string Converter::ToFormat(const vector<string> &fits)
982{
983 ostringstream str;
984 for (vector<string>::const_iterator it=fits.begin(); it!=fits.end(); it++)
985 {
986 size_t id=0;
987 int n;
988
989 try
990 {
991 n = stoi(*it, &id);
992 }
993 catch (exception&)
994 {
995 n = 1;
996 }
997
998 if (n==0)
999 continue;
1000
1001 switch ((*it)[id])
1002 {
1003 case 'L':
1004 case 'B': str << ";C:" << n; break;
1005 case 'J': str << ";I:" << n; break;
1006 case 'I': str << ";S:" << n; break;
1007 case 'K': str << ";X:" << n; break;
1008 case 'E': str << ";F:" << n; break;
1009 case 'D': str << ";D:" << n; break;
1010 default:
1011 throw runtime_error("ToFormat - id not known.");
1012 }
1013 }
1014
1015 return str.str().substr(1);
1016}
1017
1018vector<string> Converter::GetFitsFormat() const
1019{
1020 //we've got a nice structure describing the format of this service's messages.
1021 //Let's create the appropriate FITS columns
1022 vector<string> vec;
1023 for (FormatList::const_iterator it=fList.begin(); it!=fList.end(); it++)
1024 {
1025 ostringstream dataQualifier;
1026 dataQualifier << it->second.first;
1027
1028 switch (it->first.first->name()[0])
1029 {
1030 case 'c': dataQualifier << 'B'; break;
1031 case 's': dataQualifier << 'I'; break;
1032 case 'i': dataQualifier << 'J'; break;
1033 case 'l': dataQualifier << 'J'; break;
1034 case 'f': dataQualifier << 'E'; break;
1035 case 'd': dataQualifier << 'D'; break;
1036 case 'x': dataQualifier << 'K'; break;
1037 case 'v':
1038 case 'S': //we skip the variable length strings
1039 continue;
1040
1041 default:
1042 throw runtime_error("GetFitsFormat - unknown FITS format.");
1043 };
1044
1045 vec.push_back(dataQualifier.str());
1046 }
1047
1048 return vec;
1049}
1050
1051void Converter::Print(std::ostream &out) const
1052{
1053 for (FormatList::const_iterator i=fList.begin(); i!=fList.end(); i++)
1054 {
1055 out << "Type=" << i->first.first->name() << "[" << i->first.second << "] ";
1056 out << "N=" << i->second.first << " ";
1057 out << "offset=" << i->second.second << endl;
1058 }
1059}
1060
1061void Converter::Print() const
1062{
1063 return Print(cout);
1064}
Note: See TracBrowser for help on using the repository browser.