Files
avmplus/core/PrintWriter.cpp
dmcallis 65a0592776 Initial source code drop
Source code drop for the Actionscript virtual machine in the Adobe
Flash Player for December 2013
2013-12-02 16:04:04 -08:00

401 lines
12 KiB
C++

/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "avmplus.h"
namespace avmplus
{
PrintWriter::StreamAdapter::StreamAdapter()
{
gcStream = NULL;
nongcStream = NULL;
}
void PrintWriter::StreamAdapter::set(GCOutputStream* s)
{
MMgc::GC* gc = MMgc::GC::GetGC(s);
if (gc->IsPointerToGCPage(this))
WB(gc, gc->FindBeginningFast(this), &gcStream, s);
else
gcStream=s;
nongcStream=NULL;
}
void PrintWriter::StreamAdapter::set(NonGCOutputStream* s)
{
gcStream=NULL;
nongcStream=s;
}
void PrintWriter::StreamAdapter::write(const char* utf8)
{
if (gcStream)
gcStream->write(utf8);
else if (nongcStream)
nongcStream->write(utf8);
}
void PrintWriter::StreamAdapter::writeN(const char* utf8, size_t charCount)
{
if (gcStream)
gcStream->writeN(utf8, charCount);
else if (nongcStream)
nongcStream->writeN(utf8, charCount);
}
// The 2 base methods below (write/writeN) forward the request to the underlying
// m_stream. For optimal performance you should check the m_stream methods and
// ensure that you're not performing unnecessary copies. For example, if you have
// a null terminated string and are using a ConsoleOutputStream its best to call
// write() as opposed to writeN(). The latter copies to a intermediate buffer,
// while the former does not.
// ------------------------------------------------------------
void PrintWriter::write(const char* utf8)
{
m_stream.write(utf8);
}
void PrintWriter::writeN(const char* utf8, size_t count)
{
m_stream.writeN(utf8, count);
}
// ------------------------------------------------------------
// only called from Date.print()
void PrintWriter::writeUTF16(const void* buffer, size_t count)
{
for (size_t i=0; i<count; i++)
{
*this << ((wchar*)buffer)[i];
}
}
PrintWriter& PrintWriter::operator<< (hexAddr value)
{
writeHexAddr(value.getValue());
return *this;
}
PrintWriter& PrintWriter::operator<< (asAtomHex a)
{
writeAtomHex(a._atom);
return *this;
}
PrintWriter& PrintWriter::operator<< (asAtom a)
{
writeAtom(a._atom);
return *this;
}
PrintWriter& PrintWriter::operator<< (asUTF16 a)
{
writeUTF16(a._buf, a._len);
return *this;
}
PrintWriter& PrintWriter::operator<< (const char *str)
{
write(str);
return *this;
}
PrintWriter& PrintWriter::operator<< (bool b)
{
*this << (b ? "true" : "false");
return *this;
}
PrintWriter& PrintWriter::operator<< (char value)
{
char buf[2] = { value, '\0' };
if (value) write(buf);
return *this;
}
PrintWriter& PrintWriter::operator<< (wchar value)
{
// Encode the character as UTF-8
if (value < 0x80) {
*this << (char)value;
} else {
uint8_t Octets[7];
size_t OctetsLen = UnicodeUtils::Ucs4ToUtf8((uint32_t)value, Octets);
Octets[OctetsLen] = '\0';
write((const char*)Octets);
}
return *this;
}
PrintWriter& PrintWriter::operator<< (int32_t value)
{
switch (value) {
case 0:
return *this << "0";
case 1:
return *this << "1";
default:
{
char buffer[MathUtils::kMinSizeForInt32_t_base10_toString];
int32_t len = sizeof(buffer);
char* p = MathUtils::convertIntegerToStringBuffer((intptr_t)value, buffer, len, 10, MathUtils::kTreatAsSigned);
return *this << p;
}
}
}
PrintWriter& PrintWriter::operator<< (uint64_t value)
{
switch (value) {
case 0:
return *this << "0";
case 1:
return *this << "1";
default:
{
char buffer[MathUtils::kMinSizeForInt64_t_toString];
int32_t len = sizeof(buffer);
char* p = MathUtils::convertIntegerToStringBuffer((intptr_t) value, buffer, len, 10, MathUtils::kTreatAsUnsigned);
return *this << p;
}
}
}
PrintWriter& PrintWriter::operator<< (int64_t value)
{
switch (value) {
case 0:
return *this << "0";
case 1:
return *this << "1";
default:
{
char buffer[MathUtils::kMinSizeForInt64_t_toString];
int32_t len = sizeof(buffer);
char* p = MathUtils::convertIntegerToStringBuffer((intptr_t) value, buffer, len, 10, MathUtils::kTreatAsSigned);
return *this << p;
}
}
}
#if defined AVMPLUS_MAC && defined AVMPLUS_64BIT
PrintWriter& PrintWriter::operator<< (ptrdiff_t value)
{
return *this << (int64_t)value;
}
#endif
PrintWriter& PrintWriter::operator<< (uint32_t value)
{
switch (value) {
case 0:
return *this << "0";
case 1:
return *this << "1";
default:
{
char buffer[MathUtils::kMinSizeForInt32_t_base10_toString];
int32_t len = sizeof(buffer);
intptr_t wideVal = (intptr_t) value;
#ifdef AVMPLUS_64BIT
wideVal = (intptr_t)(uint32_t)value;
#endif
char* p = MathUtils::convertIntegerToStringBuffer(wideVal, buffer, len, 10, MathUtils::kTreatAsUnsigned);
return *this << p;
}
}
}
/**
* format the value of an atom for debugging.
*/
void PrintWriter::writeAtom(Atom atom)
{
if (!AvmCore::isNull(atom))
{
switch (atomKind(atom))
{
case kNamespaceType:
*this << AvmCore::atomToNamespace(atom);
break;
case kObjectType:
#ifdef AVMPLUS_VERBOSE
*this << AvmCore::atomToScriptObject(atom);
#else
this->writeAtomHex(atom);
#endif
break;
case kStringType:
*this << "\"";
if (AvmCore::isString(atom)) *this << AvmCore::atomToString(atom);
*this << "\"";
break;
case kSpecialBibopType:
#ifdef VMCFG_FLOAT
if(atom == AtomConstants::undefinedAtom){
*this << "undefined";
break;
}
if (bibopKind(atom) == kBibopFloatType) {
*this << AvmCore::atomToFloat(atom);
break;
}
if (bibopKind(atom) == kBibopFloat4Type) {
float4_t v = * (float4_t*)atomPtr(atom);
*this << ((float)f4_x(v)) << "," << ((float)f4_y(v)) << "," << ((float)f4_z(v)) << "," << ((float)f4_w(v));
break;
}
AvmAssertMsg(false,"Unknown bibop type!!!");
#endif // VMCFG_FLOAT
*this << "undefined";
break;
case kBooleanType:
*this << (((atom & ~7) != 0) ? "true" : "false");
break;
case kIntptrType:
*this << (int64_t) atomGetIntptr(atom); // might be slow on 32b
break;
case kDoubleType:
AvmAssert(atom != kDoubleType); // this would be a null pointer to double
*this << AvmCore::atomToDouble(atom);
break;
default:
AvmAssertMsg(0, "Was ist das?");
}
}
else
{
*this << "null";
}
}
void PrintWriter::writeAtomHex(Atom atom)
{
char buffer[MathUtils::kMinSizeForInt64_t_toString];
int32_t len = sizeof(buffer);
char* p = MathUtils::convertIntegerToStringBuffer((intptr_t)atom, buffer, len, 16, MathUtils::kTreatAsUnsigned);
*this << p;
}
PrintWriter& PrintWriter::operator<< (double value)
{
// this could be an expensive call ... avoid it
return *this << MathUtils::convertDoubleToString(m_core, value);
}
#define PRINT_STAR_OPERATOR_SUPPORT(x,r) \
PrintWriter& PrintWriter::operator<< (const x* obj) \
{ \
if (!obj) { *this<<r; return *this; } \
return obj->print(*this); \
}
#define PRINT_AMP_OPERATOR_SUPPORT(x) \
PrintWriter& PrintWriter::operator<< (const x& obj) \
{ \
return obj.print(*this); \
}
#define PRINT_STAR_OPERATOR_SUPPORT_NULL(x) PRINT_STAR_OPERATOR_SUPPORT(x,"null")
#ifdef AVMPLUS_VERBOSE
PRINT_STAR_OPERATOR_SUPPORT(String,"(null)")
PRINT_STAR_OPERATOR_SUPPORT(Traits,"*")
PRINT_STAR_OPERATOR_SUPPORT_NULL(ScriptObject)
PRINT_STAR_OPERATOR_SUPPORT_NULL(MethodInfo)
PRINT_STAR_OPERATOR_SUPPORT_NULL(Namespace)
PRINT_STAR_OPERATOR_SUPPORT_NULL(NamespaceSet)
PRINT_STAR_OPERATOR_SUPPORT_NULL(ScopeTypeChain)
PRINT_STAR_OPERATOR_SUPPORT_NULL(ScopeChain)
PRINT_STAR_OPERATOR_SUPPORT_NULL(MethodRecognizer)
PRINT_AMP_OPERATOR_SUPPORT(Multiname)
#else
PRINT_STAR_OPERATOR_SUPPORT(String,"(null)")
PRINT_STAR_OPERATOR_SUPPORT(Traits,"*")
PRINT_STAR_OPERATOR_SUPPORT_NULL(MethodInfo)
PRINT_STAR_OPERATOR_SUPPORT_NULL(Namespace)
PRINT_STAR_OPERATOR_SUPPORT_NULL(ScopeTypeChain)
PRINT_AMP_OPERATOR_SUPPORT(Multiname)
#endif
#undef PRINT_STAR_OPERATOR_SUPPORT
#undef PRINT_STAR_OPERATOR_SUPPORT_NULL
#undef PRINT_AMP_OPERATOR_SUPPORT
void PrintWriter::writeHexNibble(uint8_t value)
{
if (value < 10) {
*this << (char)(value+'0');
} else {
*this << (char)(value+'A'-10);
}
}
void PrintWriter::writeHexByte(uint8_t value)
{
writeHexNibble(value>>4);
writeHexNibble(value&0x0f);
}
void PrintWriter::writeHexWord(uint16_t value)
{
writeHexByte((uint8_t)(value>>8));
writeHexByte((uint8_t)(value&0xff));
}
void PrintWriter::writeHexAddr(uintptr_t value)
{
#ifdef AVMPLUS_64BIT
writeHexByte(uint8_t((value>>56) & 0xff));
writeHexByte(uint8_t((value>>48) & 0xff));
writeHexByte(uint8_t((value>>40) & 0xff));
writeHexByte(uint8_t((value>>32) & 0xff));
#endif
writeHexByte(uint8_t((value>>24) & 0xff));
writeHexByte(uint8_t((value>>16) & 0xff));
writeHexByte(uint8_t(value>>8));
writeHexByte(uint8_t(value&0xff));
}
void PrintWriter::formatP(const char* format, Stringp arg1, Stringp arg2, Stringp arg3)
{
while (*format)
{
if (*format == '%')
{
switch (*++format)
{
case '1':
if (arg1) *this << arg1;
break;
case '2':
if (arg2) *this << arg2;
break;
case '3':
if (arg3) *this << arg3;
break;
default:
AvmAssertMsg(0, "Invalid specifier; should be between '1' and '3'");
break;
}
}
else
{
*this << *format;
}
format++;
}
}
}