Permalink
Browse files

Support JSON_FB_HACK_ARRAYS when using json-c

Summary:
fixes #8098

Also fix a bad use of FOLLY_FALLTHROUGH that makes clang sad.
Closes #8099

Reviewed By: mofarrell

Differential Revision: D6714628

Pulled By: fredemmott
  • Loading branch information...
fredemmott committed Jan 18, 2018
1 parent 0ba9b19 commit fb70e3599df2173c5d7791b44f6280983ac58853
Showing with 83 additions and 61 deletions.
  1. +17 −28 hphp/runtime/ext/json/JSON_parser.cpp
  2. +12 −0 hphp/runtime/ext/json/JSON_parser.h
  3. +54 −33 hphp/runtime/ext/json/jsonc_parser.cpp
@@ -299,18 +299,6 @@ enum class Mode {
ARRAY = 4
};
/**
* These are the types of containers that can be returned
* depending on the options used for json_decode.
*
* Objects are not included here.
*/
enum class ContainerType {
PHP_ARRAYS = 1,
COLLECTIONS = 2,
HACK_ARRAYS = 3,
};
namespace {
NEVER_INLINE
@@ -893,7 +881,7 @@ static void object_set(Variant &var,
const String& key,
const Variant& value,
int assoc,
ContainerType container_type) {
JSONContainerType container_type) {
if (!assoc) {
// We know it is stdClass, and everything is public (and dynamic).
if (key.empty()) {
@@ -902,10 +890,10 @@ static void object_set(Variant &var,
var.getObjectData()->o_set(key, value);
}
} else {
if (container_type == ContainerType::COLLECTIONS) {
if (container_type == JSONContainerType::COLLECTIONS) {
auto keyTV = make_tv<KindOfString>(key.get());
collections::set(var.getObjectData(), &keyTV, value.asCell());
} else if (container_type == ContainerType::HACK_ARRAYS) {
} else if (container_type == JSONContainerType::HACK_ARRAYS) {
forceToDict(var).set(key, value);
} else {
forceToArray(var).set(key, value);
@@ -916,7 +904,7 @@ static void object_set(Variant &var,
static void attach_zval(json_parser *json,
const String& key,
int assoc,
ContainerType container_type) {
JSONContainerType container_type) {
if (json->top < 1) {
return;
}
@@ -926,7 +914,7 @@ static void attach_zval(json_parser *json,
auto up_mode = json->stack[json->top - 1].mode;
if (up_mode == Mode::ARRAY) {
if (container_type == ContainerType::COLLECTIONS) {
if (container_type == JSONContainerType::COLLECTIONS) {
collections::append(root.getObjectData(), child.asCell());
} else {
root.toArrRef().append(child);
@@ -936,17 +924,17 @@ static void attach_zval(json_parser *json,
}
}
ContainerType get_container_type_from_options(int64_t options) {
JSONContainerType get_container_type_from_options(int64_t options) {
if ((options & k_JSON_FB_STABLE_MAPS) ||
(options & k_JSON_FB_COLLECTIONS)) {
return ContainerType::COLLECTIONS;
return JSONContainerType::COLLECTIONS;
}
if (options & k_JSON_FB_HACK_ARRAYS) {
return ContainerType::HACK_ARRAYS;
return JSONContainerType::HACK_ARRAYS;
}
return ContainerType::PHP_ARRAYS;
return JSONContainerType::PHP_ARRAYS;
}
/**
@@ -1003,7 +991,8 @@ bool JSON_parser(Variant &z, const char *p, int length, bool const assoc,
/*<fb>*/
bool const loose = options & k_JSON_FB_LOOSE;
ContainerType const container_type = get_container_type_from_options(options);
JSONContainerType const container_type =
get_container_type_from_options(options);
int qchr = 0;
int8_t const *byte_class;
int8_t const (*next_state_table)[32];
@@ -1122,15 +1111,15 @@ bool JSON_parser(Variant &z, const char *p, int length, bool const assoc,
top.unset();
}
/*<fb>*/
if (container_type == ContainerType::COLLECTIONS) {
if (container_type == JSONContainerType::COLLECTIONS) {
// stable_maps is meaningless
top = req::make<c_Map>();
} else {
/*</fb>*/
if (!assoc) {
top = SystemLib::AllocStdClassObject();
/* <fb> */
} else if (container_type == ContainerType::HACK_ARRAYS) {
} else if (container_type == JSONContainerType::HACK_ARRAYS) {
top = Array::CreateDict();
/* </fb> */
} else {
@@ -1198,9 +1187,9 @@ bool JSON_parser(Variant &z, const char *p, int length, bool const assoc,
top.unset();
}
/*<fb>*/
if (container_type == ContainerType::COLLECTIONS) {
if (container_type == JSONContainerType::COLLECTIONS) {
top = req::make<c_Vector>();
} else if (container_type == ContainerType::HACK_ARRAYS) {
} else if (container_type == JSONContainerType::HACK_ARRAYS) {
top = Array::CreateVec();
} else {
top = Array::Create();
@@ -1220,7 +1209,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool const assoc,
Variant mval;
json_create_zval(mval, *buf, type, options);
auto& top = json->stack[json->top].val;
if (container_type == ContainerType::COLLECTIONS) {
if (container_type == JSONContainerType::COLLECTIONS) {
collections::append(top.getObjectData(), mval.asCell());
} else {
top.toArrRef().append(mval);
@@ -1296,7 +1285,7 @@ bool JSON_parser(Variant &z, const char *p, int length, bool const assoc,
case Mode::ARRAY:
if (type != -1) {
auto& top = json->stack[json->top].val;
if (container_type == ContainerType::COLLECTIONS) {
if (container_type == JSONContainerType::COLLECTIONS) {
collections::append(top.getObjectData(), mval.asCell());
} else {
top.toArrRef().append(mval);
@@ -22,6 +22,18 @@
namespace HPHP {
/**
* These are the types of containers that can be returned
* depending on the options used for json_decode.
*
* Objects are not included here.
*/
enum class JSONContainerType {
PHP_ARRAYS = 1,
COLLECTIONS = 2,
HACK_ARRAYS = 3,
};
struct StringBuffer;
struct Variant;
@@ -94,23 +94,29 @@ const char *json_get_last_error_msg() {
///////////////////////////////////////////////////////////////////////////////
Variant json_object_to_variant(json_object *new_obj, const bool assoc,
const bool stable_maps, const bool collections);
const JSONContainerType container_type);
Variant json_type_array_to_variant(json_object *new_obj, const bool assoc,
const bool stable_maps,
const bool collections) {
const JSONContainerType container_type) {
int i, nb;
Variant var, tmpvar;
nb = json_object_array_length(new_obj);
if (collections) {
var = req::make<c_Vector>();
} else {
var = Array::Create();
switch (container_type) {
case JSONContainerType::COLLECTIONS:
var = req::make<c_Vector>();
break;
case JSONContainerType::HACK_ARRAYS:
var = Array::CreateVec();
break;
case JSONContainerType::PHP_ARRAYS:
var = Array::Create();
break;
}
for (i=0; i<nb; i++) {
tmpvar = json_object_to_variant(json_object_array_get_idx(new_obj, i),
assoc, stable_maps, collections);
if (collections) {
assoc, container_type);
if (container_type == JSONContainerType::COLLECTIONS) {
collections::append(var.getObjectData(), tmpvar.asCell());
} else {
var.asArrRef().append(tmpvar);
@@ -120,18 +126,25 @@ Variant json_type_array_to_variant(json_object *new_obj, const bool assoc,
}
Variant json_type_object_to_variant(json_object *new_obj, const bool assoc,
const bool stable_maps,
const bool collections) {
const JSONContainerType container_type) {
struct json_object_iterator it, itEnd;
json_object *jobj;
Variant var, tmpvar;
if (collections) {
var = req::make<c_Map>();
} else if (assoc) {
var = Array::Create();
} else {
if (!assoc) {
var = SystemLib::AllocStdClassObject();
} else {
switch (container_type) {
case JSONContainerType::COLLECTIONS:
var = req::make<c_Map>();
break;
case JSONContainerType::HACK_ARRAYS:
var = Array::CreateDict();
break;
case JSONContainerType::PHP_ARRAYS:
var = Array::Create();
break;
}
}
it = json_object_iter_begin(new_obj);
@@ -140,7 +153,7 @@ Variant json_type_object_to_variant(json_object *new_obj, const bool assoc,
while (!json_object_iter_equal(&it, &itEnd)) {
String key(json_object_iter_peek_name(&it), CopyString);
jobj = json_object_iter_peek_value(&it);
tmpvar = json_object_to_variant(jobj, assoc, stable_maps, collections);
tmpvar = json_object_to_variant(jobj, assoc, container_type);
if (!assoc) {
if (key.empty()) {
@@ -149,11 +162,18 @@ Variant json_type_object_to_variant(json_object *new_obj, const bool assoc,
var.getObjectData()->o_set(key, tmpvar);
}
} else {
if (collections) {
auto keyTV = make_tv<KindOfString>(key.get());
collections::set(var.getObjectData(), &keyTV, tmpvar.asCell());
} else {
forceToArray(var).set(key, tmpvar);
switch (container_type) {
case JSONContainerType::COLLECTIONS: {
auto keyTV = make_tv<KindOfString>(key.get());
collections::set(var.getObjectData(), &keyTV, tmpvar.asCell());
break;
}
case JSONContainerType::HACK_ARRAYS:
forceToDict(var).set(key, tmpvar);
break;
case JSONContainerType::PHP_ARRAYS:
forceToArray(var).set(key, tmpvar);
break;
}
}
json_object_iter_next(&it);
@@ -162,7 +182,7 @@ Variant json_type_object_to_variant(json_object *new_obj, const bool assoc,
}
Variant json_object_to_variant(json_object *new_obj, const bool assoc,
const bool stable_maps, const bool collections) {
const JSONContainerType container_type) {
json_type type;
int64_t i64;
@@ -177,7 +197,7 @@ Variant json_object_to_variant(json_object *new_obj, const bool assoc,
if (!(i64==INT64_MAX || i64==INT64_MIN)) {
return Variant(i64);
}
FOLLY_FALLTHROUGH
FOLLY_FALLTHROUGH;
case json_type_double:
return Variant(json_object_get_double(new_obj));
@@ -198,12 +218,10 @@ Variant json_object_to_variant(json_object *new_obj, const bool assoc,
return Variant(Variant::NullInit());
case json_type_array:
return json_type_array_to_variant(new_obj, assoc, stable_maps,
collections);
return json_type_array_to_variant(new_obj, assoc, container_type);
case json_type_object:
return json_type_object_to_variant(new_obj, assoc, stable_maps,
collections);
return json_type_object_to_variant(new_obj, assoc, container_type);
default:
// warning type <type> not yet implemented
@@ -229,18 +247,21 @@ bool JSON_parser(Variant &return_value, const char *data, int data_len,
//if (!(options & k_JSON_FB_LOOSE)) {
// json_tokener_set_flags(tok, JSON_TOKENER_STRICT);
//}
bool const stable_maps = options & k_JSON_FB_STABLE_MAPS;
bool const collections = stable_maps || options & k_JSON_FB_COLLECTIONS;
JSONContainerType container_type = JSONContainerType::PHP_ARRAYS;
if (options & (k_JSON_FB_STABLE_MAPS | k_JSON_FB_COLLECTIONS)) {
assoc = true;
container_type = JSONContainerType::COLLECTIONS;
} else if (options & k_JSON_FB_HACK_ARRAYS) {
container_type = JSONContainerType::HACK_ARRAYS;
}
new_obj = json_tokener_parse_ex(tok, data, data_len);
if (json_tokener_get_error(tok)==json_tokener_continue) {
new_obj = json_tokener_parse_ex(tok, "", -1);
}
if (new_obj) {
return_value = json_object_to_variant(new_obj, assoc, stable_maps,
collections);
return_value = json_object_to_variant(new_obj, assoc, container_type);
json_object_put(new_obj);
retval = true;
} else {

0 comments on commit fb70e35

Please sign in to comment.