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

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