1 // Number.cpp:  ActionScript Number class, for Gnash.
2 //
3 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 //   Free Software Foundation, Inc
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 //
20 
21 
22 #include "log.h"
23 #include "Number_as.h"
24 #include "fn_call.h"
25 #include "Global_as.h"
26 #include "as_object.h" // for inheritance
27 #include "as_value.h" // for doubleToString
28 #include "NativeFunction.h"
29 #include "VM.h"
30 
31 #include "namedStrings.h"
32 #include <sstream>
33 #include <cmath>
34 
35 
36 namespace gnash {
37 
38 class Number_as : public Relay
39 {
40 public:
41 
Number_as(double val)42     Number_as(double val)
43         :
44         _val(val)
45     {
46     }
47 
value() const48     double value() const {
49         return _val;
50     }
51 
52 private:
53 
54     // the number value
55     double _val;
56 
57 };
58 
59 namespace {
60 
61 as_value
number_toString(const fn_call & fn)62 number_toString(const fn_call& fn)
63 {
64     // Number.toString must only work for number object, not generic ones.
65     // This is so trace(Number.prototype) doesn't return 0 ...
66     Number_as* obj = ensure<ThisIsNative<Number_as> >(fn);
67 
68     double val = obj->value();
69     unsigned radix = 10;
70 
71     if ( fn.nargs )
72     {
73         int userRadix = toInt(fn.arg(0), getVM(fn));
74         if ( userRadix >= 2 && userRadix <= 36 ) radix=userRadix;
75         else
76         {
77             IF_VERBOSE_ASCODING_ERRORS(
78             log_aserror(_("Number.toString(%s): "
79                 "radix must be in the 2..36 range (%d is invalid)"),
80                 fn.arg(0), userRadix)
81             )
82         }
83 
84     }
85     return doubleToString(val, radix);
86 }
87 
88 as_value
number_valueOf(const fn_call & fn)89 number_valueOf(const fn_call& fn)
90 {
91     // Number.valueOf must only work for number object, not generic ones.
92     // This is so trace(Number.prototype == Object) return true in swf5 ?
93     Number_as* obj = ensure<ThisIsNative<Number_as> >(fn);
94 
95     return obj->value();
96 }
97 
98 as_value
number_ctor(const fn_call & fn)99 number_ctor(const fn_call& fn)
100 {
101     double val = 0;
102     if (fn.nargs > 0) {
103         val = toNumber(fn.arg(0), getVM(fn));
104     }
105 
106     if (!fn.isInstantiation()) {
107         return as_value(val);
108     }
109 
110     fn.this_ptr->setRelay(new Number_as(val));
111 
112     return as_value();
113 }
114 
115 void
attachNumberInterface(as_object & o)116 attachNumberInterface(as_object& o)
117 {
118     VM& vm = getVM(o);
119     o.init_member("valueOf", vm.getNative(106, 0));
120     o.init_member("toString", vm.getNative(106, 1));
121 }
122 
123 void
attachNumberStaticInterface(as_object & o)124 attachNumberStaticInterface(as_object& o)
125 {
126     // constant flags
127     const int cflags = as_object::DefaultFlags | PropFlags::readOnly;
128 
129     // Set __proto__ and constructor to constant.
130     as_value null; null.set_null();
131     o.setPropFlags(null, 0, cflags);
132 
133     // Not quite the same as numeric_limits<double>::max()
134     o.init_member("MAX_VALUE", 1.79769313486231e+308, cflags);
135     // This is generally numeric_limits<double>::denorm_min().
136     o.init_member("MIN_VALUE", 4.94065645841247e-324, cflags);
137     o.init_member("NaN", as_value(NaN), cflags);
138     o.init_member("POSITIVE_INFINITY",
139             as_value(std::numeric_limits<double>::infinity()), cflags);
140     o.init_member("NEGATIVE_INFINITY",
141             as_value(-std::numeric_limits<double>::infinity()), cflags);
142 }
143 
144 } // anonymous namespace
145 
146 
147 // extern (used by Global.cpp)
148 void
number_class_init(as_object & where,const ObjectURI & uri)149 number_class_init(as_object& where, const ObjectURI& uri)
150 {
151     VM& vm = getVM(where);
152     Global_as& gl = getGlobal(where);
153 
154     as_object* proto = createObject(gl);
155     as_object* cl = vm.getNative(106, 2);
156     cl->init_member(NSV::PROP_PROTOTYPE, proto);
157     proto->init_member(NSV::PROP_CONSTRUCTOR, cl);
158 
159     attachNumberInterface(*proto);
160     attachNumberStaticInterface(*cl);
161 
162     // Register _global.Number
163     where.init_member(uri, cl, as_object::DefaultFlags);
164 
165 }
166 
167 void
registerNumberNative(as_object & global)168 registerNumberNative(as_object& global)
169 {
170     VM& vm = getVM(global);
171     vm.registerNative(number_valueOf, 106, 0);
172     vm.registerNative(number_toString, 106, 1);
173     vm.registerNative(number_ctor, 106, 2);
174 }
175 
176 } // namespace gnash
177