blob: 3c53ea2ceb934c553bad1ed7e12ce2203bb464f0 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeDebugPch.h"
#if ENABLE_TTD
namespace TTD
{
namespace NSTokens
{
void InitKeyNamesArray(const char16*** names, size_t** lengths)
{
const char16** nameArray = TT_HEAP_ALLOC_ARRAY(const char16*, (uint32)Key::Count);
size_t* lengthArray = TT_HEAP_ALLOC_ARRAY(size_t, (uint32)Key::Count);
#define ENTRY_SERIALIZE_ENUM(K) { nameArray[(uint32)Key::##K] = _u(#K); lengthArray[(uint32)Key::##K] = wcslen(_u(#K)); }
#include "TTSerializeEnum.h"
*names = nameArray;
*lengths = lengthArray;
}
void CleanupKeyNamesArray(const char16*** names, size_t** lengths)
{
if(*names != nullptr)
{
TT_HEAP_FREE_ARRAY(char16*, *names, (uint32)NSTokens::Key::Count);
*names = nullptr;
}
if(*lengths != nullptr)
{
TT_HEAP_FREE_ARRAY(size_t, *lengths, (uint32)NSTokens::Key::Count);
*lengths = nullptr;
}
}
}
//////////////////
void FileWriter::WriteBlock(const byte* buff, size_t bufflen)
{
TTDAssert(bufflen != 0, "Shouldn't be writing empty blocks");
TTDAssert(this->m_hfile != nullptr, "Trying to write to closed file.");
size_t bwp = 0;
this->m_pfWrite(this->m_hfile, buff, bufflen, &bwp);
}
FileWriter::FileWriter(JsTTDStreamHandle handle, TTDWriteBytesToStreamCallback pfWrite, TTDFlushAndCloseStreamCallback pfClose)
: m_hfile(handle), m_pfWrite(pfWrite), m_pfClose(pfClose), m_cursor(0), m_buffer(nullptr)
{
this->m_buffer = TT_HEAP_ALLOC_ARRAY(byte, TTD_SERIALIZATION_BUFFER_SIZE);
}
FileWriter::~FileWriter()
{
this->FlushAndClose();
}
void FileWriter::FlushAndClose()
{
if(this->m_hfile != nullptr)
{
if(this->m_cursor != 0)
{
this->WriteBlock(this->m_buffer, this->m_cursor);
this->m_cursor = 0;
}
this->m_pfClose(this->m_hfile, false, true);
this->m_hfile = nullptr;
}
if(this->m_buffer != nullptr)
{
TT_HEAP_FREE_ARRAY(byte, this->m_buffer, TTD_SERIALIZATION_BUFFER_SIZE);
this->m_buffer = nullptr;
}
}
void FileWriter::WriteLengthValue(uint32 length, NSTokens::Separator separator)
{
this->WriteKey(NSTokens::Key::count, separator);
this->WriteNakedUInt32(length);
}
void FileWriter::WriteSequenceStart_DefaultKey(NSTokens::Separator separator)
{
this->WriteKey(NSTokens::Key::values, separator);
this->WriteSequenceStart();
}
void FileWriter::WriteRecordStart_DefaultKey(NSTokens::Separator separator)
{
this->WriteKey(NSTokens::Key::entry, separator);
this->WriteRecordStart();
}
void FileWriter::WriteNull(NSTokens::Key key, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteNakedNull();
}
void FileWriter::WriteInt32(NSTokens::Key key, int32 val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteNakedInt32(val);
}
void FileWriter::WriteUInt32(NSTokens::Key key, uint32 val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteNakedUInt32(val);
}
void FileWriter::WriteInt64(NSTokens::Key key, int64 val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteNakedInt64(val);
}
void FileWriter::WriteUInt64(NSTokens::Key key, uint64 val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteNakedUInt64(val);
}
void FileWriter::WriteDouble(NSTokens::Key key, double val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteNakedDouble(val);
}
void FileWriter::WriteAddr(NSTokens::Key key, TTD_PTR_ID val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteNakedAddr(val);
}
void FileWriter::WriteLogTag(NSTokens::Key key, TTD_LOG_PTR_ID val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteNakedLogTag(val);
}
////
void FileWriter::WriteString(NSTokens::Key key, const TTString& val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteNakedString(val);
}
void FileWriter::WriteWellKnownToken(NSTokens::Key key, TTD_WELLKNOWN_TOKEN val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteNakedWellKnownToken(val);
}
//////////////////
TextFormatWriter::TextFormatWriter(JsTTDStreamHandle handle, TTDWriteBytesToStreamCallback pfWrite, TTDFlushAndCloseStreamCallback pfClose)
: FileWriter(handle, pfWrite, pfClose), m_keyNameArray(nullptr), m_keyNameLengthArray(nullptr), m_indentSize(0)
{
byte byteOrderMarker[2] = { 0xFF, 0xFE };
this->WriteRawByteBuff(byteOrderMarker, 2);
NSTokens::InitKeyNamesArray(&(this->m_keyNameArray), &(this->m_keyNameLengthArray));
}
TextFormatWriter::~TextFormatWriter()
{
NSTokens::CleanupKeyNamesArray(&(this->m_keyNameArray), &(this->m_keyNameLengthArray));
}
void TextFormatWriter::WriteSeperator(NSTokens::Separator separator)
{
if((separator & NSTokens::Separator::CommaSeparator) == NSTokens::Separator::CommaSeparator)
{
this->WriteRawChar(_u(','));
if((separator & NSTokens::Separator::BigSpaceSeparator) == NSTokens::Separator::BigSpaceSeparator)
{
this->WriteRawChar(_u('\n'));
for(uint32 i = 0; i < this->m_indentSize; ++i)
{
this->WriteRawChar(_u(' '));
this->WriteRawChar(_u(' '));
}
}
else
{
this->WriteRawChar(_u(' '));
}
}
if(separator == NSTokens::Separator::BigSpaceSeparator)
{
this->WriteRawChar(_u('\n'));
for(uint32 i = 0; i < this->m_indentSize; ++i)
{
this->WriteRawChar(_u(' '));
this->WriteRawChar(_u(' '));
}
}
}
void TextFormatWriter::WriteKey(NSTokens::Key key, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
TTDAssert(1 <= (uint32)key && (uint32)key < (uint32)NSTokens::Key::Count, "Key not in valid range!");
const char16* kname = this->m_keyNameArray[(uint32)key];
size_t ksize = this->m_keyNameLengthArray[(uint32)key];
this->WriteRawCharBuff(kname, ksize);
this->WriteRawChar(_u(':'));
}
void TextFormatWriter::WriteSequenceStart(NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawChar(_u('['));
}
void TextFormatWriter::WriteSequenceEnd(NSTokens::Separator separator)
{
TTDAssert(separator == NSTokens::Separator::NoSeparator || separator == NSTokens::Separator::BigSpaceSeparator, "Shouldn't be anything else!!!");
this->WriteSeperator(separator);
this->WriteRawChar(_u(']'));
}
void TextFormatWriter::WriteRecordStart(NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawChar(_u('{'));
}
void TextFormatWriter::WriteRecordEnd(NSTokens::Separator separator)
{
TTDAssert(separator == NSTokens::Separator::NoSeparator || separator == NSTokens::Separator::BigSpaceSeparator, "Shouldn't be anything else!!!");
this->WriteSeperator(separator);
this->WriteRawChar(_u('}'));
}
void TextFormatWriter::AdjustIndent(int32 delta)
{
this->m_indentSize += delta;
}
void TextFormatWriter::SetIndent(uint32 depth)
{
this->m_indentSize = depth;
}
void TextFormatWriter::WriteNakedNull(NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawCharBuff(_u("null"), 4);
}
void TextFormatWriter::WriteNakedByte(byte val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteFormattedCharData(_u("%I32u"), (uint32)val);
}
void TextFormatWriter::WriteBool(NSTokens::Key key, bool val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
if(val)
{
this->WriteRawCharBuff(_u("true"), 4);
}
else
{
this->WriteRawCharBuff(_u("false"), 5);
}
}
void TextFormatWriter::WriteNakedInt32(int32 val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteFormattedCharData(_u("%I32i"), val);
}
void TextFormatWriter::WriteNakedUInt32(uint32 val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteFormattedCharData(_u("%I32u"), val);
}
void TextFormatWriter::WriteNakedInt64(int64 val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteFormattedCharData(_u("%I64i"), val);
}
void TextFormatWriter::WriteNakedUInt64(uint64 val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteFormattedCharData(_u("%I64u"), val);
}
void TextFormatWriter::WriteNakedDouble(double val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
if(Js::JavascriptNumber::IsNan(val))
{
this->WriteRawCharBuff(_u("#nan"), 4);
}
else if(Js::JavascriptNumber::IsPosInf(val))
{
this->WriteRawCharBuff(_u("#+inf"), 5);
}
else if(Js::JavascriptNumber::IsNegInf(val))
{
this->WriteRawCharBuff(_u("#-inf"), 5);
}
else if(Js::JavascriptNumber::MAX_VALUE == val)
{
this->WriteRawCharBuff(_u("#ub"), 3);
}
else if(Js::JavascriptNumber::MIN_VALUE == val)
{
this->WriteRawCharBuff(_u("#lb"), 3);
}
else if(Js::Math::EPSILON == val)
{
this->WriteRawCharBuff(_u("#ep"), 3);
}
else
{
if(INT32_MAX <= val && val <= INT32_MAX && floor(val) == val)
{
this->WriteFormattedCharData(_u("%I64i"), (int64)val);
}
else
{
//
//TODO: this is nice for visual debugging but we inherently lose precision
// will want to change this to a dump of the bit representation of the number
//
this->WriteFormattedCharData(_u("%.32f"), val);
}
}
}
void TextFormatWriter::WriteNakedAddr(TTD_PTR_ID val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteFormattedCharData(_u("*%I64u"), val);
}
void TextFormatWriter::WriteNakedLogTag(TTD_LOG_PTR_ID val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteFormattedCharData(_u("!%I64i"), val);
}
void TextFormatWriter::WriteNakedTag(uint32 tagvalue, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteFormattedCharData(_u("$%I32i"), tagvalue);
}
////
void TextFormatWriter::WriteNakedString(const TTString& val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
if(IsNullPtrTTString(val))
{
this->WriteNakedNull();
}
else
{
this->WriteFormattedCharData(_u("@%I32u"), val.Length);
this->WriteRawChar(_u('\"'));
this->WriteRawCharBuff(val.Contents, val.Length);
this->WriteRawChar(_u('\"'));
}
}
void TextFormatWriter::WriteNakedWellKnownToken(TTD_WELLKNOWN_TOKEN val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawChar(_u('~'));
this->WriteRawCharBuff(val, wcslen(val));
this->WriteRawChar(_u('~'));
}
void TextFormatWriter::WriteInlineCode(_In_reads_(length) const char16* code, uint32 length, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteFormattedCharData(_u("@%I32u"), length);
this->WriteRawChar(_u('\"'));
this->WriteRawCharBuff(code, length);
this->WriteRawChar(_u('\"'));
}
void TextFormatWriter::WriteInlinePropertyRecordName(_In_reads_(length) const char16* pname, uint32 length, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteFormattedCharData(_u("@%I32u"), length);
this->WriteRawChar(_u('\"'));
this->WriteRawCharBuff(pname, length);
this->WriteRawChar(_u('\"'));
}
BinaryFormatWriter::BinaryFormatWriter(JsTTDStreamHandle handle, TTDWriteBytesToStreamCallback pfWrite, TTDFlushAndCloseStreamCallback pfClose)
: FileWriter(handle, pfWrite, pfClose)
{
;
}
BinaryFormatWriter::~BinaryFormatWriter()
{
;
}
void BinaryFormatWriter::WriteSeperator(NSTokens::Separator separator)
{
if((separator & NSTokens::Separator::CommaSeparator) == NSTokens::Separator::CommaSeparator)
{
this->WriteRawByteBuff_Fixed<byte>((byte)NSTokens::Separator::CommaSeparator);
}
}
void BinaryFormatWriter::WriteKey(NSTokens::Key key, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<byte>((byte)key);
}
void BinaryFormatWriter::WriteSequenceStart(NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<byte>('[');
}
void BinaryFormatWriter::WriteSequenceEnd(NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<byte>(']');
}
void BinaryFormatWriter::WriteRecordStart(NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<byte>('{');
}
void BinaryFormatWriter::WriteRecordEnd(NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<byte>('}');
}
void BinaryFormatWriter::AdjustIndent(int32 delta)
{
;
}
void BinaryFormatWriter::SetIndent(uint32 depth)
{
;
}
void BinaryFormatWriter::WriteNakedNull(NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<byte>((byte)0);
}
void BinaryFormatWriter::WriteNakedByte(byte val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<byte>(val);
}
void BinaryFormatWriter::WriteBool(NSTokens::Key key, bool val, NSTokens::Separator separator)
{
this->WriteKey(key, separator);
this->WriteRawByteBuff_Fixed<byte>(val ? (byte)1 : (byte)0);
}
void BinaryFormatWriter::WriteNakedInt32(int32 val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<int32>(val);
}
void BinaryFormatWriter::WriteNakedUInt32(uint32 val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<uint32>(val);
}
void BinaryFormatWriter::WriteNakedInt64(int64 val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<int64>(val);
}
void BinaryFormatWriter::WriteNakedUInt64(uint64 val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<uint64>(val);
}
void BinaryFormatWriter::WriteNakedDouble(double val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<double>(val);
}
void BinaryFormatWriter::WriteNakedAddr(TTD_PTR_ID val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<TTD_PTR_ID>(val);
}
void BinaryFormatWriter::WriteNakedLogTag(TTD_LOG_PTR_ID val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<TTD_LOG_PTR_ID>(val);
}
void BinaryFormatWriter::WriteNakedTag(uint32 tagvalue, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<uint32>(tagvalue);
}
void BinaryFormatWriter::WriteNakedString(const TTString& val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
if(IsNullPtrTTString(val))
{
this->WriteRawByteBuff_Fixed<uint32>(UINT32_MAX);
}
else
{
this->WriteRawByteBuff_Fixed<uint32>(val.Length);
this->WriteRawByteBuff((const byte*)val.Contents, val.Length * sizeof(char16));
}
}
void BinaryFormatWriter::WriteNakedWellKnownToken(TTD_WELLKNOWN_TOKEN val, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
uint32 charLen = (uint32)wcslen(val);
this->WriteRawByteBuff_Fixed<uint32>(charLen);
this->WriteRawByteBuff((const byte*)val, charLen * sizeof(char16));
}
void BinaryFormatWriter::WriteInlineCode(_In_reads_(length) const char16* code, uint32 length, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<uint32>(length);
this->WriteRawByteBuff((const byte*)code, length * sizeof(char16));
}
void BinaryFormatWriter::WriteInlinePropertyRecordName(_In_reads_(length) const char16* pname, uint32 length, NSTokens::Separator separator)
{
this->WriteSeperator(separator);
this->WriteRawByteBuff_Fixed<uint32>(length);
this->WriteRawByteBuff((const byte*)pname, length * sizeof(char16));
}
//////////////////
void FileReader::ReadBlock(byte* buff, size_t* readSize)
{
TTDAssert(this->m_hfile != nullptr, "Trying to read a invalid file.");
size_t bwp = 0;
this->m_pfRead(this->m_hfile, buff, TTD_SERIALIZATION_BUFFER_SIZE, &bwp);
*readSize = (size_t)bwp;
}
FileReader::FileReader(JsTTDStreamHandle handle, TTDReadBytesFromStreamCallback pfRead, TTDFlushAndCloseStreamCallback pfClose)
: m_hfile(handle), m_pfRead(pfRead), m_pfClose(pfClose), m_peekChar(-1), m_cursor(0), m_buffCount(0), m_buffer(nullptr)
{
this->m_buffer = TT_HEAP_ALLOC_ARRAY(byte, TTD_SERIALIZATION_BUFFER_SIZE);
}
FileReader::~FileReader()
{
if(this->m_hfile != nullptr)
{
this->m_pfClose(this->m_hfile, true, false);
this->m_hfile = nullptr;
}
if(this->m_buffer != nullptr)
{
TT_HEAP_FREE_ARRAY(byte, this->m_buffer, TTD_SERIALIZATION_BUFFER_SIZE);
this->m_buffer = nullptr;
}
}
uint32 FileReader::ReadLengthValue(bool readSeparator)
{
this->ReadKey(NSTokens::Key::count, readSeparator);
return this->ReadNakedUInt32();
}
void FileReader::ReadSequenceStart_WDefaultKey(bool readSeparator)
{
this->ReadKey(NSTokens::Key::values, readSeparator);
this->ReadSequenceStart();
}
void FileReader::ReadRecordStart_WDefaultKey(bool readSeparator)
{
this->ReadKey(NSTokens::Key::entry, readSeparator);
this->ReadRecordStart();
}
void FileReader::ReadNull(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadKey(keyCheck, readSeparator);
this->ReadNakedNull();
}
int32 FileReader::ReadInt32(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadKey(keyCheck, readSeparator);
return this->ReadNakedInt32();
}
uint32 FileReader::ReadUInt32(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadKey(keyCheck, readSeparator);
return this->ReadNakedUInt32();
}
int64 FileReader::ReadInt64(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadKey(keyCheck, readSeparator);
return this->ReadNakedInt64();
}
uint64 FileReader::ReadUInt64(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadKey(keyCheck, readSeparator);
return this->ReadNakedUInt64();
}
double FileReader::ReadDouble(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadKey(keyCheck, readSeparator);
return this->ReadNakedDouble();
}
TTD_PTR_ID FileReader::ReadAddr(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadKey(keyCheck, readSeparator);
return this->ReadNakedAddr();
}
TTD_LOG_PTR_ID FileReader::ReadLogTag(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadKey(keyCheck, readSeparator);
return this->ReadNakedLogTag();
}
//////////////////
NSTokens::ParseTokenKind TextFormatReader::Scan(JsUtil::List<char16, HeapAllocator>& charList)
{
char16 c = _u('\0');
charList.Clear();
while(this->ReadRawChar(&c))
{
switch(c)
{
case 0:
return NSTokens::ParseTokenKind::Error; //we shouldn't hit EOF explicitly here
case _u('\t'):
case _u('\r'):
case _u('\n'):
case _u(' '):
//WS - keep looping
break;
case _u(','):
return NSTokens::ParseTokenKind::Comma;
case _u(':'):
return NSTokens::ParseTokenKind::Colon;
case _u('['):
return NSTokens::ParseTokenKind::LBrack;
case _u(']'):
return NSTokens::ParseTokenKind::RBrack;
case _u('{'):
return NSTokens::ParseTokenKind::LCurly;
case _u('}'):
return NSTokens::ParseTokenKind::RCurly;
case _u('#'):
//# starts special double/number value representation
return this->ScanSpecialNumber();
case _u('-'):
case _u('+'):
case _u('0'):
case _u('1'):
case _u('2'):
case _u('3'):
case _u('4'):
case _u('5'):
case _u('6'):
case _u('7'):
case _u('8'):
case _u('9'):
//decimal digit or (-,+) starts a number
charList.Add(c);
return this->ScanNumber(charList);
case _u('*'):
//address
return this->ScanAddress(charList);
case _u('!'):
//log tag
return this->ScanLogTag(charList);
case _u('$'):
//enumeration value tag
return this->ScanEnumTag(charList);
case _u('~'):
//wellknown token
return this->ScanWellKnownToken(charList);
case _u('@'):
//string
return this->ScanString(charList);
default:
//it is a naked literal value (or an error)
return this->ScanNakedString(c);
}
}
return NSTokens::ParseTokenKind::Error;
}
NSTokens::ParseTokenKind TextFormatReader::ScanKey(JsUtil::List<char16, HeapAllocator>& charList)
{
charList.Clear();
char16 c = _u('\0');
bool endFound = false;
//Read off any whitespace
while(this->PeekRawChar(&c))
{
if((c != _u('\t')) & (c != _u('\r')) & (c != _u('\n')) & (c != _u(' ')))
{
break;
}
this->ReadRawChar(&c);
}
while(this->PeekRawChar(&c))
{
if(c == 0 || charList.Count() > 256)
{
//we reached the end of the file or the "key" is much longer than it should be
return NSTokens::ParseTokenKind::Error;
}
if(c == _u(':'))
{
//end of the string
endFound = true;
break;
}
else
{
this->ReadRawChar(&c);
charList.Add(c);
}
}
if(!endFound)
{
// no ending found
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::String;
}
NSTokens::ParseTokenKind TextFormatReader::ScanSpecialNumber()
{
char16 c = _u('\0');
bool ok = this->ReadRawChar(&c);
if(ok && c == _u('n'))
{
ok = this->ReadRawChar(&c);
if(!ok || c != _u('a'))
{
return NSTokens::ParseTokenKind::Error;
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('n'))
{
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::NaN;
}
else if(ok && (c == _u('+') || c == _u('-')))
{
char16 signc = c;
ok = this->ReadRawChar(&c);
if(!ok || c != _u('i'))
{
return NSTokens::ParseTokenKind::Error;
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('n'))
{
return NSTokens::ParseTokenKind::Error;
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('f'))
{
return NSTokens::ParseTokenKind::Error;
}
return (signc == _u('+')) ? NSTokens::ParseTokenKind::PosInfty : NSTokens::ParseTokenKind::NegInfty;
}
else if(ok && (c == _u('u') || c == _u('l')))
{
char16 limitc = c;
ok = this->ReadRawChar(&c);
if(!ok || c != _u('b'))
{
return NSTokens::ParseTokenKind::Error;
}
return (limitc == _u('u')) ? NSTokens::ParseTokenKind::UpperBound : NSTokens::ParseTokenKind::LowerBound;
}
else if(ok && c == _u('e'))
{
ok = this->ReadRawChar(&c);
if(!ok || c != _u('p'))
{
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::Epsilon;
}
else
{
return NSTokens::ParseTokenKind::Error;
}
}
NSTokens::ParseTokenKind TextFormatReader::ScanNumber(JsUtil::List<char16, HeapAllocator>& charList)
{
char16 c = _u('\0');
while(this->PeekRawChar(&c) && ((_u('0') <= c && c <= _u('9')) || (c == _u('.'))))
{
this->ReadRawChar(&c);
charList.Add(c);
}
// Null-terminate the list before we try to use the buffer as a string.
charList.Add(_u('\0'));
bool likelyint; //we don't care about this just want to know that it is convertable to a number
const char16* end;
const char16* start = charList.GetBuffer();
double val = Js::NumberUtilities::StrToDbl<char16>(start, &end, likelyint);
if(start == end)
{
return NSTokens::ParseTokenKind::Error;
}
TTDAssert(!Js::JavascriptNumber::IsNan(val), "Bad result from string to double conversion");
return NSTokens::ParseTokenKind::Number;
}
NSTokens::ParseTokenKind TextFormatReader::ScanAddress(JsUtil::List<char16, HeapAllocator>& charList)
{
NSTokens::ParseTokenKind okNumber = this->ScanNumber(charList);
if(okNumber != NSTokens::ParseTokenKind::Number)
{
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::Address;
}
NSTokens::ParseTokenKind TextFormatReader::ScanLogTag(JsUtil::List<char16, HeapAllocator>& charList)
{
NSTokens::ParseTokenKind okNumber = this->ScanNumber(charList);
if(okNumber != NSTokens::ParseTokenKind::Number)
{
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::LogTag;
}
NSTokens::ParseTokenKind TextFormatReader::ScanEnumTag(JsUtil::List<char16, HeapAllocator>& charList)
{
NSTokens::ParseTokenKind okNumber = this->ScanNumber(charList);
if(okNumber != NSTokens::ParseTokenKind::Number)
{
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::EnumTag;
}
NSTokens::ParseTokenKind TextFormatReader::ScanWellKnownToken(JsUtil::List<char16, HeapAllocator>& charList)
{
char16 c = _u('\0');
bool endFound = false;
while(this->ReadRawChar(&c))
{
if(c == 0)
{
return NSTokens::ParseTokenKind::Error;
}
if(c == _u('~'))
{
//end of the string
endFound = true;
break;
}
else
{
charList.Add(c);
}
}
if(!endFound)
{
// no ending found
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::WellKnownToken;
}
NSTokens::ParseTokenKind TextFormatReader::ScanString(JsUtil::List<char16, HeapAllocator>& charList)
{
bool ok = false;
char16 c = _u('\0');
//first we should find a number
NSTokens::ParseTokenKind okNumber = this->ScanNumber(charList);
if(okNumber != NSTokens::ParseTokenKind::Number)
{
return NSTokens::ParseTokenKind::Error;
}
// Convert this number to get the length of the string (not including ""),
// charList is already null-terminated by the call to ScanNumber.
uint32 length = (uint32)this->ReadUIntFromCharArray(charList.GetBuffer());
//read the lead "\""
ok = this->ReadRawChar(&c);
if(!ok || c != _u('\"'))
{
return NSTokens::ParseTokenKind::Error;
}
//read that many chars and check for the terminating "\""
charList.Clear();
for(uint32 i = 0; i < length; ++i)
{
ok = this->ReadRawChar(&c);
if(!ok)
{
return NSTokens::ParseTokenKind::Error;
}
charList.Add(c);
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('\"'))
{
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::String;
}
NSTokens::ParseTokenKind TextFormatReader::ScanNakedString(char16 leadChar)
{
bool ok = false;
char16 c = _u('\0');
if(leadChar == _u('n'))
{
//check for "null"
ok = this->ReadRawChar(&c);
if(!ok || c != _u('u'))
{
return NSTokens::ParseTokenKind::Error;
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('l'))
{
return NSTokens::ParseTokenKind::Error;
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('l'))
{
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::Null;
}
else if(leadChar == _u('t'))
{
//check for "true"
ok = this->ReadRawChar(&c);
if(!ok || c != _u('r'))
{
return NSTokens::ParseTokenKind::Error;
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('u'))
{
return NSTokens::ParseTokenKind::Error;
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('e'))
{
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::True;
}
else if(leadChar == _u('f'))
{
//check for "false"
ok = this->ReadRawChar(&c);
if(!ok || c != _u('a'))
{
return NSTokens::ParseTokenKind::Error;
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('l'))
{
return NSTokens::ParseTokenKind::Error;
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('s'))
{
return NSTokens::ParseTokenKind::Error;
}
ok = this->ReadRawChar(&c);
if(!ok || c != _u('e'))
{
return NSTokens::ParseTokenKind::Error;
}
return NSTokens::ParseTokenKind::False;
}
else
{
return NSTokens::ParseTokenKind::Error;
}
}
int64 TextFormatReader::ReadIntFromCharArray(const char16* buff)
{
int64 value = 0;
int64 multiplier = 1;
int64 sign = 1;
int32 lastIdx = 0;
if(buff[0] == _u('-'))
{
sign = -1;
lastIdx = 1;
}
int32 digitCount = (int32)wcslen(buff);
for(int32 i = digitCount - 1; i >= lastIdx; --i)
{
char16 digit = buff[i];
uint32 digitValue = (digit - _u('0'));
value += (multiplier * digitValue);
multiplier *= 10;
}
return value * sign;
}
uint64 TextFormatReader::ReadUIntFromCharArray(const char16* buff)
{
uint64 value = 0;
uint64 multiplier = 1;
int32 digitCount = (int32)wcslen(buff);
for(int32 i = digitCount - 1; i >= 0; --i)
{
char16 digit = buff[i];
uint32 digitValue = (digit - _u('0'));
value += (multiplier * digitValue);
multiplier *= 10;
}
return value;
}
double TextFormatReader::ReadDoubleFromCharArray(const char16* buff)
{
bool likelytInt; //we don't care about this as we already know it is a double
const char16* end;
double val = Js::NumberUtilities::StrToDbl<char16>(buff, &end, likelytInt);
TTDAssert((buff != end) && !Js::JavascriptNumber::IsNan(val), "Error in parse.");
return val;
}
TextFormatReader::TextFormatReader(JsTTDStreamHandle handle, TTDReadBytesFromStreamCallback pfRead, TTDFlushAndCloseStreamCallback pfClose)
: FileReader(handle, pfRead, pfClose), m_charListPrimary(&HeapAllocator::Instance), m_charListOpt(&HeapAllocator::Instance), m_charListDiscard(&HeapAllocator::Instance), m_keyNameArray(nullptr), m_keyNameLengthArray(nullptr)
{
byte byteOrderMarker[2] = { 0x0, 0x0 };
this->ReadBytesInto(byteOrderMarker, 2);
TTDAssert(byteOrderMarker[0] == 0xFF && byteOrderMarker[1] == 0xFE, "Byte Order Marker is incorrect!");
NSTokens::InitKeyNamesArray(&(this->m_keyNameArray), &(this->m_keyNameLengthArray));
}
TextFormatReader::~TextFormatReader()
{
NSTokens::CleanupKeyNamesArray(&(this->m_keyNameArray), &(this->m_keyNameLengthArray));
}
void TextFormatReader::ReadSeperator(bool readSeparator)
{
if(readSeparator)
{
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListDiscard);
TTDAssert(tok == NSTokens::ParseTokenKind::Comma, "Error in parse.");
}
}
void TextFormatReader::ReadKey(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadSeperator(readSeparator);
//We do a special scan here for a key (instead of the more general scan we call elsewhere)
NSTokens::ParseTokenKind tok = this->ScanKey(this->m_charListPrimary);
TTDAssert(tok == NSTokens::ParseTokenKind::String, "Error in parse.");
this->m_charListPrimary.Add(_u('\0'));
const char16* keystr = this->m_charListPrimary.GetBuffer();
//check key strings are the same
TTDAssert(1 <= (uint32)keyCheck && (uint32)keyCheck < (uint32)NSTokens::Key::Count, "Error in parse.");
const char16* kname = this->m_keyNameArray[(uint32)keyCheck];
TTDAssert(kname != nullptr, "Error in parse.");
TTDAssert(wcscmp(keystr, kname) == 0, "Error in parse.");
NSTokens::ParseTokenKind toksep = this->Scan(this->m_charListDiscard);
TTDAssert(toksep == NSTokens::ParseTokenKind::Colon, "Error in parse.");
}
void TextFormatReader::ReadSequenceStart(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListDiscard);
TTDAssert(tok == NSTokens::ParseTokenKind::LBrack, "Error in parse.");
}
void TextFormatReader::ReadSequenceEnd()
{
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListDiscard);
TTDAssert(tok == NSTokens::ParseTokenKind::RBrack, "Error in parse.");
}
void TextFormatReader::ReadRecordStart(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListDiscard);
TTDAssert(tok == NSTokens::ParseTokenKind::LCurly, "Error in parse.");
}
void TextFormatReader::ReadRecordEnd()
{
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListDiscard);
TTDAssert(tok == NSTokens::ParseTokenKind::RCurly, "Error in parse.");
}
void TextFormatReader::ReadNakedNull(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListDiscard);
TTDAssert(tok == NSTokens::ParseTokenKind::Null, "Error in parse.");
}
byte TextFormatReader::ReadNakedByte(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::Number, "Error in parse.");
uint64 uval = this->ReadUIntFromCharArray(this->m_charListOpt.GetBuffer());
TTDAssert(uval <= BYTE_MAX, "Error in parse.");
return (byte)uval;
}
bool TextFormatReader::ReadBool(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadKey(keyCheck, readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::True || tok == NSTokens::ParseTokenKind::False, "Error in parse.");
return (tok == NSTokens::ParseTokenKind::True);
}
int32 TextFormatReader::ReadNakedInt32(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::Number, "Error in parse.");
int64 ival = this->ReadIntFromCharArray(this->m_charListOpt.GetBuffer());
TTDAssert(INT32_MIN <= ival && ival <= INT32_MAX, "Error in parse.");
return (int32)ival;
}
uint32 TextFormatReader::ReadNakedUInt32(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::Number, "Error in parse.");
uint64 uval = this->ReadUIntFromCharArray(this->m_charListOpt.GetBuffer());
TTDAssert(uval <= UINT32_MAX, "Error in parse.");
return (uint32)uval;
}
int64 TextFormatReader::ReadNakedInt64(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::Number, "Error in parse.");
return this->ReadIntFromCharArray(this->m_charListOpt.GetBuffer());
}
uint64 TextFormatReader::ReadNakedUInt64(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::Number, "Error in parse.");
return this->ReadUIntFromCharArray(this->m_charListOpt.GetBuffer());
}
double TextFormatReader::ReadNakedDouble(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
double res = -1.0;
switch(tok)
{
case TTD::NSTokens::ParseTokenKind::NaN:
res = Js::JavascriptNumber::NaN;
break;
case TTD::NSTokens::ParseTokenKind::PosInfty:
res = Js::JavascriptNumber::POSITIVE_INFINITY;
break;
case TTD::NSTokens::ParseTokenKind::NegInfty:
res = Js::JavascriptNumber::NEGATIVE_INFINITY;
break;
case TTD::NSTokens::ParseTokenKind::UpperBound:
res = Js::JavascriptNumber::MAX_VALUE;
break;
case TTD::NSTokens::ParseTokenKind::LowerBound:
res = Js::JavascriptNumber::MIN_VALUE;
break;
case TTD::NSTokens::ParseTokenKind::Epsilon:
res = Js::Math::EPSILON;
break;
default:
{
TTDAssert(tok == NSTokens::ParseTokenKind::Number, "Error in parse.");
res = this->ReadDoubleFromCharArray(this->m_charListOpt.GetBuffer());
break;
}
}
return res;
}
TTD_PTR_ID TextFormatReader::ReadNakedAddr(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::Address, "Error in parse.");
return (TTD_PTR_ID)this->ReadUIntFromCharArray(this->m_charListOpt.GetBuffer());
}
TTD_LOG_PTR_ID TextFormatReader::ReadNakedLogTag(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::LogTag, "Error in parse.");
return (TTD_LOG_PTR_ID)this->ReadUIntFromCharArray(this->m_charListOpt.GetBuffer());
}
uint32 TextFormatReader::ReadNakedTag(bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::EnumTag, "Error in parse.");
uint64 tval = this->ReadUIntFromCharArray(this->m_charListOpt.GetBuffer());
TTDAssert(tval <= UINT32_MAX, "Error in parse.");
return (uint32)tval;
}
////
void TextFormatReader::ReadNakedString(SlabAllocator& alloc, TTString& into, bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::String || tok == NSTokens::ParseTokenKind::Null, "Error in parse.");
if(tok == NSTokens::ParseTokenKind::Null)
{
alloc.CopyNullTermStringInto(nullptr, into);
}
else
{
alloc.CopyStringIntoWLength(this->m_charListOpt.GetBuffer(), this->m_charListOpt.Count(), into);
}
}
void TextFormatReader::ReadNakedString(UnlinkableSlabAllocator& alloc, TTString& into, bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::String || tok == NSTokens::ParseTokenKind::Null, "Error in parse.");
if(tok == NSTokens::ParseTokenKind::Null)
{
alloc.CopyNullTermStringInto(nullptr, into);
}
else
{
alloc.CopyStringIntoWLength(this->m_charListOpt.GetBuffer(), this->m_charListOpt.Count(), into);
}
}
TTD_WELLKNOWN_TOKEN TextFormatReader::ReadNakedWellKnownToken(SlabAllocator& alloc, bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::WellKnownToken, "Error in parse.");
this->m_charListOpt.Add(_u('\0')); //add null terminator
return alloc.CopyRawNullTerminatedStringInto(this->m_charListOpt.GetBuffer());
}
TTD_WELLKNOWN_TOKEN TextFormatReader::ReadNakedWellKnownToken(UnlinkableSlabAllocator& alloc, bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::WellKnownToken, "Error in parse.");
this->m_charListOpt.Add(_u('\0')); //add null terminator
return alloc.CopyRawNullTerminatedStringInto(this->m_charListOpt.GetBuffer() + 1);
}
void TextFormatReader::ReadInlineCode(_Out_writes_(length) char16* code, uint32 length, bool readSeparator)
{
this->ReadSeperator(readSeparator);
NSTokens::ParseTokenKind tok = this->Scan(this->m_charListOpt);
TTDAssert(tok == NSTokens::ParseTokenKind::String, "Error in parse.");
js_memcpy_s(code, length * sizeof(char16), this->m_charListOpt.GetBuffer(), this->m_charListOpt.Count() * sizeof(char16));
}
BinaryFormatReader::BinaryFormatReader(JsTTDStreamHandle handle, TTDReadBytesFromStreamCallback pfRead, TTDFlushAndCloseStreamCallback pfClose)
: FileReader(handle, pfRead, pfClose)
{
;
}
BinaryFormatReader::~BinaryFormatReader()
{
;
}
void BinaryFormatReader::ReadSeperator(bool readSeparator)
{
if(readSeparator)
{
byte sep;
this->ReadBytesInto_Fixed<byte>(sep);
TTDAssert((NSTokens::Separator)sep == NSTokens::Separator::CommaSeparator, "Error in parse.");
}
}
void BinaryFormatReader::ReadKey(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadSeperator(readSeparator);
byte key;
this->ReadBytesInto_Fixed<byte>(key);
TTDAssert((NSTokens::Key)key == keyCheck, "Error in parse.");
}
void BinaryFormatReader::ReadSequenceStart(bool readSeparator)
{
this->ReadSeperator(readSeparator);
byte tok;
this->ReadBytesInto_Fixed<byte>(tok);
TTDAssert(tok == '[', "Error in parse.");
}
void BinaryFormatReader::ReadSequenceEnd()
{
byte tok;
this->ReadBytesInto_Fixed<byte>(tok);
TTDAssert(tok == ']', "Error in parse.");
}
void BinaryFormatReader::ReadRecordStart(bool readSeparator)
{
this->ReadSeperator(readSeparator);
byte tok;
this->ReadBytesInto_Fixed<byte>(tok);
TTDAssert(tok == '{', "Error in parse.");
}
void BinaryFormatReader::ReadRecordEnd()
{
byte tok;
this->ReadBytesInto_Fixed<byte>(tok);
TTDAssert(tok == '}', "Error in parse.");
}
void BinaryFormatReader::ReadNakedNull(bool readSeparator)
{
this->ReadSeperator(readSeparator);
byte tok;
this->ReadBytesInto_Fixed<byte>(tok);
TTDAssert(tok == 0, "Error in parse.");
}
byte BinaryFormatReader::ReadNakedByte(bool readSeparator)
{
this->ReadSeperator(readSeparator);
byte b;
this->ReadBytesInto_Fixed<byte>(b);
return b;
}
bool BinaryFormatReader::ReadBool(NSTokens::Key keyCheck, bool readSeparator)
{
this->ReadKey(keyCheck, readSeparator);
byte b;
this->ReadBytesInto_Fixed<byte>(b);
return !!b;
}
int32 BinaryFormatReader::ReadNakedInt32(bool readSeparator)
{
this->ReadSeperator(readSeparator);
int32 i;
this->ReadBytesInto_Fixed<int32>(i);
return i;
}
uint32 BinaryFormatReader::ReadNakedUInt32(bool readSeparator)
{
this->ReadSeperator(readSeparator);
uint32 i;
this->ReadBytesInto_Fixed<uint32>(i);
return i;
}
int64 BinaryFormatReader::ReadNakedInt64(bool readSeparator)
{
this->ReadSeperator(readSeparator);
int64 i;
this->ReadBytesInto_Fixed<int64>(i);
return i;
}
uint64 BinaryFormatReader::ReadNakedUInt64(bool readSeparator)
{
this->ReadSeperator(readSeparator);
uint64 i;
this->ReadBytesInto_Fixed<uint64>(i);
return i;
}
double BinaryFormatReader::ReadNakedDouble(bool readSeparator)
{
this->ReadSeperator(readSeparator);
double d;
this->ReadBytesInto_Fixed<double>(d);
return d;
}
TTD_PTR_ID BinaryFormatReader::ReadNakedAddr(bool readSeparator)
{
this->ReadSeperator(readSeparator);
TTD_PTR_ID addr;
this->ReadBytesInto_Fixed<TTD_PTR_ID>(addr);
return addr;
}
TTD_LOG_PTR_ID BinaryFormatReader::ReadNakedLogTag(bool readSeparator)
{
this->ReadSeperator(readSeparator);
TTD_LOG_PTR_ID tag;
this->ReadBytesInto_Fixed<TTD_LOG_PTR_ID>(tag);
return tag;
}
uint32 BinaryFormatReader::ReadNakedTag(bool readSeparator)
{
this->ReadSeperator(readSeparator);
uint32 tag;
this->ReadBytesInto_Fixed<uint32>(tag);
return tag;
}
void BinaryFormatReader::ReadNakedString(SlabAllocator& alloc, TTString& into, bool readSeparator)
{
this->ReadSeperator(readSeparator);
uint32 sizeField;
this->ReadBytesInto_Fixed<uint32>(sizeField);
if(sizeField == UINT32_MAX)
{
alloc.CopyNullTermStringInto(nullptr, into);
}
else
{
alloc.InitializeAndAllocateWLength(sizeField, into);
this->ReadBytesInto((byte*)into.Contents, into.Length * sizeof(char16));
into.Contents[into.Length] = '\0';
}
}
void BinaryFormatReader::ReadNakedString(UnlinkableSlabAllocator& alloc, TTString& into, bool readSeparator)
{
this->ReadSeperator(readSeparator);
uint32 sizeField;
this->ReadBytesInto_Fixed<uint32>(sizeField);
if(sizeField == UINT32_MAX)
{
alloc.CopyNullTermStringInto(nullptr, into);
}
else
{
alloc.InitializeAndAllocateWLength(sizeField, into);
this->ReadBytesInto((byte*)into.Contents, into.Length * sizeof(char16));
into.Contents[into.Length] = '\0';
}
}
TTD_WELLKNOWN_TOKEN BinaryFormatReader::ReadNakedWellKnownToken(SlabAllocator& alloc, bool readSeparator)
{
this->ReadSeperator(readSeparator);
uint32 charLen;
this->ReadBytesInto_Fixed<uint32>(charLen);
char16* cbuff = alloc.SlabAllocateArray<char16>(charLen + 1);
this->ReadBytesInto((byte*)cbuff, charLen * sizeof(char16));
cbuff[charLen] = _u('\0');
return cbuff;
}
TTD_WELLKNOWN_TOKEN BinaryFormatReader::ReadNakedWellKnownToken(UnlinkableSlabAllocator& alloc, bool readSeparator)
{
this->ReadSeperator(readSeparator);
uint32 charLen;
this->ReadBytesInto_Fixed<uint32>(charLen);
char16* cbuff = alloc.SlabAllocateArray<char16>(charLen + 1);
this->ReadBytesInto((byte*)cbuff, charLen * sizeof(char16));
cbuff[charLen] = _u('\0');
return cbuff;
}
void BinaryFormatReader::ReadInlineCode(_Out_writes_(length) char16* code, uint32 length, bool readSeparator)
{
uint32 wlen = 0;
this->ReadBytesInto_Fixed<uint32>(wlen);
TTDAssert(wlen == length, "Not exepcted string length!!!");
this->ReadBytesInto((byte*)code, length * sizeof(char16));
}
//////////////////
#if ENABLE_OBJECT_SOURCE_TRACKING
bool IsDiagnosticOriginInformationValid(const DiagnosticOrigin& info)
{
return info.SourceLine != -1;
}
void InitializeDiagnosticOriginInformation(DiagnosticOrigin& info)
{
info.SourceLine = -1;
info.EventTime = 0;
info.TimeHash = 0;
}
void CopyDiagnosticOriginInformation(DiagnosticOrigin& infoInto, const DiagnosticOrigin& infoFrom)
{
infoInto.SourceLine = infoFrom.SourceLine;
infoInto.EventTime = infoFrom.EventTime;
infoInto.TimeHash = infoFrom.TimeHash;
}
void SetDiagnosticOriginInformation(DiagnosticOrigin& info, uint32 sourceLine, uint64 eTime, uint64 fTime, uint64 lTime)
{
info.SourceLine = sourceLine;
info.EventTime = (uint32)eTime;
info.TimeHash = ((uint32)(lTime << 32)) | ((uint32)fTime);
}
void EmitDiagnosticOriginInformation(const DiagnosticOrigin& info, FileWriter* writer, NSTokens::Separator separator)
{
writer->WriteRecordStart(separator);
writer->WriteInt32(NSTokens::Key::line, info.SourceLine);
writer->WriteUInt32(NSTokens::Key::eventTime, info.EventTime, NSTokens::Separator::CommaSeparator);
writer->WriteUInt64(NSTokens::Key::u64Val, info.TimeHash, NSTokens::Separator::CommaSeparator);
writer->WriteRecordEnd();
}
void ParseDiagnosticOriginInformation(DiagnosticOrigin& info, bool readSeperator, FileReader* reader)
{
reader->ReadRecordStart(readSeperator);
info.SourceLine = reader->ReadInt32(NSTokens::Key::line);
info.EventTime = reader->ReadUInt32(NSTokens::Key::eventTime, true);
info.TimeHash = reader->ReadUInt64(NSTokens::Key::u64Val, true);
reader->ReadRecordEnd();
}
#endif
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
void TraceLogger::AppendText(char* text, uint32 length)
{
this->EnsureSpace(length);
this->AppendRaw(text, length);
}
void TraceLogger::AppendText(const char16* text, uint32 length)
{
this->EnsureSpace(length);
this->AppendRaw(text, length);
}
void TraceLogger::AppendIndent()
{
uint32 totalIndent = this->m_indentSize * 2;
while(totalIndent > TRACE_LOGGER_INDENT_BUFFER_SIZE)
{
this->EnsureSpace(TRACE_LOGGER_INDENT_BUFFER_SIZE);
this->AppendRaw(this->m_indentBuffer, TRACE_LOGGER_INDENT_BUFFER_SIZE);
totalIndent -= TRACE_LOGGER_INDENT_BUFFER_SIZE;
}
this->EnsureSpace(totalIndent);
this->AppendRaw(this->m_indentBuffer, totalIndent);
}
void TraceLogger::AppendString(char* text)
{
uint32 length = (uint32)strlen(text);
this->AppendText(text, length);
}
void TraceLogger::AppendBool(bool bval)
{
if(bval)
{
this->AppendLiteral("true");
}
else
{
this->AppendLiteral("false");
}
}
void TraceLogger::AppendInteger(int64 ival)
{
this->EnsureSpace(64);
this->m_currLength += sprintf_s(this->m_buffer + this->m_currLength, 64, "%I64i", ival);
}
void TraceLogger::AppendUnsignedInteger(uint64 ival)
{
this->EnsureSpace(64);
this->m_currLength += sprintf_s(this->m_buffer + this->m_currLength, 64, "%I64u", ival);
}
void TraceLogger::AppendIntegerHex(int64 ival)
{
this->EnsureSpace(64);
this->m_currLength += sprintf_s(this->m_buffer + this->m_currLength, 64, "0x%I64x", ival);
}
void TraceLogger::AppendDouble(double dval)
{
this->EnsureSpace(64);
if(INT32_MIN <= dval && dval <= INT32_MAX && floor(dval) == dval)
{
this->m_currLength += sprintf_s(this->m_buffer + this->m_currLength, 64, "%I64i", (int64)dval);
}
else
{
this->m_currLength += sprintf_s(this->m_buffer + this->m_currLength, 64, "%.32f", dval);
}
}
TraceLogger::TraceLogger(FILE* outfile)
: m_currLength(0), m_indentSize(0), m_outfile(outfile)
{
this->m_buffer = (char*)malloc(TRACE_LOGGER_BUFFER_SIZE);
TTDAssert(this->m_buffer != nullptr, "Malloc failure in tracing code.");
this->m_indentBuffer = (char*)malloc(TRACE_LOGGER_INDENT_BUFFER_SIZE);
TTDAssert(this->m_indentBuffer != nullptr, "Malloc failure in tracing code.");
memset(this->m_buffer, 0, TRACE_LOGGER_BUFFER_SIZE);
memset(this->m_indentBuffer, 0, TRACE_LOGGER_INDENT_BUFFER_SIZE);
}
TraceLogger::~TraceLogger()
{
this->ForceFlush();
if(this->m_outfile != stdout && this->m_outfile != stderr)
{
fclose(this->m_outfile);
}
free(this->m_buffer);
free(this->m_indentBuffer);
}
void TraceLogger::ForceFlush()
{
if(this->m_currLength != 0)
{
fwrite(this->m_buffer, sizeof(char), this->m_currLength, this->m_outfile);
this->m_currLength = 0;
}
fflush(this->m_outfile);
}
void TraceLogger::WriteEnumAction(int64 eTime, BOOL returnCode, Js::PropertyId pid, Js::PropertyAttributes attrib, Js::JavascriptString* pname)
{
this->AppendLiteral("EnumAction(time: ");
this->AppendInteger(eTime);
this->AppendLiteral(", rCode: ");
this->AppendInteger(returnCode);
this->AppendLiteral(", pid: ");
this->AppendInteger(pid);
if(returnCode)
{
this->AppendLiteral(", attrib: ");
this->AppendInteger(attrib);
this->AppendLiteral(", name: ");
this->AppendText(pname->GetSz(), (uint32)pname->GetLength());
}
this->AppendLiteral(")\n");
}
void TraceLogger::WriteVar(Js::Var var, bool skipStringContents)
{
if(var == nullptr)
{
this->AppendLiteral("nullptr");
}
else
{
Js::TypeId tid = Js::JavascriptOperators::GetTypeId(var);
switch(tid)
{
case Js::TypeIds_Undefined:
this->AppendLiteral("undefined");
break;
case Js::TypeIds_Null:
this->AppendLiteral("null");
break;
case Js::TypeIds_Boolean:
this->AppendBool(!!Js::JavascriptBoolean::FromVar(var)->GetValue());
break;
case Js::TypeIds_Integer:
this->AppendInteger(Js::TaggedInt::ToInt64(var));
break;
case Js::TypeIds_Number:
this->AppendDouble(Js::JavascriptNumber::GetValue(var));
break;
case Js::TypeIds_Int64Number:
this->AppendInteger(Js::JavascriptInt64Number::FromVar(var)->GetValue());
break;
case Js::TypeIds_UInt64Number:
this->AppendUnsignedInteger(Js::JavascriptUInt64Number::FromVar(var)->GetValue());
break;
case Js::TypeIds_String:
this->AppendLiteral("'");
if(!skipStringContents)
{
if(Js::JavascriptString::FromVar(var)->GetLength() <= 40)
{
this->AppendText(Js::JavascriptString::FromVar(var)->GetSz(), Js::JavascriptString::FromVar(var)->GetLength());
}
else
{
this->AppendText(Js::JavascriptString::FromVar(var)->GetSz(), 40);
this->AppendLiteral("...");
this->AppendInteger(Js::JavascriptString::FromVar(var)->GetLength());
}
}
else
{
this->AppendLiteral("string@length=");
this->AppendInteger(Js::JavascriptString::FromVar(var)->GetLength());
this->AppendLiteral("...");
}
this->AppendLiteral("'");
break;
default:
{
#if ENABLE_OBJECT_SOURCE_TRACKING
if(tid > Js::TypeIds_LastStaticType)
{
const Js::DynamicObject* dynObj = Js::DynamicObject::FromVar(var);
if(!IsDiagnosticOriginInformationValid(dynObj->TTDDiagOriginInfo))
{
this->AppendLiteral("*");
}
else
{
this->AppendLiteral("obj(");
this->AppendInteger((int64)dynObj->TTDDiagOriginInfo.SourceLine);
this->AppendLiteral(", ");
this->AppendInteger((int64)dynObj->TTDDiagOriginInfo.EventTime);
this->AppendLiteral(", ");
this->AppendInteger((int64)dynObj->TTDDiagOriginInfo.TimeHash);
this->AppendLiteral(")");
}
}
else
{
#endif
this->AppendLiteral("Unspecialized object kind: ");
this->AppendInteger((int64)tid);
#if ENABLE_OBJECT_SOURCE_TRACKING
}
#endif
break;
}
}
}
}
void TraceLogger::WriteCall(Js::JavascriptFunction* function, bool isExternal, uint32 argc, Js::Var* argv, int64 etime)
{
Js::JavascriptString* displayName = function->GetDisplayName();
this->AppendIndent();
const char16* nameStr = displayName->GetSz();
uint32 nameLength = displayName->GetLength();
this->AppendText(nameStr, nameLength);
if(isExternal)
{
this->AppendLiteral("^(");
}
else
{
this->AppendLiteral("(");
}
for(uint32 i = 0; i < argc; ++i)
{
if(i != 0)
{
this->AppendLiteral(", ");
}
this->WriteVar(argv[i]);
}
this->AppendLiteral(")");
this->AppendLiteral(" @ ");
this->AppendInteger(etime);
this->AppendLiteral("\n");
this->m_indentSize++;
}
void TraceLogger::WriteReturn(Js::JavascriptFunction* function, Js::Var res, int64 etime)
{
this->m_indentSize--;
Js::JavascriptString* displayName = function->GetDisplayName();
this->AppendIndent();
this->AppendLiteral("return(");
this->AppendText(displayName->GetSz(), displayName->GetLength());
this->AppendLiteral(") -> ");
this->WriteVar(res);
this->AppendLiteral(" @ ");
this->AppendInteger(etime);
this->AppendLiteral("\n");
}
void TraceLogger::WriteReturnException(Js::JavascriptFunction* function, int64 etime)
{
this->m_indentSize--;
Js::JavascriptString* displayName = function->GetDisplayName();
this->AppendIndent();
this->AppendLiteral("return(");
this->AppendText(displayName->GetSz(), displayName->GetLength());
this->AppendLiteral(") -> !!exception");
this->AppendLiteral(" @ ");
this->AppendInteger(etime);
this->AppendLiteral("\n");
}
void TraceLogger::WriteStmtIndex(uint32 line, uint32 column)
{
this->AppendIndent();
this->EnsureSpace(128);
this->m_currLength += sprintf_s(this->m_buffer + this->m_currLength, 128, "(l:%I32u, c:%I32u)\n", line + 1, column);
////
//Temp debugging help if needed
this->ForceFlush();
//
////
}
void TraceLogger::WriteTraceValue(Js::Var var)
{
this->WriteVar(var, true);
this->WriteLiteralMsg("\n");
}
#endif
}
#endif