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