ZTupleValue ZUtil_BitTorrent::sTupleValueFromStream(const ZStreamU& s) { ZTupleValue theTV; const uint8 type = s.ReadUInt8(); switch (type) { case 'd': { // Dictionary ZTuple& theTuple = theTV.SetMutableTuple(); for (;;) { if (sTryRead_Byte(s, 'e')) break; string name = sReadString(s); theTuple.SetValue(name, sTupleValueFromStream(s)); } break; } case 'l': { // List vector<ZTupleValue>& theVector = theTV.SetMutableVector(); for (;;) { if (sTryRead_Byte(s, 'e')) break; theVector.push_back(sTupleValueFromStream(s)); } break; } case 'i': { // Integer theTV = sReadInteger(s); uint8 terminator = s.ReadUInt8(); if (terminator != 'e') throw runtime_error("Expected 'e' terminator for integer"); break; } default: { s.Unread(); // It must be a 'string'. It could be valid UTF-8, or could be // arbitrary bytes, so we call sReadStringish. theTV = sReadStringish(s); break; } } return theTV; }
static bool sFromStrim_TupleValue(const ZStrimU& iStrimU, ZTupleValue& oTupleValue) { using namespace ZUtil_Strim; sSkip_WSAndCPlusPlusComments(iStrimU); if (sTryRead_CP(iStrimU, '[')) { sFromStrim_BodyOfVector(iStrimU, oTupleValue.SetMutableVector()); sSkip_WSAndCPlusPlusComments(iStrimU); if (!sTryRead_CP(iStrimU, ']')) throw ParseException("Expected ']' to close a vector"); } else if (sTryRead_CP(iStrimU, '{')) { // It's a tuple. sFromStrim_BodyOfTuple(iStrimU, oTupleValue.SetMutableTuple()); sSkip_WSAndCPlusPlusComments(iStrimU); if (!sTryRead_CP(iStrimU, '}')) throw ParseException("Expected '}' to close a tuple"); } else if (sTryRead_CP(iStrimU, '"')) { // It's a string, delimited by ". sReadQuotedString_Quote(iStrimU, oTupleValue); } else if (sTryRead_CP(iStrimU, '\'')) { // It's a string, delimited by '. sReadQuotedString_Apos(iStrimU, oTupleValue); } else if (sTryRead_CP(iStrimU, '(')) { // It's a raw. ZMemoryBlock theMemoryBlock; ZStreamR_HexStrim(iStrimU).CopyAllTo(ZStreamRWPos_MemoryBlock(theMemoryBlock)); sSkip_WSAndCPlusPlusComments(iStrimU); if (!sTryRead_CP(iStrimU, ')')) throw ParseException("Expected ')' to close a raw"); oTupleValue.SetRaw(theMemoryBlock); } else { string theTypeLC, theType; if (!ZUtil_Tuple::sRead_Identifier(iStrimU, &theTypeLC, &theType)) { // We couldn't find any of the special characters, nor could // we read a type designator, so we fail to read a tuplevalue, // which is not a parse error at this stage -- it might be for our caller. return false; } if (theTypeLC == "null") { oTupleValue.SetNull(); } else if (theTypeLC == "false") { oTupleValue.SetBool(false); } else if (theTypeLC == "true") { oTupleValue.SetBool(true); } else { sSkip_WSAndCPlusPlusComments(iStrimU); if (!sTryRead_CP(iStrimU, '(')) throw ParseException("Expected '(' following a type designator"); sSkip_WSAndCPlusPlusComments(iStrimU); if (theTypeLC == "type") { string typeValueLC, typeValue; if (!ZUtil_Tuple::sRead_Identifier(iStrimU, &typeValueLC, &typeValue)) throw ParseException("Expected a type name"); if (typeValueLC == "null") oTupleValue.SetType(eZType_Null); else if (typeValueLC == "string") oTupleValue.SetType(eZType_String); else if (typeValueLC == "cstring") oTupleValue.SetType(eZType_CString); else if (typeValueLC == "int8") oTupleValue.SetType(eZType_Int8); else if (typeValueLC == "int16") oTupleValue.SetType(eZType_Int16); else if (typeValueLC == "int32") oTupleValue.SetType(eZType_Int32); else if (typeValueLC == "int64") oTupleValue.SetType(eZType_Int64); else if (typeValueLC == "float") oTupleValue.SetType(eZType_Float); else if (typeValueLC == "double") oTupleValue.SetType(eZType_Double); else if (typeValueLC == "time") oTupleValue.SetType(eZType_Time); else if (typeValueLC == "bool") oTupleValue.SetType(eZType_Bool); else if (typeValueLC == "pointer") oTupleValue.SetType(eZType_Pointer); else if (typeValueLC == "raw") oTupleValue.SetType(eZType_Raw); else if (typeValueLC == "tuple") oTupleValue.SetType(eZType_Tuple); else if (typeValueLC == "refcounted") oTupleValue.SetType(eZType_RefCounted); else if (typeValueLC == "rect") oTupleValue.SetType(eZType_Rect); else if (typeValueLC == "point") oTupleValue.SetType(eZType_Point); else if (typeValueLC == "region") oTupleValue.SetType(eZType_Region); else if (typeValueLC == "id") oTupleValue.SetType(eZType_ID); else if (typeValueLC == "vector") oTupleValue.SetType(eZType_Vector); else if (typeValueLC == "type") oTupleValue.SetType(eZType_Type); else if (typeValueLC == "time") oTupleValue.SetType(eZType_Time); else throw ParseException("Unknown type name '" + typeValue + "'"); } else if (theTypeLC == "id") { oTupleValue.SetID(sMustRead_GenericInteger(iStrimU)); } else if (theTypeLC == "int8") { oTupleValue.SetInt8(sMustRead_GenericInteger(iStrimU)); } else if (theTypeLC == "int16") { oTupleValue.SetInt16(sMustRead_GenericInteger(iStrimU)); } else if (theTypeLC == "int32") { oTupleValue.SetInt32(sMustRead_GenericInteger(iStrimU)); } else if (theTypeLC == "int64") { oTupleValue.SetInt64(sMustRead_GenericInteger(iStrimU)); } else if (theTypeLC == "bool") { string theBool; if (!ZUtil_Tuple::sRead_Identifier(iStrimU, &theBool, nil)) throw ParseException("Expected 'false' or 'true'"); if (theBool == "true") oTupleValue.SetBool(true); else if (theBool == "false") oTupleValue.SetBool(false); else throw ParseException("Expected 'false' or 'true'"); } else if (theTypeLC == "float") { double theDouble; if (!sTryRead_SignedDouble(iStrimU, theDouble)) throw ParseException("Expected a floating point number"); oTupleValue.SetFloat(theDouble); } else if (theTypeLC == "double") { double theDouble; if (!sTryRead_SignedDouble(iStrimU, theDouble)) throw ParseException("Expected a floating point number"); oTupleValue.SetDouble(theDouble); } else if (theTypeLC == "time") { if (sTryRead_CP(iStrimU, ')')) { // It's a time with no content, hence an invalid time. oTupleValue.SetTime(ZTime()); // We'll take an early exit so the normal code that // looks for a closing parenthesis doesn't choke. return true; } // Try to read a double, which is how we're representing // times in text streams for now. double theDouble; if (!sTryRead_SignedDouble(iStrimU, theDouble)) throw ParseException("Expected a floating point time"); oTupleValue.SetTime(theDouble); } else if (theTypeLC == "rect") { ZRectPOD theRect; theRect.left = sMustRead_GenericInteger(iStrimU); sMustRead_WSCommaWS(iStrimU); theRect.top = sMustRead_GenericInteger(iStrimU); sMustRead_WSCommaWS(iStrimU); theRect.right = sMustRead_GenericInteger(iStrimU); sMustRead_WSCommaWS(iStrimU); theRect.bottom = sMustRead_GenericInteger(iStrimU); oTupleValue.SetRect(theRect); } else if (theTypeLC == "point") { ZPointPOD thePoint; thePoint.h = sMustRead_GenericInteger(iStrimU); sMustRead_WSCommaWS(iStrimU); thePoint.v = sMustRead_GenericInteger(iStrimU); oTupleValue.SetPoint(thePoint); } else { throw ParseException("Unknown type designator '" + theType + "'"); } sSkip_WSAndCPlusPlusComments(iStrimU); if (!sTryRead_CP(iStrimU, ')')) throw ParseException("Expected ')' to close a value"); } } return true; }