bool TestExtVariable::test_unserialize() { { // this was crashing unserialize_from_string(StringUtil::HexDecode("53203a20224c612072756f74612067697261207065722074757474692220204d203a20227365636f6e646f206d6520736920c3a820696e6361737472617461206461207175616c6368652070617274652122")); } { Variant v = unserialize_from_string("O:8:\"stdClass\":1:{s:4:\"name\";s:5:\"value\";}"); VERIFY(v.is(KindOfObject)); Object obj = v.toObject(); VS(obj->o_getClassName(), "stdClass"); VS(obj.o_get("name"), "value"); } { Variant v = unserialize_from_string(String("O:8:\"stdClass\":1:{s:7:\"\0*\0name\";s:5:\"value\";}", 45, AttachLiteral)); VERIFY(v.is(KindOfObject)); Object obj = v.toObject(); VS(obj->o_getClassName(), "stdClass"); VS(obj.o_get("name"), uninit_null()); } { Variant v1 = CREATE_MAP3("a","apple","b",2,"c",CREATE_VECTOR3(1,"y",3)); Variant v2 = unserialize_from_string("a:3:{s:1:\"a\";s:5:\"apple\";s:1:\"b\";i:2;s:1:\"c\";a:3:{i:0;i:1;i:1;s:1:\"y\";i:2;i:3;}}"); VS(v1, v2); } return Count(true); }
Variant HHVM_FUNCTION(xbox_process_call_message, const String& msg) { Variant v = unserialize_from_string(msg); if (!v.isArray()) { raise_error("Error decoding xbox call message"); } Array arr = v.toArray(); if (arr.size() != 2 || !arr.exists(0) || !arr.exists(1)) { raise_error("Error decoding xbox call message"); } Variant fn = arr.rvalAt(0); if (fn.isArray()) { Array farr = fn.toArray(); if (!array_is_valid_callback(farr)) { raise_error("Error decoding xbox call message"); } } else if (!fn.isString()) { raise_error("Error decoding xbox call message"); } Variant args = arr.rvalAt(1); if (!args.isArray()) { raise_error("Error decoding xbox call message"); } return vm_call_user_func(fn, args.toArray()); }
bool TestCppBase::TestObject() { { String s = "O:1:\"B\":1:{s:3:\"obj\";O:1:\"A\":1:{s:1:\"a\";i:10;}}"; Variant v = unserialize_from_string(s); VERIFY(v.isObject()); auto o = v.toObject(); VS(o->o_getClassName().asString(), "__PHP_Incomplete_Class"); auto os = HHVM_FN(serialize)(o); VS(os, "O:1:\"B\":1:{s:3:\"obj\";O:1:\"A\":1:{s:1:\"a\";i:10;}}"); } return Count(true); }
bool TestExtFile::test_file_get_contents() { Variant f = f_fopen("test/test_ext_file.tmp", "w"); f_fputs(f, "testing file_get_contents"); f_fclose(f); VS(f_file_get_contents("test/test_ext_file.tmp"), "testing file_get_contents"); VS(unserialize_from_string(f_file_get_contents("compress.zlib://test/test_zlib_file")), CREATE_VECTOR1("rblock:216105")); return Count(true); }
bool TestCppBase::TestObject() { { String s = "O:1:\"B\":1:{s:3:\"obj\";O:1:\"A\":1:{s:1:\"a\";i:10;}}"; Variant v = unserialize_from_string(s); VERIFY(v.isObject()); auto o = v.toObject(); VS(o->o_getClassName(), "__PHP_Incomplete_Class"); auto os = f_serialize(o); VS(os, "O:1:\"B\":1:{s:3:\"obj\";O:1:\"A\":1:{s:1:\"a\";i:10;}}"); } VERIFY(!equal(Object(new TestResource()), Object(new TestResource()) )); return Count(true); }
TEST(Object, Serialization) { String s = "O:1:\"B\":1:{s:3:\"obj\";O:1:\"A\":1:{s:1:\"a\";i:10;}}"; Variant v = unserialize_from_string(s); EXPECT_TRUE(v.isObject()); auto o = v.toObject(); EXPECT_TRUE( !o->getClassName().asString().compare("__PHP_Incomplete_Class") ); auto os = HHVM_FN(serialize)(o); EXPECT_TRUE( !os.compare( "O:1:\"B\":1:{s:3:\"obj\";O:1:\"A\":1:{s:1:\"a\";i:10;}}") ); }
bool XboxServer::PostMessage(const String& message, const String& host /* = "localhost" */) { if (isLocalHost(host)) { Lock l(s_dispatchMutex); if (!s_dispatcher) { return false; } XboxTransport *job = new XboxTransport(message.toCppString()); job->incRefCount(); // paired with worker's decRefCount() assert(s_dispatcher); s_dispatcher->enqueue(job); return true; } else { // remote string url = "http://"; url += host.data(); url += "/xbox_post_message"; std::vector<std::string> headers; std::string hostStr(host.data()); LibEventHttpClientPtr http = LibEventHttpClient::Get(hostStr, RuntimeOption::XboxServerPort); if (http->send(url, headers, 0, false, message.data(), message.size())) { int code = http->getCode(); if (code > 0) { int len = 0; char *response = http->recv(len); String sresponse(response, len, AttachString); if (code == 200 && same( unserialize_from_string( sresponse, VariableUnserializer::Type::Internal ), true ) ) { return true; } } } } return false; }
void RepoQuery::getTypedValue(int iCol, TypedValue& tv) { const void* blob; size_t size; getBlob(iCol, blob, size); tvWriteUninit(&tv); if (size > 0) { String s = String((const char*)blob, size, CopyString); Variant v = unserialize_from_string(s); if (v.isString()) { v = String(StringData::GetStaticString(v.asCStrRef().get())); } else if (v.isArray()) { v = Array(ArrayData::GetScalarArray(v.asCArrRef().get())); } else { // Serialized variants and objects shouldn't ever make it into the repo. assert(!IS_REFCOUNTED_TYPE(v.getType())); } tvAsVariant(&tv) = v; } }
EXTERNALLY_VISIBLE void apc_load_impl(struct cache_info *info, const char **int_keys, long long *int_values, const char **char_keys, char *char_values, const char **strings, const char **objects, const char **thrifts, const char **others) { if (!apcExtension::ForceConstLoadToAPC) { if (apcExtension::EnableConstLoad && info && info->use_const) return; } auto& s = s_apc_store[0]; { int count = count_items(int_keys, 2); if (count) { vector<KeyValuePair> vars(count); const char **k = int_keys; long long*v = int_values; for (int i = 0; i < count; i++, k += 2) { auto& item = vars[i]; item.key = *k; item.len = (int)(int64_t)*(k+1); s.constructPrime(*v++, item); } s.prime(vars); } } { int count = count_items(char_keys, 2); if (count) { vector<KeyValuePair> vars(count); const char **k = char_keys; char *v = char_values; for (int i = 0; i < count; i++, k += 2) { auto& item = vars[i]; item.key = *k; item.len = (int)(int64_t)*(k+1); switch (*v++) { case 0: s.constructPrime(false, item); break; case 1: s.constructPrime(true , item); break; case 2: s.constructPrime(uninit_null() , item); break; default: throw Exception("bad apc archive, unknown char type"); } } s.prime(vars); } } { int count = count_items(strings, 4); if (count) { vector<KeyValuePair> vars(count); const char **p = strings; for (int i = 0; i < count; i++, p += 4) { auto& item = vars[i]; item.key = *p; item.len = (int)(int64_t)*(p+1); // Strings would be copied into APC anyway. String value(*(p+2), (int)(int64_t)*(p+3), CopyString); s.constructPrime(value, item, false); } s.prime(vars); } } { int count = count_items(objects, 4); if (count) { vector<KeyValuePair> vars(count); const char **p = objects; for (int i = 0; i < count; i++, p += 4) { auto& item = vars[i]; item.key = *p; item.len = (int)(int64_t)*(p+1); String value(*(p+2), (int)(int64_t)*(p+3), CopyString); s.constructPrime(value, item, true); } s.prime(vars); } } { int count = count_items(thrifts, 4); if (count) { vector<KeyValuePair> vars(count); const char **p = thrifts; for (int i = 0; i < count; i++, p += 4) { auto& item = vars[i]; item.key = *p; item.len = (int)(int64_t)*(p+1); String value(*(p+2), (int)(int64_t)*(p+3), CopyString); Variant success; Variant v = f_fb_unserialize(value, ref(success)); if (same(success, false)) { throw Exception("bad apc archive, f_fb_unserialize failed"); } s.constructPrime(v, item); } s.prime(vars); } } { int count = count_items(others, 4); if (count) { vector<KeyValuePair> vars(count); const char **p = others; for (int i = 0; i < count; i++, p += 4) { auto& item = vars[i]; item.key = *p; item.len = (int)(int64_t)*(p+1); String value(*(p+2), (int)(int64_t)*(p+3), CopyString); Variant v = unserialize_from_string(value); if (same(v, false)) { // we can't possibly get here if it was a boolean "false" that's // supposed to be serialized as a char throw Exception("bad apc archive, unserialize_from_string failed"); } s.constructPrime(v, item); } s.prime(vars); } } }
Variant HHVM_FUNCTION(unserialize, const String& str, const Array& class_whitelist /* =[] */) { return unserialize_from_string(str, class_whitelist); }
void SnapshotLoader::load(ConcurrentTableSharedStore& s) { // This could share code with apc_load_impl_compressed, but that function // should go away together with the shared object format. { std::vector<KeyValuePair> ints(read32()); for (auto& item : ints) { item.key = readString().begin(); s.constructPrime(read64(), item); } s.prime(ints); } { std::vector<KeyValuePair> chars(read32()); for (auto& item : chars) { item.key = readString().begin(); switch (static_cast<SnapshotBuilder::CharBasedType>(read<char>())) { case SnapshotBuilder::kSnapFalse: s.constructPrime(false, item); break; case SnapshotBuilder::kSnapTrue: s.constructPrime(true, item); break; case SnapshotBuilder::kSnapNull: s.constructPrime(uninit_null(), item); break; default: assert(false); break; } } s.prime(chars); } auto numStringBased = read32(); CHECK(numStringBased == SnapshotBuilder::kNumStringBased); for (int i = 0; i < numStringBased; ++i) { auto type = static_cast<SnapshotBuilder::StringBasedType>(i); std::vector<KeyValuePair> items(read32()); for (auto& item : items) { item.key = readString().begin(); auto data = readString(); String value(data.begin(), data.size(), CopyString); switch (type) { case SnapshotBuilder::kSnapString: s.constructPrime(value, item, false); break; case SnapshotBuilder::kSnapObject: s.constructPrime(value, item, true); break; case SnapshotBuilder::kSnapThrift: { Variant success; Variant v = HHVM_FN(fb_unserialize)(value, ref(success)); if (same(success, false)) { throw Exception("bad apc archive, fb_unserialize failed"); } s.constructPrime(v, item); break; } case SnapshotBuilder::kSnapOther: { Variant v = unserialize_from_string(value); if (same(v, false)) { throw Exception("bad apc archive, unserialize_from_string failed"); } s.constructPrime(v, item); break; } default: assert(false); break; } } s.prime(items); } { const char* disk = m_begin + header().diskOffset; std::vector<KeyValuePair> items(read32()); for (auto& item : items) { item.key = readString().begin(); item.sSize = read32(); item.sAddr = const_cast<char*>(disk); disk += abs(item.sSize) + 1; // \0 } assert(disk == m_begin + m_size); s.prime(items); } assert(m_cur == m_begin + header().diskOffset); // Keys have been copied, so don't need that part any more. madvise(const_cast<char*>(m_begin), header().diskOffset, MADV_DONTNEED); }
void PDOResource::persistentRestore() { auto const serialized = conn()->serialized_def_stmt_ctor_args; if (!serialized.empty()) { def_stmt_ctor_args = unserialize_from_string(serialized); } }
EXTERNALLY_VISIBLE void apc_load_impl_compressed (struct cache_info *info, int *int_lens, const char *int_keys, long long *int_values, int *char_lens, const char *char_keys, char *char_values, int *string_lens, const char *strings, int *object_lens, const char *objects, int *thrift_lens, const char *thrifts, int *other_lens, const char *others) { if (!apcExtension::ForceConstLoadToAPC) { if (apcExtension::EnableConstLoad && info && info->use_const) return; } auto& s = s_apc_store[0]; { int count = int_lens[0]; int len = int_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *keys = gzdecode(int_keys, len); if (keys == NULL) throw Exception("bad compressed apc archive."); ScopedMem holder(keys); const char *k = keys; long long* v = int_values; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = k; item.len = int_lens[i + 2]; s.constructPrime(*v++, item); k += int_lens[i + 2] + 1; // skip \0 } s.prime(vars); assert((k - keys) == len); } } { int count = char_lens[0]; int len = char_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *keys = gzdecode(char_keys, len); if (keys == NULL) throw Exception("bad compressed apc archive."); ScopedMem holder(keys); const char *k = keys; char *v = char_values; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = k; item.len = char_lens[i + 2]; switch (*v++) { case 0: s.constructPrime(false, item); break; case 1: s.constructPrime(true , item); break; case 2: s.constructPrime(uninit_null() , item); break; default: throw Exception("bad apc archive, unknown char type"); } k += char_lens[i + 2] + 1; // skip \0 } s.prime(vars); assert((k - keys) == len); } } { int count = string_lens[0] / 2; int len = string_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *decoded = gzdecode(strings, len); if (decoded == NULL) throw Exception("bad compressed apc archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = p; item.len = string_lens[i + i + 2]; p += string_lens[i + i + 2] + 1; // skip \0 // Strings would be copied into APC anyway. String value(p, string_lens[i + i + 3], CopyString); // todo: t2539893: check if value is already a static string s.constructPrime(value, item, false); p += string_lens[i + i + 3] + 1; // skip \0 } s.prime(vars); assert((p - decoded) == len); } } { int count = object_lens[0] / 2; int len = object_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *decoded = gzdecode(objects, len); if (decoded == NULL) throw Exception("bad compressed APC archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = p; item.len = object_lens[i + i + 2]; p += object_lens[i + i + 2] + 1; // skip \0 String value(p, object_lens[i + i + 3], CopyString); s.constructPrime(value, item, true); p += object_lens[i + i + 3] + 1; // skip \0 } s.prime(vars); assert((p - decoded) == len); } } { int count = thrift_lens[0] / 2; int len = thrift_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *decoded = gzdecode(thrifts, len); if (decoded == NULL) throw Exception("bad compressed apc archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = p; item.len = thrift_lens[i + i + 2]; p += thrift_lens[i + i + 2] + 1; // skip \0 String value(p, thrift_lens[i + i + 3], CopyString); Variant success; Variant v = f_fb_unserialize(value, ref(success)); if (same(success, false)) { throw Exception("bad apc archive, f_fb_unserialize failed"); } s.constructPrime(v, item); p += thrift_lens[i + i + 3] + 1; // skip \0 } s.prime(vars); assert((p - decoded) == len); } } { int count = other_lens[0] / 2; int len = other_lens[1]; if (count) { vector<KeyValuePair> vars(count); char *decoded = gzdecode(others, len); if (decoded == NULL) throw Exception("bad compressed apc archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { auto& item = vars[i]; item.key = p; item.len = other_lens[i + i + 2]; p += other_lens[i + i + 2] + 1; // skip \0 String value(p, other_lens[i + i + 3], CopyString); Variant v = unserialize_from_string(value); if (same(v, false)) { // we can't possibly get here if it was a boolean "false" that's // supposed to be serialized as a char throw Exception("bad apc archive, unserialize_from_string failed"); } s.constructPrime(v, item); p += other_lens[i + i + 3] + 1; // skip \0 } s.prime(vars); assert((p - decoded) == len); } } }
EXTERNALLY_VISIBLE void const_load_impl_compressed (struct cache_info *info, int *int_lens, const char *int_keys, long long *int_values, int *char_lens, const char *char_keys, char *char_values, int *string_lens, const char *strings, int *object_lens, const char *objects, int *thrift_lens, const char *thrifts, int *other_lens, const char *others) { if (!apcExtension::EnableConstLoad || !info || !info->use_const) return; { int count = int_lens[0]; int len = int_lens[1]; if (count) { char *keys = gzdecode(int_keys, len); if (keys == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(keys); const char *k = keys; long long* v = int_values; for (int i = 0; i < count; i++) { String key(k, int_lens[i + 2], CopyString); int64_t value = *v++; const_load_set(key, value); k += int_lens[i + 2] + 1; } assert((k - keys) == len); } } { int count = char_lens[0]; int len = char_lens[1]; if (count) { char *keys = gzdecode(char_keys, len); if (keys == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(keys); const char *k = keys; char *v = char_values; for (int i = 0; i < count; i++) { String key(k, char_lens[i + 2], CopyString); Variant value; switch (*v++) { case 0: value = false; break; case 1: value = true; break; case 2: value = uninit_null(); break; default: throw Exception("bad const archive, unknown char type"); } const_load_set(key, value); k += char_lens[i + 2] + 1; } assert((k - keys) == len); } } { int count = string_lens[0] / 2; int len = string_lens[1]; if (count) { char *decoded = gzdecode(strings, len); if (decoded == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { String key(p, string_lens[i + i + 2], CopyString); p += string_lens[i + i + 2] + 1; String value(p, string_lens[i + i + 3], CopyString); const_load_set(key, value); p += string_lens[i + i + 3] + 1; } assert((p - decoded) == len); } } // unserialize_from_string object is extremely slow here; // currently turned off: no objects in haste_maps. if (false) { int count = object_lens[0] / 2; int len = object_lens[1]; if (count) { char *decoded = gzdecode(objects, len); if (decoded == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { String key(p, object_lens[i + i + 2], CopyString); p += object_lens[i + i + 2] + 1; String value(p, object_lens[i + i + 3], CopyString); const_load_set(key, unserialize_from_string(value)); p += object_lens[i + i + 3] + 1; } assert((p - decoded) == len); } } { int count = thrift_lens[0] / 2; int len = thrift_lens[1]; if (count) { char *decoded = gzdecode(thrifts, len); if (decoded == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { String key(p, thrift_lens[i + i + 2], CopyString); p += thrift_lens[i + i + 2] + 1; String value(p, thrift_lens[i + i + 3], CopyString); Variant success; Variant v = f_fb_unserialize(value, ref(success)); if (same(success, false)) { throw Exception("bad apc archive, f_fb_unserialize failed"); } const_load_set(key, v); p += thrift_lens[i + i + 3] + 1; } assert((p - decoded) == len); } } {//Would we use others[]? int count = other_lens[0] / 2; int len = other_lens[1]; if (count) { char *decoded = gzdecode(others, len); if (decoded == NULL) throw Exception("bad compressed const archive."); ScopedMem holder(decoded); const char *p = decoded; for (int i = 0; i < count; i++) { String key(p, other_lens[i + i + 2], CopyString); p += other_lens[i + i + 2] + 1; String value(p, other_lens[i + i + 3], CopyString); Variant v = unserialize_from_string(value); if (same(v, false)) { throw Exception("bad apc archive, unserialize_from_string failed"); } const_load_set(key, v); p += other_lens[i + i + 3] + 1; } assert((p - decoded) == len); } } }
void PDOConnection::persistentRestore() { if (!serialized_def_stmt_ctor_args.empty()) { def_stmt_ctor_args = unserialize_from_string(serialized_def_stmt_ctor_args); } }
Variant f_unserialize(CStrRef str, CArrRef class_whitelist /* = empty_array */) { return unserialize_from_string(str, class_whitelist); }
Variant HHVM_FUNCTION(unserialize, const String& str, const Array& options /* =[] */) { return unserialize_from_string(str, options); }
bool XboxServer::SendMessage(const String& message, Array& ret, int timeout_ms, const String& host /* = "localhost" */) { if (isLocalHost(host)) { XboxTransport *job; { Lock l(s_dispatchMutex); if (!s_dispatcher) { return false; } job = new XboxTransport(message); job->incRefCount(); // paired with worker's decRefCount() job->incRefCount(); // paired with decRefCount() at below assert(s_dispatcher); s_dispatcher->enqueue(job); } if (timeout_ms <= 0) { timeout_ms = RuntimeOption::XboxDefaultLocalTimeoutMilliSeconds; } int code = 0; String response = job->getResults(code, timeout_ms); job->decRefCount(); // i'm done with this job if (code > 0) { ret.set(s_code, code); if (code == 200) { ret.set(s_response, unserialize_from_string(response)); } else { ret.set(s_error, response); } return true; } } else { // remote string url = "http://"; url += host.data(); url += '/'; url += RuntimeOption::XboxProcessMessageFunc; int timeoutSeconds = timeout_ms / 1000; if (timeoutSeconds <= 0) { timeoutSeconds = RuntimeOption::XboxDefaultRemoteTimeoutSeconds; } string hostStr(host.data()); std::vector<std::string> headers; LibEventHttpClientPtr http = LibEventHttpClient::Get(hostStr, RuntimeOption::XboxServerPort); if (http->send(url, headers, timeoutSeconds, false, message.data(), message.size())) { int code = http->getCode(); if (code > 0) { int len = 0; char *response = http->recv(len); String sresponse(response, len, AttachString); ret.set(s_code, code); if (code == 200) { ret.set(s_response, unserialize_from_string(sresponse)); } else { ret.set(s_error, sresponse); } return true; } // code wasn't correctly set by http client, treat it as not found ret.set(s_code, 404); ret.set(s_error, "http client failed"); } } return false; }
EXTERNALLY_VISIBLE void const_load_impl(struct cache_info *info, const char **int_keys, long long *int_values, const char **char_keys, char *char_values, const char **strings, const char **objects, const char **thrifts, const char **others) { if (!apcExtension::EnableConstLoad || !info || !info->use_const) return; { int count = count_items(int_keys, 2); if (count) { const char **k = int_keys; long long* v = int_values; for (int i = 0; i < count; i++, k += 2) { String key(*k, (int)(int64_t)*(k+1), CopyString); int64_t value = *v++; const_load_set(key, value); } } } { int count = count_items(char_keys, 2); if (count) { const char **k = char_keys; char *v = char_values; for (int i = 0; i < count; i++, k += 2) { String key(*k, (int)(int64_t)*(k+1), CopyString); Variant value; switch (*v++) { case 0: value = false; break; case 1: value = true; break; case 2: value = uninit_null(); break; default: throw Exception("bad apc archive, unknown char type"); } const_load_set(key, value); } } } { int count = count_items(strings, 4); if (count) { const char **p = strings; for (int i = 0; i < count; i++, p += 4) { String key(*p, (int)(int64_t)*(p+1), CopyString); String value(*(p+2), (int)(int64_t)*(p+3), CopyString); const_load_set(key, value); } } } // unserialize_from_string object is extremely slow here; // currently turned off: no objects in haste_maps. if (false) { int count = count_items(objects, 4); if (count) { const char **p = objects; for (int i = 0; i < count; i++, p += 4) { String key(*p, (int)(int64_t)*(p+1), CopyString); String value(*(p+2), (int)(int64_t)*(p+3), CopyString); const_load_set(key, unserialize_from_string(value)); } } } { int count = count_items(thrifts, 4); if (count) { vector<KeyValuePair> vars(count); const char **p = thrifts; for (int i = 0; i < count; i++, p += 4) { String key(*p, (int)(int64_t)*(p+1), CopyString); String value(*(p+2), (int)(int64_t)*(p+3), CopyString); Variant success; Variant v = f_fb_unserialize(value, ref(success)); if (same(success, false)) { throw Exception("bad apc archive, f_fb_unserialize failed"); } const_load_set(key, v); } } } {//Would we use others[]? int count = count_items(others, 4); if (count) { const char **p = others; for (int i = 0; i < count; i++, p += 4) { String key(*p, (int)(int64_t)*(p+1), CopyString); String value(*(p+2), (int)(int64_t)*(p+3), CopyString); Variant v = unserialize_from_string(value); if (same(v, false)) { throw Exception("bad apc archive, unserialize_from_string failed"); } const_load_set(key, v); } } } }