a8e3321fbd
We'd like to start using ##mixed## instead of ##var## for attribute types to be consistent with Hack. As a followup to this (once released), we would codemod all ##var## to ##mixed##.
151 linhas
5.1 KiB
C++
151 linhas
5.1 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
| Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt. |
|
|
| If you did not receive a copy of the Zend license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@zend.com so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifndef incl_HPHP_VARIABLE_UNSERIALIZER_H_
|
|
#define incl_HPHP_VARIABLE_UNSERIALIZER_H_
|
|
|
|
#include "hphp/runtime/base/types.h"
|
|
#include "hphp/runtime/base/smart_containers.h"
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class VariableUnserializer {
|
|
public:
|
|
/**
|
|
* Supported formats.
|
|
*/
|
|
enum class Type {
|
|
Serialize,
|
|
APCSerialize,
|
|
};
|
|
|
|
public:
|
|
/**
|
|
* Be aware that the default class_whitelist is null_array instead of
|
|
* empty_array here because we do not limit the unserialization of arbitrary
|
|
* class for hphp internal use
|
|
*/
|
|
VariableUnserializer(const char *str, size_t len, Type type,
|
|
bool allowUnknownSerializableClass = false,
|
|
CArrRef class_whitelist = null_array)
|
|
: m_type(type), m_buf(str), m_end(str + len),
|
|
m_unknownSerializable(allowUnknownSerializableClass),
|
|
m_classWhiteList(class_whitelist) {}
|
|
VariableUnserializer(const char *str, const char *end, Type type,
|
|
bool allowUnknownSerializableClass = false,
|
|
CArrRef class_whitelist = null_array)
|
|
: m_type(type), m_buf(str), m_end(end),
|
|
m_unknownSerializable(allowUnknownSerializableClass),
|
|
m_classWhiteList(class_whitelist) {}
|
|
|
|
Type getType() const { return m_type;}
|
|
bool allowUnknownSerializableClass() const { return m_unknownSerializable;}
|
|
bool isWhitelistedClass(CStrRef cls_name) const;
|
|
|
|
Variant unserialize();
|
|
Variant unserializeKey();
|
|
void add(Variant* v, Uns::Mode mode) {
|
|
if (mode == Uns::Mode::Value) {
|
|
m_refs.emplace_back(RefInfo(v));
|
|
} else if (mode == Uns::Mode::Key) {
|
|
// do nothing
|
|
} else if (mode == Uns::Mode::ColValue) {
|
|
m_refs.emplace_back(RefInfo::makeNonRefable(v));
|
|
} else {
|
|
assert(mode == Uns::Mode::ColKey);
|
|
// 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");
|
|
}
|
|
Variant* ret = m_refs[id-1].var();
|
|
if (!ret) {
|
|
throw Exception("Collection keys cannot be taken by reference");
|
|
}
|
|
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;
|
|
CArrRef m_classWhiteList; // classes allowed to be unserialized
|
|
|
|
void check() {
|
|
if (m_buf >= m_end) {
|
|
throw Exception("Unexpected end of buffer during unserialization");
|
|
}
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|
|
|
|
#endif // incl_HPHP_VARIABLE_UNSERIALIZER_H_
|