Arquivos
hhvm/hphp/runtime/base/util/thrift_buffer.cpp
T
Edwin Smith d15e609333 Revert "Do copying with the AttachLiteral constructors."
Revert "Explicit CopyString, remove (const char*) constructors."
2013-05-06 09:31:26 -07:00

271 linhas
6.8 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. |
+----------------------------------------------------------------------+
*/
#include <runtime/base/util/thrift_buffer.h>
#include <runtime/base/type_conversions.h>
#include <runtime/base/builtin_functions.h>
#include <runtime/base/variable_unserializer.h>
#include <util/logger.h>
#define INVALID_DATA 1
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
ThriftBuffer::ThriftBuffer(int size,
int sType /* = VariableSerializer::Serialize*/)
: m_size(size), m_safe(false), m_serializerType(sType) {
m_buf = (char *)malloc(m_size + 1);
if (!m_buf) throwOutOfMemory();
m_pEnd = m_buf + m_size;
m_pSafe = m_pEnd - sizeof(int64_t) - 1;
m_p = m_buf;
}
ThriftBuffer::~ThriftBuffer() {
free(m_buf);
}
void ThriftBuffer::reset(bool read) {
if (read) {
m_pEnd = m_buf;
m_safe = false;
} else {
m_pEnd = m_buf + m_size;
}
m_pSafe = m_pEnd - sizeof(int64_t) - 1;
m_p = m_buf;
}
///////////////////////////////////////////////////////////////////////////////
void ThriftBuffer::write(CStrRef data) {
int32_t len = data.size();
write(len);
if (m_p + len > m_pEnd) {
flush();
}
if (len > m_size) {
flushImpl(data);
} else {
memcpy(m_p, data.data(), len);
if ((m_p += len) > m_pSafe) flush();
}
}
void ThriftBuffer::flush() {
*m_p = '\0';
String data(m_buf, m_p - m_buf, AttachLiteral);
m_p = m_buf;
flushImpl(data);
}
///////////////////////////////////////////////////////////////////////////////
void ThriftBuffer::read(char *data, int len) {
int avail = m_pEnd - m_p;
// still enough
if (avail >= len) {
if (data) memcpy(data, m_p, len);
if ((m_p += len) > m_pSafe) m_safe = false;
return;
}
if (data) memcpy(data, m_p, avail);
len -= avail;
data += avail;
while (true) {
String ret = readImpl();
if (ret.empty()) {
throwError("unable to read enough bytes",INVALID_DATA);
}
const char *rdata = ret.data();
int rsize = ret.size();
if (rsize >= len) {
if (data) memcpy(data, rdata, len);
rsize -= len;
if (rsize) {
memcpy(m_buf, rdata + len, rsize);
m_pEnd = m_buf + rsize;
} else {
m_pEnd = m_buf;
}
m_pSafe = m_pEnd - sizeof(int64_t) - 1;
m_p = m_buf;
if (m_p > m_pSafe) m_safe = false;
return; // done
}
if (data) memcpy(data, rdata, rsize);
len -= rsize;
data += rsize;
}
}
void ThriftBuffer::skip(int8_t type) {
switch (type) {
case T_STOP:
case T_VOID:
return;
case T_STRUCT:
while (true) {
int8_t ttype; read(ttype); // get field type
if (ttype == T_STOP) break;
read(nullptr, 2); // skip field number, I16
skip(ttype); // skip field payload
}
return;
case T_BOOL:
case T_BYTE:
read(nullptr, 1);
return;
case T_I16:
read(nullptr, 2);
return;
case T_I32:
read(nullptr, 4);
return;
case T_U64:
case T_I64:
case T_DOUBLE:
read(nullptr, 8);
return;
//case T_UTF7: // aliases T_STRING
case T_UTF8:
case T_UTF16:
case T_STRING: {
int32_t len; read(len);
read(nullptr, len);
} return;
case T_MAP: {
int8_t keytype; read(keytype);
int8_t valtype; read(valtype);
int32_t size; read(size);
for (int32_t i = 0; i < size; ++i) {
skip(keytype);
skip(valtype);
}
} return;
case T_LIST:
case T_SET: {
int8_t valtype; read(valtype);
int32_t size; read(size);
for (int32_t i = 0; i < size; ++i) {
skip(valtype);
}
} return;
};
char errbuf[128];
sprintf(errbuf, "Unknown field type: %d", (int)type);
throwError(errbuf, INVALID_DATA);
}
void ThriftBuffer::throwOutOfMemory() {
throwError("out of memory", 0);
}
void ThriftBuffer::throwInvalidStringSize(int size) {
char errbuf[128];
sprintf(errbuf, "Negative string size: %d", (int)size);
throwError(errbuf, INVALID_DATA);
}
///////////////////////////////////////////////////////////////////////////////
static Variant unserialize_with_no_notice(CStrRef str) {
VariableUnserializer vu(str.data(), str.data() + str.size(),
VariableUnserializer::Serialize, true);
Variant v;
try {
v = vu.unserialize();
} catch (Exception &e) {
Logger::Error("unserialize(): %s", e.getMessage().c_str());
}
return v;
}
void ThriftBuffer::read(std::string &data) {
String sdata;
read(sdata);
data = std::string(sdata.data(), sdata.size());
}
void ThriftBuffer::write(const std::string &data) {
write(String(data.data(), data.size(), AttachLiteral));
}
void ThriftBuffer::read(std::vector<std::string> &data) {
int32_t size;
read(size);
data.resize(size);
for (int i = 0; i < size; i++) {
read(data[i]);
}
}
void ThriftBuffer::write(const std::vector<std::string> &data) {
int32_t size = data.size();
write(size);
for (int i = 0; i < size; i++) {
write(data[i]);
}
}
void ThriftBuffer::read(Array &data) {
String sdata;
read(sdata);
data = unserialize_with_no_notice(sdata).toArray();
}
void ThriftBuffer::write(CArrRef data) {
VariableSerializer vs((VariableSerializer::Type)m_serializerType);
String sdata = vs.serialize(VarNR(data), true);
write(sdata);
}
void ThriftBuffer::read(Object &data) {
String sdata;
read(sdata);
data = unserialize_with_no_notice(sdata).toObject();
}
void ThriftBuffer::write(CObjRef data) {
VariableSerializer vs((VariableSerializer::Type)m_serializerType);
String sdata = vs.serialize(VarNR(data), true);
write(sdata);
}
void ThriftBuffer::read(Variant &data) {
String sdata;
read(sdata);
data = unserialize_with_no_notice(sdata);
}
void ThriftBuffer::write(CVarRef data) {
VariableSerializer vs((VariableSerializer::Type)m_serializerType);
String sdata = vs.serialize(data, true);
write(sdata);
}
///////////////////////////////////////////////////////////////////////////////
}