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

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