Fix refcounting in arReturn() and stop leaking static strings.
[hiphop-php.git] / hphp / runtime / ext / wddx / ext_wddx.cpp
blob5df0449209b34a65ffe4d93f0f0c0bb9f33e4f65
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
17 #include "hphp/runtime/ext/wddx/ext_wddx.h"
19 #include <string>
20 #include <vector>
22 namespace HPHP {
24 WddxPacket::WddxPacket(const Variant& comment, bool manualPacket, bool sVar) :
25 m_packetString(""), m_packetClosed(false),
26 m_manualPacketCreation(manualPacket) {
27 std::string header = "<header/>";
29 if (!comment.isNull() && !sVar) {
30 std::string scomment = comment.toString().data();
31 header = "<header><comment>" + scomment + "</comment></header>";
33 m_packetString = "<wddxPacket version='1.0'>" + header + "<data>";
35 if (m_manualPacketCreation) {
36 m_packetString = m_packetString + "<struct>";
40 bool WddxPacket::add_var(const String& varName, bool hasVarTag) {
41 VarEnv* v = g_context->getVarEnv();
42 if (!v) return false;
43 Variant varVariant = *reinterpret_cast<Variant*>(v->lookup(varName.get()));
44 return recursiveAddVar(varName, varVariant, hasVarTag);
47 std::string WddxPacket::packet_end() {
48 if (!m_packetClosed) {
49 if (m_manualPacketCreation) {
50 m_packetString += "</struct>";
52 m_packetString += "</data></wddxPacket>";
54 m_packetClosed = true;
55 return m_packetString;
58 bool WddxPacket::serialize_value(const Variant& varVariant) {
59 return recursiveAddVar(empty_string_ref, varVariant, false);
62 bool WddxPacket::recursiveAddVar(const String& varName,
63 const Variant& varVariant,
64 bool hasVarTag) {
66 bool isArray = varVariant.isArray();
67 bool isObject = varVariant.isObject();
69 if (isArray || isObject) {
70 if (hasVarTag) {
71 m_packetString += "<var name='";
72 m_packetString += varName.data();
73 m_packetString += "'>";
76 Array varAsArray;
77 Object varAsObject = varVariant.toObject();
78 if (isArray) varAsArray = varVariant.toArray();
79 if (isObject) varAsArray = varAsObject.toArray();
81 int length = varAsArray.length();
82 if (length > 0) {
83 ArrayIter it = ArrayIter(varAsArray);
84 if (it.first().isString()) isObject = true;
85 if (isObject) {
86 m_packetString += "<struct>";
87 if (!isArray) {
88 m_packetString += "<var name='php_class_name'><string>";
89 m_packetString += varAsObject->o_getClassName().c_str();
90 m_packetString += "</string></var>";
92 } else {
93 m_packetString += "<array length='";
94 m_packetString += std::to_string(length);
95 m_packetString += "'>";
97 for (ArrayIter it(varAsArray); it; ++it) {
98 Variant key = it.first();
99 Variant value = it.second();
100 recursiveAddVar(key.toString(), value, isObject);
102 if (isObject) {
103 m_packetString += "</struct>";
105 else {
106 m_packetString += "</array>";
109 else {
110 //empty object
111 if (isObject) {
112 m_packetString += "<struct>";
113 if (!isArray) {
114 m_packetString += "<var name='php_class_name'><string>";
115 m_packetString += varAsObject->o_getClassName().c_str();
116 m_packetString += "</string></var>";
118 m_packetString += "</struct>";
121 if (hasVarTag) {
122 m_packetString += "</var>";
124 return true;
127 std::string varType = getDataTypeString(varVariant.getType()).data();
128 if (!getWddxEncoded(varType, "", varName, false).empty()) {
129 std::string varValue = varVariant.toString().data();
130 if (varType.compare("boolean") == 0) {
131 varValue = varVariant.toBoolean() ? "true" : "false";
133 m_packetString += getWddxEncoded(varType, varValue, varName, hasVarTag);
134 return true;
137 return false;
140 std::string WddxPacket::getWddxEncoded(const std::string& varType,
141 const std::string& varValue,
142 const String& varName,
143 bool hasVarTag) {
144 if (varType.compare("NULL") == 0) {
145 return wrapValue("<null/>", "", "", varName, hasVarTag);
147 if (varType.compare("boolean") == 0) {
148 return wrapValue("<boolean value='", "'/>", varValue, varName, hasVarTag);
150 if (varType.compare("integer") == 0 || varType.compare("double") == 0) {
151 return wrapValue("<number>", "</number>", varValue, varName, hasVarTag);
153 if (varType.compare("string") == 0) {
154 return wrapValue("<string>", "</string>", varValue, varName, hasVarTag);
156 return "";
159 std::string WddxPacket::wrapValue(const std::string& start,
160 const std::string& end,
161 const std::string& varValue,
162 const String& varName,
163 bool hasVarTag) {
164 std::string startVar = "";
165 std::string endVar = "";
166 if (hasVarTag) {
167 startVar += "<var name='";
168 startVar += varName.data();
169 startVar += "'>";
170 endVar = "</var>";
172 return startVar + start + varValue + end + endVar;
175 //////////////////////////////////////////////////////////////////////////////
176 // helpers
178 void find_var_recursive(const TypedValue* tv, WddxPacket* wddxPacket) {
179 if (tvIsString(tv)) {
180 String var_name = tvCastToString(tv);
181 wddxPacket->add_var(var_name, true);
183 if (tv->m_type == KindOfArray) {
184 for (ArrayIter iter(tv->m_data.parr); iter; ++iter) {
185 find_var_recursive(iter.secondRef().asTypedValue(), wddxPacket);
190 static TypedValue* add_vars_helper(ActRec* ar) {
191 int start_index = 1;
192 Resource packet_id = getArg<KindOfResource>(ar, 0);
193 auto wddxPacket = packet_id.getTyped<WddxPacket>();
195 for (int i = start_index; i < ar->numArgs(); i++) {
196 auto const tv = getArg(ar, i);
197 find_var_recursive(tv, wddxPacket);
199 return arReturn(ar, true);
202 static TypedValue* serialize_vars_helper(ActRec* ar) {
203 WddxPacket* wddxPacket = NEWOBJ(WddxPacket)(empty_string_variant_ref,
204 true, true);
205 int start_index = 0;
206 for (int i = start_index; i < ar->numArgs(); i++) {
207 auto const tv = getArg(ar, i);
208 find_var_recursive(tv, wddxPacket);
210 Variant packet = wddxPacket->packet_end();
211 return arReturn(ar, std::move(packet));
214 //////////////////////////////////////////////////////////////////////////////
215 // functions
217 static TypedValue* HHVM_FN(wddx_add_vars)(ActRec* ar) {
218 return add_vars_helper(ar);
221 static TypedValue* HHVM_FN(wddx_serialize_vars)(ActRec* ar) {
222 return serialize_vars_helper(ar);
225 static String HHVM_FUNCTION(wddx_packet_end, const Resource& packet_id) {
226 auto wddxPacket = packet_id.getTyped<WddxPacket>();
227 std::string packetString = wddxPacket->packet_end();
228 return String(packetString);
231 static Resource HHVM_FUNCTION(wddx_packet_start, const Variant& comment) {
232 auto wddxPacket = NEWOBJ(WddxPacket)(comment, true, false);
233 return Resource(wddxPacket);
236 static String HHVM_FUNCTION(wddx_serialize_value, const Variant& var,
237 const Variant& comment) {
238 WddxPacket* wddxPacket = NEWOBJ(WddxPacket)(comment, false, false);
239 wddxPacket->serialize_value(var);
240 const std::string packetString = wddxPacket->packet_end();
241 return String(packetString);
244 //////////////////////////////////////////////////////////////////////////////
246 class wddxExtension : public Extension {
247 public:
248 wddxExtension() : Extension("wddx") {}
249 virtual void moduleInit() {
250 HHVM_FE(wddx_add_vars);
251 HHVM_FE(wddx_packet_end);
252 HHVM_FE(wddx_packet_start);
253 HHVM_FE(wddx_serialize_value);
254 HHVM_FE(wddx_serialize_vars);
255 loadSystemlib();
257 } s_wddx_extension;
259 // Uncomment for non-bundled module
260 //HHVM_GET_MODULE(wddx);
262 //////////////////////////////////////////////////////////////////////////////
263 } // namespace HPHP