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

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