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

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