Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core2/src/util/Convert.h @ 1031

Last change on this file since 1031 was 1004, checked in by landauf, 16 years ago

test

File size: 23.1 KB
RevLine 
[961]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *
4 *
5 *   License notice:
6 *
7 *   This program is free software; you can redistribute it and/or
8 *   modify it under the terms of the GNU General Public License
9 *   as published by the Free Software Foundation; either version 2
10 *   of the License, or (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with this program; if not, write to the Free Software
19 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 *
21 *   Author:
22 *      Benjamin Grauer
[1003]23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
[961]26 */
27
28/*!
29    @file Convert.h
30    @brief Definition and Implementation of the Convert class.
31*/
32
33#ifndef _Convert_H__
34#define _Convert_H__
35
36#include <string>
37#include <sstream>
38
39#include "UtilPrereqs.h"
40#include "Math.h"
41#include "SubString.h"
42#include "MultiTypeMath.h"
[1001]43
44
45//////////
[1004]46// MAIN //
[1001]47//////////
[1003]48
49// Enum to declare the wanted conversion preference in case of equal type-levels
[1001]50enum ConversionPreference
51{
[1003]52    CP_PreferToType,
53    CP_PreferFromType,
[1001]54};
55
56// Helper classes to determine the preferred partial template specialization
[1003]57class _ToType_   {};
58class _FromType_ {};
59class _Explicit_ {};
[1001]60
61
62// The default convert functions
[1003]63template <class FromType, class ToType, class Type>
64struct ConverterSpecialized
65{
66    enum { specialized = false };
67    static bool convert(ToType* output, const FromType& input)
68    { return false; }
69};
[1001]70
71
72// The default convert function if both types are the same
73template <class BothTypes>
[1003]74struct ConverterSpecialized<BothTypes, BothTypes, _Explicit_>
[1001]75{
[1003]76    enum { specialized = true };
77    static bool convert(BothTypes* output, const BothTypes& input)
[1001]78    { (*output) = input; return true; }
[1003]79};
[1001]80
81
[1003]82// The possible levels
83#define __low__  0 // Everything that is or behaves like a primitive type (an can be converted with a typecast to every other low-level type)
84#define __mid__  1 // Everything that has overloaded << and >> operators to operate on a std::stream
85#define __high__ 2 // Everything that doesn't fullfill the lowerlevel-requirements and therefore needs specialized conversions
[1001]86
[1003]87// Defines the levels of all types: Default is __high__ so you don't have to define every high-level type
88template <class T> struct ConverterLevel           { enum { level = __high__ }; };
89template <> struct ConverterLevel<std::string>     { enum { level = __mid__ }; };
90template <> struct ConverterLevel<orxonox::Radian> { enum { level = __mid__ }; };
91template <> struct ConverterLevel<orxonox::Degree> { enum { level = __mid__ }; };
92template <> struct ConverterLevel<int>             { enum { level = __low__ }; };
93template <> struct ConverterLevel<unsigned int>    { enum { level = __low__ }; };
94template <> struct ConverterLevel<char>            { enum { level = __low__ }; };
95template <> struct ConverterLevel<unsigned char>   { enum { level = __low__ }; };
96template <> struct ConverterLevel<short>           { enum { level = __low__ }; };
97template <> struct ConverterLevel<unsigned short>  { enum { level = __low__ }; };
98template <> struct ConverterLevel<long>            { enum { level = __low__ }; };
99template <> struct ConverterLevel<unsigned long>   { enum { level = __low__ }; };
100template <> struct ConverterLevel<float>           { enum { level = __low__ }; };
101template <> struct ConverterLevel<double>          { enum { level = __low__ }; };
102template <> struct ConverterLevel<long double>     { enum { level = __low__ }; };
103template <> struct ConverterLevel<bool>            { enum { level = __low__ }; };
[1001]104
105
[1003]106// Calculates the preference based on the levels of FromType and ToType
107template <int from, int to>
108struct ConverterPreference
109{
110    enum
[1001]111    {
[1003]112        // The maximum of both levels: element of {0, 1, 2}
113        // max 0: Both types are primitives or have a similar behaviour
114        // max 1: At least one type is not a primitive, but both can be put on a std::stream
115        // max 2: There is at least one generic type that needs specialized conversions
116        max = (from > to) ? from : to,
[1001]117
[1003]118        // The difference between both levels limited to +-1: element of {-1, 0, 1}
119        // diff -1: The FromType has higher level than the ToType
120        // diff  0: Both types have the same level
121        // diff  1: The ToType has higher level than the FromType
122        diff = ((to - from) > 1) ? 1 : (((to - from) < -1) ? -1 : to - from)
[1001]123    };
[1003]124};
[1001]125
126
[1003]127// The default conversion: This usually does nothing
128template <int max, class FromType, class ToType>
129struct ConverterDefault
130{
131    static bool convert(ToType* output, const FromType& input)
[1001]132    {
[1003]133        return false;
134    }
135};
136// The default conversion for primitives: A typecast (defined over two partial specialized templates to exclude all non-primitive types and classes)    template <int max, class FromType, class ToType>
137template <class FromType, class ToType>
138struct ConverterDefault<0, FromType, ToType>
139{
140    static bool convert(ToType* output, const FromType& input)
[1001]141    {
[1003]142        (*output) = (ToType)input;
143        return true;
144    }
145};
[1001]146
147
[1003]148// Converter: Converts input of FromType into output of ToType
149template <int diff, int max, class FromType, class ToType, ConversionPreference pref>
150struct Converter
151{
152    static bool convert(ToType* output, const FromType& input)
[1001]153    {
[1003]154        return false;
155    }
156};
157// Converter: level{FromType} > level{ToType}
158template <int max, class FromType, class ToType, ConversionPreference pref>
159struct Converter<-1, max, FromType, ToType, pref>
160{   static bool convert(ToType* output, const FromType& input)
161    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _FromType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _FromType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
162// Converter: level{FromType} < level{ToType}
163template <int max, class FromType, class ToType, ConversionPreference pref>
164struct Converter<1, max, FromType, ToType, pref>
165{   static bool convert(ToType* output, const FromType& input)
166    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _ToType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _ToType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
167// Converter: level{FromType} = level{ToType}
168// CP_PreferToType
169template <int max, class FromType, class ToType>
170struct Converter<0, max, FromType, ToType, CP_PreferToType>
171{   static bool convert(ToType* output, const FromType& input)
172    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _ToType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _ToType_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _FromType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _FromType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
173// CP_PreferFromType
174template <int max, class FromType, class ToType>
175struct Converter<0, max, FromType, ToType, CP_PreferFromType>
176{   static bool convert(ToType* output, const FromType& input)
177    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _FromType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _FromType_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _ToType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _ToType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
[1001]178
179
[1003]180// Calls the Converter::convertValue function with the correct template type parameters calculated by ConverterPreference
181template <class FromType, class ToType>
182static bool convertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
183{
184    return (preference == CP_PreferToType) ?
185           Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
186                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
187                     FromType,
188                     ToType,
189                     CP_PreferToType>::convert(output, input)
190         : Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
191                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
192                     FromType,
193                     ToType,
194                     CP_PreferFromType>::convert(output, input);
195}
[1001]196
197
[1004]198//////////////////////
199// HELPER FUNCTIONS //
200//////////////////////
201
[1001]202// Helper function: Calls convertValue with and without default value and returns true if the conversion was successful
203template<class FromType, class ToType>
[1003]204static bool ConvertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
[1001]205{
206    return convertValue(output, input, preference);
207}
208template<class FromType, class ToType>
[1003]209static bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
[1001]210{
211    if (convertValue(output, input, preference))
212        return true;
213
214    (*output) = fallback;
215    return false;
216}
217
218// Helper function: Calls convertValue with and without default value and returns the converted value
219template<class FromType, class ToType>
[1003]220static ToType getConvertedValue(const FromType& input, ConversionPreference preference = CP_PreferToType)
[1001]221{
222    ToType output = ToType();
223    ConvertValue(&output, input, preference);
224    return output;
225}
226template<class FromType, class ToType>
[1003]227static ToType getConvertedValue(const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
[1001]228{
229    ToType output = fallback;
230    ConvertValue(&output, input, fallback, preference);
231    return output;
232}
[1004]233
[961]234
[1001]235/////////////////////
[1004]236// SPECIALIZATIONS //
[1001]237/////////////////////
238
[1003]239/////////////
[1004]240// SAMPLES //
[1003]241/////////////
[1001]242/*
[1003]243// convert everything to xyz
[1001]244template <class FromType>
[1003]245struct ConverterSpecialized<FromType, xyz, _ToType_>
[1001]246{
[1003]247    enum { specialized = true };
248    static bool convert(xyz* output, const FromType& input)
249    { return ...; }
250};
[1001]251
[1003]252// convert xyz to everything
[1001]253template <class ToType>
[1003]254struct ConverterSpecialized<xyz, ToType, _FromType_>
[1001]255{
[1003]256    enum { specialized = true };
257    static bool convert(ToType* output, const xyz& input)
258    { return ...; }
259};
[1001]260
[1003]261// convert abc to xyz
[1001]262template <>
[1003]263struct ConverterSpecialized<abc, xyz, _Explicit_>
[1001]264{
[1003]265    enum { specialized = true };
266    static bool convert(xyz* output, const abc& input)
267    { return ...; }
268};
[1001]269*/
270
271////////////
[1004]272// STRING //
[1001]273////////////
274
275// convert to string
276template <class FromType>
[1003]277struct ConverterSpecialized<FromType, std::string, _ToType_>
[1001]278{
[1003]279    enum { specialized = true };
280    static bool convert(std::string* output, const FromType& input)
[1001]281    {
[1003]282        std::ostringstream oss;
283        if (oss << input)
284        {
285            (*output) = oss.str();
286            return true;
287        }
288        else
289            return false;
[1001]290    }
[1003]291};
[1001]292
293// convert from string
294template <class ToType>
[1003]295struct ConverterSpecialized<std::string, ToType, _FromType_>
[1001]296{
[1003]297    enum { specialized = true };
298    static bool convert(ToType* output, const std::string& input)
299    {
300        std::istringstream iss(input);
301        if (iss >> (*output))
302            return true;
303        else
304            return false;
305    }
306};
[1001]307
308
309////////////////
310// MULTITYPES //
311////////////////
312
313// convert from MultiTypePrimitive
314template <class ToType>
[1003]315struct ConverterSpecialized<MultiTypePrimitive, ToType, _FromType_>
[1001]316{
[1003]317    enum { specialized = true };
318    static bool convert(ToType* output, const MultiTypePrimitive& input)
319    {
320        if (input.getType() == MT_void)
321            return ConvertValue(output, input.getVoid());
322        else if (input.getType() == MT_int)
323            return ConvertValue(output, input.getInt());
324        else if (input.getType() == MT_uint)
325            return ConvertValue(output, input.getUnsignedInt());
326        else if (input.getType() == MT_char)
327            return ConvertValue(output, input.getChar());
328        else if (input.getType() == MT_uchar)
329            return ConvertValue(output, input.getUnsignedChar());
330        else if (input.getType() == MT_short)
331            return ConvertValue(output, input.getShort());
332        else if (input.getType() == MT_ushort)
333            return ConvertValue(output, input.getUnsignedShort());
334        else if (input.getType() == MT_long)
335            return ConvertValue(output, input.getLong());
336        else if (input.getType() == MT_ulong)
337            return ConvertValue(output, input.getUnsignedLong());
338        else if (input.getType() == MT_float)
339            return ConvertValue(output, input.getFloat());
340        else if (input.getType() == MT_double)
341            return ConvertValue(output, input.getDouble());
342        else if (input.getType() == MT_longdouble)
343            return ConvertValue(output, input.getLongDouble());
344        else if (input.getType() == MT_bool)
345            return ConvertValue(output, input.getBool());
346        else
347            return false;
348    }
349};
[1001]350
351// convert from MultiTypeString
352template <class ToType>
[1003]353struct ConverterSpecialized<MultiTypeString, ToType, _FromType_>
[1001]354{
[1003]355    enum { specialized = true };
356    static bool convert(ToType* output, const MultiTypeString& input)
357    {
358        if (input.getType() == MT_constchar)
359            return ConvertValue(output, input.getConstChar());
360        else if (input.getType() == MT_string)
361            return ConvertValue(output, input.getString());
362        else
363            return ConvertValue(output, (MultiTypePrimitive)input);
364    }
365};
[1001]366
367// convert from MultiTypeMath
368template <class ToType>
[1003]369struct ConverterSpecialized<MultiTypeMath, ToType, _FromType_>
[1001]370{
[1003]371    enum { specialized = true };
372    static bool convert(ToType* output, const MultiTypeMath& input)
373    {
374        if (input.getType() == MT_vector2)
375            return ConvertValue(output, input.getVector2());
376        else if (input.getType() == MT_vector3)
377            return ConvertValue(output, input.getVector3());
378        else if (input.getType() == MT_quaternion)
379            return ConvertValue(output, input.getQuaternion());
380        else if (input.getType() == MT_colourvalue)
381            return ConvertValue(output, input.getColourValue());
382        else if (input.getType() == MT_radian)
383            return ConvertValue(output, input.getRadian());
384        else if (input.getType() == MT_degree)
385            return ConvertValue(output, input.getDegree());
386        else
387            return ConvertValue(output, (MultiTypeString)input);
388    }
389};
[1001]390
[961]391
392////////////////////
393// MATH TO STRING //
394////////////////////
[1001]395
396// Vector2 to std::string
397template <>
[1003]398struct ConverterSpecialized<orxonox::Vector2, std::string, _Explicit_>
[1001]399{
[1003]400    enum { specialized = true };
401    static bool convert(std::string* output, const orxonox::Vector2& input)
[1001]402    {
[1003]403        std::ostringstream ostream;
404        if (ostream << input.x << "," << input.y)
405        {
406            (*output) = ostream.str();
407            return true;
408        }
409        return false;
[1001]410    }
[1003]411};
[1001]412
413// Vector3 to std::string
414template <>
[1003]415struct ConverterSpecialized<orxonox::Vector3, std::string, _Explicit_>
[1001]416{
[1003]417    enum { specialized = true };
418    static bool convert(std::string* output, const orxonox::Vector3& input)
[1001]419    {
[1003]420        std::ostringstream ostream;
421        if (ostream << input.x << "," << input.y << "," << input.z)
422        {
423            (*output) = ostream.str();
424            return true;
425        }
426        return false;
[1001]427    }
[1003]428};
[1001]429
430// Vector4 to std::string
431template <>
[1003]432struct ConverterSpecialized<orxonox::Vector4, std::string, _Explicit_>
[1001]433{
[1003]434    enum { specialized = true };
435    static bool convert(std::string* output, const orxonox::Vector4& input)
[1001]436    {
[1003]437        std::ostringstream ostream;
438        if (ostream << input.x << "," << input.y << "," << input.z << "," << input.w)
439        {
440            (*output) = ostream.str();
441            return true;
442        }
443        return false;
[1001]444    }
[1003]445};
446
[1001]447// Quaternion to std::string
448template <>
[1003]449struct ConverterSpecialized<orxonox::Quaternion, std::string, _Explicit_>
[1001]450{
[1003]451    enum { specialized = true };
452    static bool convert(std::string* output, const orxonox::Quaternion& input)
[1001]453    {
[1003]454        std::ostringstream ostream;
455        if (ostream << input.w << "," << input.x << "," << input.y << "," << input.z)
456        {
457            (*output) = ostream.str();
458            return true;
459        }
460        return false;
[1001]461    }
[1003]462};
463
[1001]464// ColourValue to std::string
465template <>
[1003]466struct ConverterSpecialized<orxonox::ColourValue, std::string, _Explicit_>
[1001]467{
[1003]468    enum { specialized = true };
469    static bool convert(std::string* output, const orxonox::ColourValue& input)
[1001]470    {
[1003]471        std::ostringstream ostream;
472        if (ostream << input.r << "," << input.g << "," << input.b << "," << input.a)
473        {
474            (*output) = ostream.str();
475            return true;
476        }
477        return false;
[1001]478    }
[1003]479};
[1001]480
481
[961]482////////////////////
483// STRING TO MATH //
484////////////////////
[1001]485
486// std::string to Vector2
487template <>
[1003]488struct ConverterSpecialized<std::string, orxonox::Vector2, _Explicit_>
[1001]489{
[1003]490    enum { specialized = true };
491    static bool convert(orxonox::Vector2* output, const std::string& input)
[1001]492    {
[1003]493        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
494        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[1001]495
[1003]496        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
497        if (tokens.size() >= 2)
498        {
499            if (!ConvertValue(&(output->x), tokens[0]))
500                return false;
501            if (!ConvertValue(&(output->y), tokens[1]))
502                return false;
503
504            return true;
505        }
506        return false;
[1001]507    }
[1003]508};
509
[1001]510// std::string to Vector3
511template <>
[1003]512struct ConverterSpecialized<std::string, orxonox::Vector3, _Explicit_>
[1001]513{
[1003]514    enum { specialized = true };
515    static bool convert(orxonox::Vector3* output, const std::string& input)
[1001]516    {
[1003]517        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
518        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[1001]519
[1003]520        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
521        if (tokens.size() >= 3)
522        {
523            if (!ConvertValue(&(output->x), tokens[0]))
524                return false;
525            if (!ConvertValue(&(output->y), tokens[1]))
526                return false;
527            if (!ConvertValue(&(output->z), tokens[2]))
528                return false;
529
530            return true;
531        }
532        return false;
[1001]533    }
[1003]534};
535
[1001]536// std::string to Vector4
537template <>
[1003]538struct ConverterSpecialized<std::string, orxonox::Vector4, _Explicit_>
[1001]539{
[1003]540    enum { specialized = true };
541    static bool convert(orxonox::Vector4* output, const std::string& input)
[1001]542    {
[1003]543        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
544        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[1001]545
[1003]546        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
547        if (tokens.size() >= 4)
548        {
549            if (!ConvertValue(&(output->x), tokens[0]))
550                return false;
551            if (!ConvertValue(&(output->y), tokens[1]))
552                return false;
553            if (!ConvertValue(&(output->z), tokens[2]))
554                return false;
555            if (!ConvertValue(&(output->w), tokens[3]))
556                return false;
557
558            return true;
559        }
560        return false;
[1001]561    }
[1003]562};
563
[1001]564// std::string to Quaternion
565template <>
[1003]566struct ConverterSpecialized<std::string, orxonox::Quaternion, _Explicit_>
[1001]567{
[1003]568    enum { specialized = true };
569    static bool convert(orxonox::Quaternion* output, const std::string& input)
[1001]570    {
[1003]571        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
572        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[1001]573
[1003]574        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
575        if (tokens.size() >= 4)
576        {
577            if (!ConvertValue(&(output->w), tokens[0]))
578                return false;
579            if (!ConvertValue(&(output->x), tokens[1]))
580                return false;
581            if (!ConvertValue(&(output->y), tokens[2]))
582                return false;
583            if (!ConvertValue(&(output->z), tokens[3]))
584                return false;
585
586            return true;
587        }
588        return false;
[1001]589    }
[1003]590};
591
[1001]592// std::string to ColourValue
593template <>
[1003]594struct ConverterSpecialized<std::string, orxonox::ColourValue, _Explicit_>
[1001]595{
[1003]596    enum { specialized = true };
597    static bool convert(orxonox::ColourValue* output, const std::string& input)
[1001]598    {
[1003]599        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
600        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[1001]601
[1003]602        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
603        if (tokens.size() >= 4)
604        {
605            if (!ConvertValue(&(output->r), tokens[0]))
606                return false;
607            if (!ConvertValue(&(output->g), tokens[1]))
608                return false;
609            if (!ConvertValue(&(output->b), tokens[2]))
610                return false;
611            if (!ConvertValue(&(output->a), tokens[3]))
612                return false;
613
614            return true;
615        }
616        return false;
[1001]617    }
618};
[961]619
620#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.