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

Last change on this file since 19438 was 18613, checked in by tbretz, 3 years ago
With gcc 5 it seems N also identifies our strings... this might still require more changes!
File size: 30.8 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' || type=='N')
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         case 'N':
1064             continue;
1065
1066         default:
1067             throw runtime_error(string("GetFitsFormat - unknown FITS format [")+it->first.first->name()[0]+"]");
1068         };
1069
1070         vec.push_back(dataQualifier.str());
1071    }
1072
1073    return vec;
1074}
1075
1076void Converter::Print(std::ostream &out) const
1077{
1078    for (FormatList::const_iterator i=fList.begin(); i!=fList.end(); i++)
1079    {
1080        out << "Type=" << i->first.first->name() << "[" << i->first.second << "]  ";
1081        out << "N=" << i->second.first << "  ";
1082        out << "offset=" << i->second.second << endl;
1083    }
1084}
1085
1086void Converter::Print() const
1087{
1088    return Print(cout);
1089}
Note: See TracBrowser for help on using the repository browser.