Beispiel #1
0
Variant HHVM_FUNCTION(json_encode, const Variant& value,
                                   int64_t options /* = 0 */,
                                   int64_t depth /* = 512 */) {
  // Special case for resource since VariableSerializer does not take care of it
  if (value.isResource()) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_UNSUPPORTED_TYPE);

    if (options & k_JSON_PARTIAL_OUTPUT_ON_ERROR) {
      return "null";
    }

    return false;
  }

  json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  VariableSerializer vs(VariableSerializer::Type::JSON, options);
  vs.setDepthLimit(depth);

  String json = vs.serializeValue(value, !(options & k_JSON_FB_UNLIMITED));

  if ((json_get_last_error_code() != json_error_codes::JSON_ERROR_NONE) &&
      !(options & k_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
    return false;
  }

  return json;
}
Beispiel #2
0
Variant f_json_decode(const String& json, bool assoc /* = false */,
                      CVarRef options /* = 0 */) {

  json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);

  if (json.empty()) {
    return uninit_null();
  }

  int64_t json_options = options.toInt64();
  if (options.isBoolean() && options.toBooleanVal()) {
    json_options = k_JSON_FB_LOOSE;
  }

  const int64_t supported_options =
    k_JSON_FB_LOOSE | k_JSON_FB_COLLECTIONS | k_JSON_FB_STABLE_MAPS;
  Variant z;
  if (JSON_parser(z, json.data(), json.size(), assoc,
                  (json_options & supported_options))) {
    return z;
  }

  if (json.size() == 4) {
    if (!strcasecmp(json.data(), "null")) return uninit_null();
    if (!strcasecmp(json.data(), "true")) return true;
  } else if (json.size() == 5 && !strcasecmp(json.data(), "false")) {
    return false;
  }

  int64_t p;
  double d;
  DataType type = json->isNumericWithVal(p, d, 0);
  if (type == KindOfInt64) {
    return p;
  } else if (type == KindOfDouble) {
    return d;
  }

  char ch0 = json.charAt(0);
  if (json.size() > 1 && ch0 == '"' && json.charAt(json.size() - 1) == '"') {
    return json.substr(1, json.size() - 2);
  }

  if ((json_options & k_JSON_FB_LOOSE) && json.size() > 1 &&
      ch0 == '\'' && json.charAt(json.size() - 1) == '\'') {
    return json.substr(1, json.size() - 2);
  }

  if (ch0 == '{' || ch0 == '[') { /* invalid JSON string */
    json_set_last_error_code(json_error_codes::JSON_ERROR_SYNTAX);
  }

  assert(json_get_last_error_code() != json_error_codes::JSON_ERROR_NONE);
  return uninit_null();
}
Beispiel #3
0
bool JSON_parser(Variant &return_value, const char *data, int data_len,
                 bool assoc, int depth, int64_t options) {
    json_tokener *tok;
    json_object *new_obj;
    bool retval = false;

#if JSON_C_MINOR_VERSION >= 11
    tok = json_tokener_new_ex(depth);
#else
    tok = json_tokener_new();
#endif
    if (!tok) {
        return retval;
    }

    //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;

    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);
        json_object_put(new_obj);
        retval = true;
    } else {
        switch (json_tokener_get_error(tok)) {
        case json_tokener_success:
            retval = true;
            break;

        case json_tokener_error_depth:
            json_set_last_error_code(json_error_codes::JSON_ERROR_DEPTH);
            break;

        default:
            json_set_last_error_code(json_error_codes::JSON_ERROR_SYNTAX,
                                     json_tokener_get_error(tok));
        }
    }

    json_tokener_free(tok);
    return retval;
}
Beispiel #4
0
String f_json_encode(CVarRef value, CVarRef options /* = 0 */) {

  json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);

  int64_t json_options = options.toInt64();
  if (options.isBoolean() && options.toBooleanVal()) {
    json_options = k_JSON_FB_LOOSE;
  }

  VariableSerializer vs(VariableSerializer::Type::JSON, json_options);
  return vs.serializeValue(value, !(json_options & k_JSON_FB_UNLIMITED));
}
Beispiel #5
0
TypedValue HHVM_FUNCTION(json_encode, const Variant& value,
                         int64_t options, int64_t depth) {
  // Special case for resource since VariableSerializer does not take care of it
  if (value.isResource()) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_UNSUPPORTED_TYPE);
    return tvReturn(json_guard_error_result("null", options));
  }

  json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  VariableSerializer vs(VariableSerializer::Type::JSON, options);
  vs.setDepthLimit(depth);

  String json = vs.serializeValue(value, !(options & k_JSON_FB_UNLIMITED));
  assertx(json.get() != nullptr);
  if (UNLIKELY(StructuredLog::coinflip(RuntimeOption::EvalSerDesSampleRate))) {
    StructuredLog::logSerDes("json", "ser", json, value);
  }

  if (json_get_last_error_code() != json_error_codes::JSON_ERROR_NONE) {
    return tvReturn(json_guard_error_result(json, options));
  }

  return tvReturn(std::move(json));
}
Beispiel #6
0
Variant f_json_decode(const String& json, bool assoc /* = false */,
                      CVarRef options /* = 0 */) {

  json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);

  if (json.empty()) {
    return uninit_null();
  }

  int64_t json_options = options.toInt64();
  if (options.isBoolean() && options.toBooleanVal()) {
    json_options = k_JSON_FB_LOOSE;
  }

  const int64_t supported_options =
    k_JSON_FB_LOOSE | k_JSON_FB_COLLECTIONS | k_JSON_FB_STABLE_MAPS;
  int64_t parser_options = json_options & supported_options;
  Variant z;
  if (JSON_parser(z, json.data(), json.size(), assoc, parser_options)) {
    return z;
  }

  if (json.size() == 4) {
    if (!strcasecmp(json.data(), "null")) {
      json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
      return uninit_null();
    }
    if (!strcasecmp(json.data(), "true")) {
      json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
      return true;
    }
  } else if (json.size() == 5 && !strcasecmp(json.data(), "false")) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return false;
  }

  int64_t p;
  double d;
  DataType type = json->isNumericWithVal(p, d, 0);
  if (type == KindOfInt64) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return p;
  } else if (type == KindOfDouble) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return d;
  }

  char ch0 = json.charAt(0);
  if (json.size() > 1 && ch0 == '"' && json.charAt(json.size() - 1) == '"') {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);

    // Wrap the string in an array to allow the JSON_parser to handle
    // things like unicode escape sequences, then unwrap to get result
    String wrapped("[");
    wrapped += json + "]";
    // Stick to a normal hhvm array for the wrapper
    const int64_t mask = ~(k_JSON_FB_COLLECTIONS | k_JSON_FB_STABLE_MAPS);
    if (JSON_parser(z, wrapped.data(), wrapped.size(), false,
                    parser_options & mask) && z.isArray()) {
      Array arr = z.toArray();
      if ((arr.size() == 1) && arr.exists(0)) {
        return arr[0];
      }
      // The input string could be something like: "foo","bar"
      // Which will parse inside the [] wrapper, but be invalid
      json_set_last_error_code(json_error_codes::JSON_ERROR_SYNTAX);
    }
  }

  if ((json_options & k_JSON_FB_LOOSE) && json.size() > 1 &&
      ch0 == '\'' && json.charAt(json.size() - 1) == '\'') {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return json.substr(1, json.size() - 2);
  }

  if (ch0 == '{' || ch0 == '[') { /* invalid JSON string */
    json_set_last_error_code(json_error_codes::JSON_ERROR_SYNTAX);
  }

  assert(json_get_last_error_code() != json_error_codes::JSON_ERROR_NONE);
  return uninit_null();
}
Beispiel #7
0
TypedValue HHVM_FUNCTION(json_decode, const String& json,
                         bool assoc, int64_t depth, int64_t options) {
  json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);

  if (json.empty()) {
    return make_tv<KindOfNull>();
  }

  const int64_t supported_options =
    k_JSON_FB_LOOSE |
    k_JSON_FB_COLLECTIONS |
    k_JSON_FB_STABLE_MAPS |
    k_JSON_BIGINT_AS_STRING |
    k_JSON_FB_HACK_ARRAYS;
  int64_t parser_options = options & supported_options;
  Variant z;
  const auto ok =
    JSON_parser(z, json.data(), json.size(), assoc, depth, parser_options);
  if (UNLIKELY(StructuredLog::coinflip(RuntimeOption::EvalSerDesSampleRate))) {
    StructuredLog::logSerDes("json", "des", json, z);
  }
  if (ok) {
    return tvReturn(std::move(z));
  }

  String trimmed = HHVM_FN(trim)(json, "\t\n\r ");

  if (trimmed.size() == 4) {
    if (!strcasecmp(trimmed.data(), "null")) {
      json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
      return make_tv<KindOfNull>();
    }
    if (!strcasecmp(trimmed.data(), "true")) {
      json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
      return make_tv<KindOfBoolean>(true);
    }
  } else if (trimmed.size() == 5 && !strcasecmp(trimmed.data(), "false")) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return make_tv<KindOfBoolean>(false);
  }

  int64_t p;
  double d;
  DataType type = json.get()->isNumericWithVal(p, d, 0);
  if (type == KindOfInt64) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return make_tv<KindOfInt64>(p);
  } else if (type == KindOfDouble) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    if ((options & k_JSON_BIGINT_AS_STRING) &&
        (json.toInt64() == LLONG_MAX || json.toInt64() == LLONG_MIN)
        && errno == ERANGE) { // Overflow
      bool is_float = false;
      for (int i = (trimmed[0] == '-' ? 1 : 0); i < trimmed.size(); ++i) {
        if (trimmed[i] < '0' || trimmed[i] > '9') {
          is_float = true;
          break;
        }
      }
      if (!is_float) {
        return tvReturn(trimmed);
      }
    }
    return make_tv<KindOfDouble>(d);
  }

  char ch0 = json.charAt(0);
  if (json.size() > 1 && ch0 == '"' && json.charAt(json.size() - 1) == '"') {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);

    // Wrap the string in an array to allow the JSON_parser to handle
    // things like unicode escape sequences, then unwrap to get result
    String wrapped("[");
    wrapped += json + "]";
    // Stick to a normal hhvm array for the wrapper
    const int64_t mask = ~(k_JSON_FB_COLLECTIONS | k_JSON_FB_STABLE_MAPS);
    if (JSON_parser(z, wrapped.data(), wrapped.size(), false, depth,
                    parser_options & mask) && z.isArray()) {
      Array arr = z.toArray();
      if ((arr.size() == 1) && arr.exists(0)) {
        return tvReturn(arr[0]);
      }
      // The input string could be something like: "foo","bar"
      // Which will parse inside the [] wrapper, but be invalid
      json_set_last_error_code(json_error_codes::JSON_ERROR_SYNTAX);
    }
  }

  if ((options & k_JSON_FB_LOOSE) && json.size() > 1 &&
      ch0 == '\'' && json.charAt(json.size() - 1) == '\'') {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return tvReturn(json.substr(1, json.size() - 2));
  }

  assert(json_get_last_error_code() != json_error_codes::JSON_ERROR_NONE);
  return make_tv<KindOfNull>();
}
Beispiel #8
0
Variant HHVM_FUNCTION(json_decode, const String& json, bool assoc /* = false */,
                      int64_t depth /* = 512 */, int64_t options /* = 0 */) {

  json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);

  if (json.empty()) {
    return init_null();
  }

  const int64_t supported_options =
    k_JSON_FB_LOOSE |
    k_JSON_FB_COLLECTIONS |
    k_JSON_FB_STABLE_MAPS |
    k_JSON_BIGINT_AS_STRING;
  int64_t parser_options = options & supported_options;
  Variant z;
  if (JSON_parser(z, json.data(), json.size(), assoc, depth, parser_options)) {
    return z;
  }

  String trimmed = f_trim(json, "\t\n\r ");

  if (trimmed.size() == 4) {
    if (!strcasecmp(trimmed.data(), "null")) {
      json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
      return init_null();
    }
    if (!strcasecmp(trimmed.data(), "true")) {
      json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
      return true;
    }
  } else if (trimmed.size() == 5 && !strcasecmp(trimmed.data(), "false")) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return false;
  }

  int64_t p;
  double d;
  DataType type = json.get()->isNumericWithVal(p, d, 0);
  if (type == KindOfInt64) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return p;
  } else if (type == KindOfDouble) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    if ((options & k_JSON_BIGINT_AS_STRING) &&
        (json.toInt64() == LLONG_MAX || json.toInt64() == LLONG_MIN)
        && errno == ERANGE) { // Overflow
      bool is_float = false;
      for (int i = (trimmed[0] == '-' ? 1 : 0); i < trimmed.size(); ++i) {
        if (trimmed[i] < '0' || trimmed[i] > '9') {
          is_float = true;
          break;
        }
      }
      if (!is_float) {
        return trimmed;
      }
    }
    return d;
  }

  char ch0 = json.charAt(0);
  if (json.size() > 1 && ch0 == '"' && json.charAt(json.size() - 1) == '"') {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);

    // Wrap the string in an array to allow the JSON_parser to handle
    // things like unicode escape sequences, then unwrap to get result
    String wrapped("[");
    wrapped += json + "]";
    // Stick to a normal hhvm array for the wrapper
    const int64_t mask = ~(k_JSON_FB_COLLECTIONS | k_JSON_FB_STABLE_MAPS);
    if (JSON_parser(z, wrapped.data(), wrapped.size(), false, depth,
                    parser_options & mask) && z.isArray()) {
      Array arr = z.toArray();
      if ((arr.size() == 1) && arr.exists(0)) {
        return arr[0];
      }
      // The input string could be something like: "foo","bar"
      // Which will parse inside the [] wrapper, but be invalid
      json_set_last_error_code(json_error_codes::JSON_ERROR_SYNTAX);
    }
  }

  if ((options & k_JSON_FB_LOOSE) && json.size() > 1 &&
      ch0 == '\'' && json.charAt(json.size() - 1) == '\'') {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return json.substr(1, json.size() - 2);
  }

  assert(json_get_last_error_code() != json_error_codes::JSON_ERROR_NONE);
  return init_null();
}