39ba801ffc
And use them for VariableSerializer/VariableUnserializer
138 linhas
4.5 KiB
C++
138 linhas
4.5 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifndef __HPHP_VARIABLE_UNSERIALIZER_H__
|
|
#define __HPHP_VARIABLE_UNSERIALIZER_H__
|
|
|
|
#include <runtime/base/types.h>
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class VariableUnserializer {
|
|
public:
|
|
/**
|
|
* Supported formats.
|
|
*/
|
|
enum Type {
|
|
Serialize,
|
|
APCSerialize,
|
|
};
|
|
|
|
public:
|
|
VariableUnserializer(const char *str, size_t len, Type type,
|
|
bool allowUnknownSerializableClass = false)
|
|
: m_type(type), m_buf(str), m_end(str + len),
|
|
m_unknownSerializable(allowUnknownSerializableClass) {}
|
|
VariableUnserializer(const char *str, const char *end, Type type,
|
|
bool allowUnknownSerializableClass = false)
|
|
: m_type(type), m_buf(str), m_end(end),
|
|
m_unknownSerializable(allowUnknownSerializableClass) {}
|
|
|
|
Type getType() const { return m_type;}
|
|
bool allowUnknownSerializableClass() const { return m_unknownSerializable;}
|
|
|
|
Variant unserialize();
|
|
Variant unserializeKey();
|
|
void add(Variant* v, Uns::Mode mode) {
|
|
if (mode == Uns::ValueMode) {
|
|
m_refs.emplace_back(RefInfo(v));
|
|
} else if (mode == Uns::KeyMode) {
|
|
// do nothing
|
|
} else if (mode == Uns::ColValueMode) {
|
|
m_refs.emplace_back(RefInfo::makeNonRefable(v));
|
|
} else {
|
|
assert(mode == Uns::ColKeyMode);
|
|
// We don't currently support using the 'r' encoding to refer
|
|
// to collection keys, but eventually we'll need to make this
|
|
// work to allow objects as keys. For now we encode collections
|
|
// keys in m_refs using a null pointer.
|
|
m_refs.emplace_back(RefInfo(nullptr));
|
|
}
|
|
}
|
|
// getByVal() is used to resolve the 'r' encoding
|
|
Variant* getByVal(int id) {
|
|
if (id <= 0 || id > (int)m_refs.size()) return nullptr;
|
|
Variant* ret = m_refs[id-1].var();
|
|
if (!ret) {
|
|
throw Exception("Referring to collection keys using the 'r' encoding "
|
|
"is not supported");
|
|
}
|
|
return ret;
|
|
}
|
|
// getByVal() is used to resolve the 'R' encoding
|
|
Variant* getByRef(int id) {
|
|
if (id <= 0 || id > (int)m_refs.size()) return nullptr;
|
|
if (!m_refs[id-1].canBeReferenced()) {
|
|
// If the low bit is set, that means the value cannot
|
|
// be taken by reference
|
|
throw Exception("Collection values cannot be taken by reference", id);
|
|
}
|
|
Variant* ret = m_refs[id-1].var();
|
|
if (!ret) {
|
|
throw Exception("Collection keys cannot be taken by reference", id);
|
|
}
|
|
return ret;
|
|
}
|
|
int64_t readInt();
|
|
double readDouble();
|
|
char readChar() {
|
|
check();
|
|
return *(m_buf++);
|
|
}
|
|
void read(char *buf, uint n);
|
|
char peek() {
|
|
check();
|
|
return *m_buf;
|
|
}
|
|
const char *head() { return m_buf; }
|
|
Variant &addVar();
|
|
|
|
private:
|
|
struct RefInfo {
|
|
explicit RefInfo(Variant* v) : m_data(reinterpret_cast<uintptr_t>(v)) {}
|
|
static RefInfo makeNonRefable(Variant* v) {
|
|
RefInfo r(v);
|
|
r.m_data |= 1;
|
|
return r;
|
|
}
|
|
Variant* var() const {
|
|
return reinterpret_cast<Variant*>(m_data & ~1);
|
|
}
|
|
bool canBeReferenced() const { return !(m_data & 1); }
|
|
private:
|
|
uintptr_t m_data;
|
|
};
|
|
|
|
Type m_type;
|
|
const char *m_buf;
|
|
const char *m_end;
|
|
smart::vector<RefInfo> m_refs;
|
|
smart::list<Variant> m_vars;
|
|
bool m_unknownSerializable;
|
|
|
|
void check() {
|
|
if (m_buf >= m_end) {
|
|
throw Exception("Unexpected end of buffer during unserialization");
|
|
}
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|
|
|
|
#endif // __HPHP_VARIABLE_UNSERIALIZER_H__
|