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

Last change on this file since 14574 was 12846, checked in by tbretz, 13 years ago
Allow 'A' when converting FITS format to Dim format.
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 switch (i->first.first->name()[0])
676 {
677 case 'b': Add<bool> (text, ptr); break;
678 case 'c': Add<char> (text, ptr); break;
679 case 's': Add<short> (text, ptr); break;
680 case 'i': Add<int> (text, ptr); break;
681 case 'l': Add<long> (text, ptr); break;
682 case 'f': Add<float> (text, ptr); break;
683 case 'd': Add<double> (text, ptr); break;
684 case 'x': Add<long long>(text, ptr); break;
685 case 'N': AddString(text, ptr); break;
686
687 case 'v':
688 // This should never happen!
689 throw runtime_error("Type 'void' not supported!");
690 default:
691 throw runtime_error("TypeId '"+string(i->first.first->name())+"' not known!");
692 }
693 }
694 }
695
696 if (ptr-size!=dat)
697 {
698 ostringstream err;
699 err << "Data block size (" << size << ") doesn't fit format description [fmt=" << fFormat << "|size=" << GetSize() <<"]";
700 throw runtime_error(err.str());
701 }
702
703 return text;
704}
705
706std::vector<boost::any> Converter::GetAny(const void *dat, size_t size) const
707{
708 return Get<vector<boost::any>>(dat, size);
709}
710
711std::vector<char> Converter::GetVector(const void *dat, size_t size) const
712{
713 const string ref = GetString(dat, size);
714
715 vector<char> data;
716 data.insert(data.begin(), ref.begin()+1, ref.end());
717 data.push_back(0);
718
719 return data;
720}
721
722string Converter::GetString(const void *dat, size_t size) const
723{
724 const string s = Get<string>(dat, size);
725 return s.empty() ? s : s.substr(1);
726}
727
728template<class T>
729Converter::Type Converter::GetType()
730{
731 Type t;
732 t.first = &typeid(T);
733 t.second = sizeof(T);
734 return t;
735}
736
737template<class T>
738Converter::Type Converter::GetVoid()
739{
740 Type t;
741 t.first = &typeid(T);
742 t.second = 0;
743 return t;
744}
745
746// --------------------------------------------------------------------------
747//
748//! static function to compile a format string.
749//!
750//! @param out
751//! Output stream to which possible logging is redirected
752//!
753//! @param fmt
754//! Format to be compiled. For details see class reference
755//!
756//! @param strict
757//! Setting this to true allows non DIM options, whiel false
758//! will restrict the possible format strings to the ones also
759//! understood by DIM.
760//!
761Converter::FormatList Converter::Compile(std::ostream &out, const std::string &fmt, bool strict)
762{
763 ostringstream text;
764
765 // Access both, the data and the format through a stringstream
766 stringstream stream(fmt);
767
768 // For better performance we could use sregex
769 static const boost::regex expr1("^([CSILFDXBOW])(:([1-9]+[0-9]*))?$");
770 static const boost::regex expr2("^([CSILFDX])(:([1-9]+[0-9]*))?$");
771
772 FormatList list;
773 Format format;
774
775 // Tokenize the format
776 string buffer;
777 while (getline(stream, buffer, ';'))
778 {
779 boost::smatch what;
780 if (!boost::regex_match(buffer, what, strict?expr2:expr1))
781 {
782 out << kRed << "Wrong format string '" << buffer << "'!" << endl;
783 return FormatList();
784 }
785
786 const string t = what[1]; // type id
787 const string n = what[3]; // counter
788
789 const int cnt = n.empty() ? 0 : stoi(n);
790
791 // if the :N part was not given assume 1
792 format.second.first = cnt == 0 ? 1 : cnt;
793
794 /*
795 if (strict && t[0]=='C' && cnt>0)
796 {
797 out << kRed << "Dim doesn't support the format C with N>0!" << endl;
798 return FormatList();
799 }*/
800
801 // Check if the format is just C (without a number)
802 // That would mean that it is a \0 terminated string
803 if (t[0]=='C' && cnt==0)
804 {
805 format.first = GetType<string>();
806 list.push_back(format);
807 format.second.second = 0; // end position not known
808 break;
809 }
810
811 // Get as many items from the input line as requested
812 switch (t[0])
813 {
814 case 'B': format.first = GetType<bool>(); break;
815 case 'C': format.first = GetType<char>(); break;
816 case 'S': format.first = GetType<short>(); break;
817 case 'I': format.first = GetType<int>(); break;
818 case 'L': format.first = GetType<long>(); break;
819 case 'F': format.first = GetType<float>(); break;
820 case 'D': format.first = GetType<double>(); break;
821 case 'X': format.first = GetType<long long>(); break;
822 case 'O': format.first = GetVoid<O>(); break;
823 case 'W': format.first = GetVoid<W>(); break;
824 default:
825 // This should never happen!
826 out << kRed << "Format '" << t[0] << " not known!" << endl;
827 return list;
828 }
829
830 list.push_back(format);
831 format.second.second += format.first.second * format.second.first;
832 }
833
834 format.first = GetVoid<void>();
835 format.second.first = 0;
836
837 list.push_back(format);
838
839 return list;
840}
841
842// --------------------------------------------------------------------------
843//
844//! Same as Compile(ostream&,string&,bool) but cout is used as the default
845//! output stream.
846//!
847//!
848Converter::FormatList Converter::Compile(const std::string &fmt, bool strict)
849{
850 return Compile(cout, fmt, strict);
851}
852
853vector<string> Converter::Regex(const string &expr, const string &line)
854{
855 const boost::regex reg(expr);
856
857 boost::smatch what;
858 if (!boost::regex_match(line, what, reg, boost::match_extra))
859 return vector<string>();
860
861 vector<string> ret;
862 for (unsigned int i=0; i<what.size(); i++)
863 ret.push_back(what[i]);
864
865 return ret;
866}
867
868// --------------------------------------------------------------------------
869//
870//! @param dest
871//! Array to which the destination data is written
872//! @param src
873//! Array with the source data according to the format stored in the
874//! Converter
875//! @param size
876//! size of the destination data in bytes
877//!
878void Converter::ToFits(void *dest, const void *src, size_t size) const
879{
880 // crawl through the src buffer and copy the data appropriately to the
881 // destination buffer
882 // Assumption: the string is always last. This way we
883 // use the provided size to determine the number
884 // of character to copy
885
886 char *charDest = static_cast<char*>(dest);
887 const char *charSrc = static_cast<const char*>(src);
888
889 // We skip the last element 'v'
890 for (Converter::FormatList::const_iterator i=fList.begin(); i!=fList.end()-1; i++)
891 {
892 /*
893 // For speed reasons we don't do a check in the loop
894 if (charDest-size>dest || charSrc-size>src)
895 {
896 ostringstream err;
897 err << "Format description [fmt=" << fFormat << "] exceeds available data size (" << size << ")";
898 throw runtime_error(err.str());
899 }
900 */
901
902 // Skip strings (must be the last, so we could just skip it)
903 const char type = i->first.first->name()[0];
904 if (type=='S')
905 {
906 charSrc += strlen(charSrc)+1;
907 continue;
908 }
909
910 const int s = i->first.second; // size of element
911 const int n = i->second.first; // number of elements
912
913 // Check if there are types with unknown sizes
914 if (s==0 || n==0)
915 throw runtime_error(string("Type '")+type+"' not supported converting to FITS.");
916
917 // Let the compiler do some optimization
918 switch (s)
919 {
920 case 1: memcpy(charDest, charSrc, s*n); charSrc+=s*n; charDest+=s*n; break;
921 case 2: for (int j=0; j<n; j++) { reverse_copy(charSrc, charSrc+2, charDest); charSrc+=2; charDest+=2; } break;
922 case 4: for (int j=0; j<n; j++) { reverse_copy(charSrc, charSrc+4, charDest); charSrc+=4; charDest+=4; } break;
923 case 8: for (int j=0; j<n; j++) { reverse_copy(charSrc, charSrc+8, charDest); charSrc+=8; charDest+=8; } break;
924 }
925 }
926
927 if (charDest-size!=dest/* || charSrc-size!=src*/)
928 {
929 ostringstream err;
930 err << "ToFits - Data block size (" << size << ") doesn't fit format description [fmt=" << fFormat << "|size=" << GetSize() << "]";
931 throw runtime_error(err.str());
932 }
933}
934
935vector<string> Converter::ToStrings(const void *src/*, size_t size*/) const
936{
937 const char *charSrc = static_cast<const char*>(src);
938
939 vector<string> rc;
940
941 for (Converter::FormatList::const_iterator i=fList.begin(); i!=fList.end(); i++)
942 {
943 /*
944 if (charSrc-size>src)
945 {
946 ostringstream err;
947 err << "Format description [fmt=" << fFormat << "] exceeds available data size (" << size << ")";
948 throw runtime_error(err.str());
949 }*/
950
951 const char type = i->first.first->name()[0];
952 if (type=='v')
953 break;
954
955 if (type=='S')
956 {
957 const string str(charSrc);
958 rc.push_back(str);
959 charSrc += str.length()+1;
960 continue;
961 }
962
963 // string types
964 //if (string("bsilfdxc").find_first_of(type)==string::npos)
965 // throw runtime_error(string("Type '")+type+"' not supported converting to FITS.");
966
967 const int s = i->first.second; // size of element
968 const int n = i->second.first; // number of elements
969
970 charSrc += s*n;
971 }
972
973 return rc;
974
975 /*
976 if (charSrc-size!=src)
977 {
978 ostringstream err;
979 err << "Data block size (" << size << ") doesn't fit format description [fmt=" << fFormat << "]";
980 throw runtime_error(err.str());
981 }*/
982}
983
984vector<char> Converter::ToFits(const void *src, size_t size) const
985{
986 vector<char> dest(size);
987 ToFits(dest.data(), src, size);
988 return dest;
989}
990
991string Converter::ToFormat(const vector<string> &fits)
992{
993 ostringstream str;
994 for (vector<string>::const_iterator it=fits.begin(); it!=fits.end(); it++)
995 {
996 size_t id=0;
997 int n;
998
999 try
1000 {
1001 n = stoi(*it, &id);
1002 }
1003 catch (exception&)
1004 {
1005 n = 1;
1006 }
1007
1008 if (n==0)
1009 continue;
1010
1011 switch ((*it)[id])
1012 {
1013 case 'A':
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.