blob: ab9a85b1dcad23c6110634c8b9b8574ad91c9a1b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(_MSC_VER)
#pragma warning ( disable: 4231 4251 4275 4786 )
#endif
#include <log4cxx/logstring.h>
#include <log4cxx/helpers/objectoutputstream.h>
#include <log4cxx/helpers/bytebuffer.h>
#include <log4cxx/helpers/outputstream.h>
#include <log4cxx/helpers/charsetencoder.h>
using namespace log4cxx;
using namespace log4cxx::helpers;
IMPLEMENT_LOG4CXX_OBJECT(ObjectOutputStream)
typedef std::map<std::string, unsigned int> ClassDescriptionMap;
struct ObjectOutputStream::ObjectOutputStreamPriv
{
OutputStreamPtr os;
log4cxx::helpers::CharsetEncoderPtr utf8Encoder;
const unsigned int objectHandleDefault;
unsigned int objectHandle;
ClassDescriptionMap classDescriptions;
ObjectOutputStreamPriv(OutputStreamPtr outputStream, Pool& p)
: os(outputStream)
, utf8Encoder(CharsetEncoder::getUTF8Encoder())
, objectHandleDefault(0x7E0000)
, objectHandle(objectHandleDefault)
{}
};
ObjectOutputStream::ObjectOutputStream(OutputStreamPtr outputStream, Pool& p)
: m_priv(std::make_unique<ObjectOutputStreamPriv>(outputStream, p))
{
unsigned char start[] = { 0xAC, 0xED, 0x00, 0x05 };
ByteBuffer buf((char*) start, sizeof(start));
m_priv->os->write(buf, p);
}
ObjectOutputStream::~ObjectOutputStream()
{
}
void ObjectOutputStream::close(Pool& p)
{
m_priv->os->close(p);
}
void ObjectOutputStream::flush(Pool& p)
{
m_priv->os->flush(p);
}
void ObjectOutputStream::reset(Pool& p)
{
m_priv->os->flush(p);
writeByte(TC_RESET, p);
m_priv->os->flush(p);
m_priv->objectHandle = m_priv->objectHandleDefault;
m_priv->classDescriptions.clear();
}
void ObjectOutputStream::writeObject(const LogString& val, Pool& p)
{
m_priv->objectHandle++;
writeByte(TC_STRING, p);
char bytes[2];
#if LOG4CXX_LOGCHAR_IS_UTF8
size_t len = val.size();
ByteBuffer dataBuf(const_cast<char*>(val.data()), val.size());
#else
size_t maxSize = 6 * val.size();
char* data = p.pstralloc(maxSize);
ByteBuffer dataBuf(data, maxSize);
LogString::const_iterator iter(val.begin());
m_priv->utf8Encoder->encode(val, iter, dataBuf);
dataBuf.flip();
size_t len = dataBuf.limit();
#endif
bytes[1] = (char) (len & 0xFF);
bytes[0] = (char) ((len >> 8) & 0xFF);
ByteBuffer lenBuf(bytes, sizeof(bytes));
m_priv->os->write(lenBuf, p);
m_priv->os->write(dataBuf, p);
}
void ObjectOutputStream::writeObject(const MDC::Map& val, Pool& p)
{
//
// TC_OBJECT and the classDesc for java.util.Hashtable
//
unsigned char prolog[] =
{
0x72, 0x00, 0x13, 0x6A, 0x61, 0x76, 0x61,
0x2E, 0x75, 0x74, 0x69, 0x6C, 0x2E, 0x48, 0x61,
0x73, 0x68, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x13,
0xBB, 0x0F, 0x25, 0x21, 0x4A, 0xE4, 0xB8, 0x03,
0x00, 0x02, 0x46, 0x00, 0x0A, 0x6C, 0x6F, 0x61,
0x64, 0x46, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x49,
0x00, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68,
0x6F, 0x6C, 0x64, 0x78, 0x70
};
writeProlog("java.util.Hashtable", 1, (char*) prolog, sizeof(prolog), p);
// loadFactor = 0.75, threshold = 5, blockdata start, buckets.size = 7
char data[] = { 0x3F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
TC_BLOCKDATA, 0x08, 0x00, 0x00, 0x00, 0x07
};
ByteBuffer dataBuf(data, sizeof(data));
m_priv->os->write(dataBuf, p);
char size[4];
size_t sz = val.size();
size[3] = (char) (sz & 0xFF);
size[2] = (char) ((sz >> 8) & 0xFF);
size[1] = (char) ((sz >> 16) & 0xFF);
size[0] = (char) ((sz >> 24) & 0xFF);
ByteBuffer sizeBuf(size, sizeof(size));
m_priv->os->write(sizeBuf, p);
for (MDC::Map::const_iterator iter = val.begin();
iter != val.end();
iter++)
{
writeObject(iter->first, p);
writeObject(iter->second, p);
}
writeByte(TC_ENDBLOCKDATA, p);
}
void ObjectOutputStream::writeUTFString(const std::string& val, Pool& p)
{
char bytes[3];
size_t len = val.size();
ByteBuffer dataBuf(const_cast<char*>(val.data()), val.size());
m_priv->objectHandle++;
bytes[0] = 0x74;
bytes[1] = (char) ((len >> 8) & 0xFF);
bytes[2] = (char) (len & 0xFF);
ByteBuffer lenBuf(bytes, sizeof(bytes));
m_priv->os->write(lenBuf, p);
m_priv->os->write(dataBuf, p);
}
void ObjectOutputStream::writeByte(char val, Pool& p)
{
ByteBuffer buf(&val, 1);
m_priv->os->write(buf, p);
}
void ObjectOutputStream::writeInt(int val, Pool& p)
{
char bytes[4];
bytes[3] = (char) (val & 0xFF);
bytes[2] = (char) ((val >> 8) & 0xFF);
bytes[1] = (char) ((val >> 16) & 0xFF);
bytes[0] = (char) ((val >> 24) & 0xFF);
ByteBuffer buf(bytes, sizeof(bytes));
m_priv->os->write(buf, p);
}
void ObjectOutputStream::writeLong(log4cxx_time_t val, Pool& p)
{
char bytes[8];
bytes[7] = (char) (val & 0xFF);
bytes[6] = (char) ((val >> 8) & 0xFF);
bytes[5] = (char) ((val >> 16) & 0xFF);
bytes[4] = (char) ((val >> 24) & 0xFF);
bytes[3] = (char) ((val >> 32) & 0xFF);
bytes[2] = (char) ((val >> 40) & 0xFF);
bytes[1] = (char) ((val >> 48) & 0xFF);
bytes[0] = (char) ((val >> 56) & 0xFF);
ByteBuffer buf(bytes, sizeof(bytes));
m_priv->os->write(buf, p);
}
void ObjectOutputStream::writeBytes(const char* bytes, size_t len, Pool& p)
{
ByteBuffer buf(const_cast<char*>(bytes), len);
m_priv->os->write(buf, p);
}
void ObjectOutputStream::writeNull(Pool& p)
{
writeByte(TC_NULL, p);
}
void ObjectOutputStream::writeProlog(const char* className,
int classDescIncrement,
char* classDesc,
size_t len,
Pool& p)
{
ClassDescriptionMap::const_iterator match = m_priv->classDescriptions.find(className);
if (match != m_priv->classDescriptions.end())
{
char bytes[6];
bytes[0] = TC_OBJECT;
bytes[1] = TC_REFERENCE;
bytes[2] = (char) ((match->second >> 24) & 0xFF);
bytes[3] = (char) ((match->second >> 16) & 0xFF);
bytes[4] = (char) ((match->second >> 8) & 0xFF);
bytes[5] = (char) (match->second & 0xFF);
ByteBuffer buf(bytes, sizeof(bytes));
m_priv->os->write(buf, p);
m_priv->objectHandle++;
}
else
{
m_priv->classDescriptions.insert(ClassDescriptionMap::value_type(className, m_priv->objectHandle));
writeByte(TC_OBJECT, p);
ByteBuffer buf(classDesc, len);
m_priv->os->write(buf, p);
m_priv->objectHandle += (classDescIncrement + 1);
}
}