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

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