TypedValue HHVM_FUNCTION(dummy_arraylike_builtin, const Variant& var) { if (var.isArray()) { auto const& arr = var.asCArrRef(); return tvReturn(arr); } return tvReturn(staticEmptyKeysetArray()); }
TypedValue HHVM_FUNCTION(dummy_varr_or_darr_builtin, const Variant& var) { if (var.isArray()) { auto const& arr = var.asCArrRef(); if (arr.isVecOrVArray() || arr.isDictOrDArray()) return tvReturn(arr); } return tvReturn(staticEmptyVArray()); }
TypedValue HHVM_FUNCTION(serialize_memoize_param, TypedValue param) { // Memoize throws in the emitter if any function parameters are references, so // we can just assert that the param is cell here assertx(param.m_type != KindOfRef); auto const type = param.m_type; if (isStringType(type)) { auto const str = param.m_data.pstr; if (str->empty()) { return make_tv<KindOfPersistentString>(s_emptyStrMemoKey.get()); } else if ((unsigned char)str->data()[0] < '~') { // fb_compact_serialize always returns a string with the high-bit set in // the first character. Furthermore, we use ~ to begin all our special // constants, so anything less than ~ can't collide. There's no worry // about int-like strings because we use dicts (which don't perform key // coercion) to store the memoized values. str->incRefCount(); return param; } } else if (isContainer(param) && getContainerSize(param) == 0) { return make_tv<KindOfPersistentString>(s_emptyArrMemoKey.get()); } else if (type == KindOfUninit || type == KindOfNull) { return make_tv<KindOfPersistentString>(s_nullMemoKey.get()); } else if (type == KindOfBoolean) { return make_tv<KindOfPersistentString>( param.m_data.num ? s_trueMemoKey.get() : s_falseMemoKey.get() ); } else if (type == KindOfInt64) { return param; } return tvReturn( fb_compact_serialize(tvAsCVarRef(¶m), FBCompactSerializeBehavior::MemoizeParam)); }
TypedValue HHVM_FUNCTION(preg_match, StringArg pattern, StringArg subject, OutputArg matches /* = null */, int flags /* = 0 */, int offset /* = 0 */) { return tvReturn(preg_match(StrNR(pattern.get()), StrNR(subject.get()), matches.get() ? matches->var() : nullptr, flags, offset)); }
TypedValue HHVM_FUNCTION(preg_match_all, const String& pattern, const String& subject, OutputArg matches /* = null */, int flags /* = 0 */, int offset /* = 0 */) { return tvReturn(preg_match_all(pattern, subject, matches.get() ? matches->var() : nullptr, flags, offset)); }
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)); }
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>(); }
TypedValue HHVM_FUNCTION(launder_value, const Variant& val) { return tvReturn(val); }