static void sWriteAsXML(ZStrimW_ML& s, const string& iName, const ZTupleValue& iTV) { switch (iTV.TypeOf()) { case eZType_Vector: { const vector<ZTupleValue>& v = iTV.GetVector(); for (vector<ZTupleValue>::const_iterator i = v.begin(); i != v.end(); ++i) sWriteAsXML(s, iName, *i); break; } case eZType_Tuple: { s.Begin(iName); sWriteAsXML(s, iTV.GetTuple()); s.End(iName); break; } case eZType_String: { s.Begin(iName); bool old = s.Indent(false); s << iTV.GetString(); s.End(iName); s.Indent(old); break; } case eZType_Null: { s.Empty(iName); break; } } }
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 ZTuple sGetProp(const ZNode& iNode, const string& iPropName) { ZTuple propT; if (iPropName == "D:resourcetype") { if (iNode.CanHaveChildren()) propT.SetTuple(iPropName, ZTuple().SetNull("D:collection")); else propT.SetNull(iPropName); } else if (iPropName == "D:getcontenttype") { ZTupleValue theValue; if (iNode.GetProp("MIMEType", theValue)) { string theMIMEType; if (theValue.GetString(theMIMEType)) propT.SetString(iPropName, theMIMEType); } } else if (iPropName == "D:creationdate") { ZTupleValue theValue; if (iNode.GetProp("TimeCreated", theValue)) { if (ZTime theTime = theValue.GetTime()) propT.SetString(iPropName, sAsString_WebDAV(theTime)); } } else if (iPropName == "D:getlastmodified") { ZTupleValue theValue; if (iNode.GetProp("TimeModified", theValue)) { if (ZTime theTime = theValue.GetTime()) propT.SetString(iPropName, sAsString_WebDAV(theTime)); } } else if (iPropName == "D:getcontentlength") { ZTupleValue theValue; if (iNode.GetProp("ContentLength", theValue)) { int64 theLength; if (theValue.GetInt64(theLength)) propT.SetString(iPropName, ZString::sFromUInt64(theLength)); } } return propT; }
static bool sIsComplex(const ZUtil_Tuple::Options& iOptions, const ZTupleValue& iTV) { switch (iTV.TypeOf()) { case eZType_Raw: { size_t theSize; iTV.GetRawAttributes(nil, &theSize); return theSize > iOptions.fRawChunkSize; } case eZType_Vector: return !iTV.GetVector().empty(); case eZType_Tuple: return !iTV.GetTuple().Empty(); case eZType_String: return sIsComplexString(iOptions, iTV.GetString()); default: return false; } }
static void sReadQuotedString_Apos(const ZStrimU& iStrimU, ZTupleValue& oTupleValue) { using namespace ZUtil_Strim; string theString; theString.reserve(100); ZStrimW_String theStrimW(theString); for (;;) { sCopy_EscapedString(iStrimU, '\'', theStrimW); if (!sTryRead_CP(iStrimU, '\'')) throw ParseException("Expected ' to close a string"); sSkip_WSAndCPlusPlusComments(iStrimU); if (!sTryRead_CP(iStrimU, '\'')) break; } oTupleValue.SetString(theString); }
bool ZWebDAV::sHandle_GET(const ZTrail& iPrefix, ZNode iRoot, const ZStreamR&, const ZStreamW& iStreamW, const ZTuple& iHeader, const ZTrail& iTrail, const ZTuple& iParam) { ZNode theNode = iRoot.Trail(iTrail); ZHTTP::Response r; r.Set("date", sAsString_WebDAV(ZTime::sNow())); if (iHeader.Has("range")) { if (const ZLog::S& s = ZLog::S(ZLog::eInfo, "ZWebDAV")) s << "GET with range:\n" << iHeader; } if (theNode.Exists()) { r.SetResult(200); if (theNode.CanHaveChildren()) { r.Set("Content-Type", "text/html; charset=\"utf-8\""); r.Set("Transfer-Encoding", "chunked"); r.Send(iStreamW); ZHTTP::StreamW_Chunked chunkedStream(iStreamW); ZStrimW_StreamUTF8 theStrimW(chunkedStream); ZStrimW_ML s(false, theStrimW); s.Begin("html"); s.Begin("title"); s << theNode.Name(); s.End("title"); s.Begin("body"); for (ZNodeIter i = theNode; i; i.Advance()) { s.Begin("p"); s.Begin("a"); if (i.Current().CanHaveChildren()) { s.Attr("href", ZHTTP::sEncodeComponent(i.Current().Name()) + "/"); s << i.Current().Name() << "/"; } else { s.Attr("href", ZHTTP::sEncodeComponent(i.Current().Name())); s << i.Current().Name(); } s.End("a"); s.End("p"); } s.End("body"); s.End("html"); } else if (ZRef<ZStreamerRPos> theStreamer = theNode.OpenRPos()) { const ZStreamRPos& theStreamRPos = theStreamer->GetStreamRPos(); uint64 sentSize = theStreamRPos.GetSize(); if (ZTupleValue rangeParam = iHeader.GetValue("range")) { vector<pair<size_t, size_t> > ranges; if (!ZHTTP::sOrganizeRanges(sentSize, rangeParam, ranges)) { iStreamW.WriteString("HTTP/1.1 406 Unsatisfiable range\r\n\r\n"); return false; } r.SetResult(206, "Partial Content"); r.Set("Content-Range", ZString::sFormat("bytes %d-%d/%d", ranges.front().first, ranges.front().second - 1, sentSize)); theStreamRPos.SetPosition(ranges.front().first); sentSize = ranges.front().second - ranges.front().first; } else { r.SetResult(200); } string theMIMEType = "application/octet-stream"; ZTupleValue theMIMEValue; if (theNode.GetProp("MIMEType", theMIMEValue)) { string asString; if (theMIMEValue.GetString(asString)) theMIMEType = asString; } r.Set("Content-Type", theMIMEType); ZTupleValue theValue; if (theNode.GetProp("lastModified", theValue)) { if (ZTime theTime = theValue.GetTime()) r.Set("Last-Modified", sAsString_WebDAV(theTime)); } r.Set("Content-Transfer-Encoding", "binary"); r.Set("Content-Length", ZString::sFromUInt64(sentSize)); r.Send(iStreamW); iStreamW.CopyFrom(theStreamRPos, sentSize); } } else { r.SetResult(404); r.Send(iStreamW); r.Set("Content-Length", 0); } return true; }
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; }
static void sReadQuotedString_Quote(const ZStrimU& iStrimU, ZTupleValue& oTupleValue) { using namespace ZUtil_Strim; string theString; theString.reserve(100); ZStrimW_String theStrimW(theString); for (;;) { // We've read, and could un-read, a quote mark. if (sTryRead_CP(iStrimU, '"')) { // We've now seen a second quote, abutting the first. if (sTryRead_CP(iStrimU, '"')) { // We have three quotes in a row, which opens a verbatim string. // If the next character is an EOL then absorb it, so the verbatim // text can start on a fresh line, but not be parsed as // beginning with an EOL. UTF32 theCP = iStrimU.ReadCP(); if (!ZUnicode::sIsEOL(theCP)) iStrimU.Unread(); // Now copy everything till we see three quotes in a row again. ZStrimR_Boundary theStrimR_Boundary("\"\"\"", iStrimU); theStrimW.CopyAllFrom(theStrimR_Boundary); if (!theStrimR_Boundary.HitBoundary()) throw ParseException("Expected \"\"\" to close a string"); if (sTryRead_CP(iStrimU, '"')) { // We have another quote, so there were at least four in a row, // which we get with a quote in the text immediately followed // by the triple quote. So emit a quote. theStrimW.WriteCP('"'); if (sTryRead_CP(iStrimU, '"')) { // Same again -- five quotes in a row, which is two content // quotes followed by the closing triple. theStrimW.WriteCP('"'); // This is why it's essential that when using triple quotes // you put whitespace before the opening, and after the closing // triple, so we don't mistake included quotes for ones that // are (say) opening a subsequent regular quoted sequence. } } } else { // We have two quotes in a row, followed by something else, so // we had an empty string segment. } } else { sCopy_EscapedString(iStrimU, '"', theStrimW); if (!sTryRead_CP(iStrimU, '"')) throw ParseException("Expected \" to close a string"); } sSkip_WSAndCPlusPlusComments(iStrimU); if (!sTryRead_CP(iStrimU, '"')) break; } oTupleValue.SetString(theString); }
static void sToStrim_TupleValue(const ZStrimW& s, const ZTupleValue& iTV, size_t iLevel, const ZUtil_Tuple::Options& iOptions, bool iMayNeedInitialLF) { switch (iTV.TypeOf()) { case eZType_Vector: { sToStrim_Vector(s, iTV.GetVector(), iLevel, iOptions, iMayNeedInitialLF); break; } case eZType_Tuple: { sToStrim_Tuple(s, iTV.GetTuple(), iLevel, iOptions, iMayNeedInitialLF); break; } case eZType_Raw: { const void* theData; size_t theSize; iTV.GetRawAttributes(&theData, &theSize); if (theSize == 0) { // we've got an empty Raw s.Write("()"); } else { ZStreamRPos_Memory dataStream(theData, theSize); if (iOptions.DoIndentation() && theSize > iOptions.fRawChunkSize) { if (iMayNeedInitialLF) sWriteLFIndent(s, iLevel, iOptions); s.Writef("( // %d bytes", theSize); sWriteLFIndent(s, iLevel, iOptions); if (iOptions.fRawAsASCII) { for (;;) { uint64 lastPos = dataStream.GetPosition(); uint64 countCopied; ZStreamW_HexStrim(iOptions.fRawByteSeparator, "", 0, s) .CopyFrom(dataStream, iOptions.fRawChunkSize, &countCopied, nil); if (countCopied == 0) break; dataStream.SetPosition(lastPos); if (size_t extraSpaces = iOptions.fRawChunkSize - countCopied) { // We didn't write a complete line of bytes, so pad it out. while (extraSpaces--) { // Two spaces for the two nibbles s.Write(" "); // And then the separator sequence s.Write(iOptions.fRawByteSeparator); } } s.Write(" // "); while (countCopied--) { char theChar = dataStream.ReadInt8(); if (theChar < 0x20 || theChar > 0x7E) s.WriteCP('.'); else s.WriteCP(theChar); } sWriteLFIndent(s, iLevel, iOptions); } } else { string eol = iOptions.fEOLString; for (size_t x = 0; x < iLevel; ++x) eol += iOptions.fIndentString; ZStreamW_HexStrim(iOptions.fRawByteSeparator, eol, iOptions.fRawChunkSize, s).CopyAllFrom(dataStream); sWriteLFIndent(s, iLevel, iOptions); } s.Write(")"); } else { s.Write("("); ZStreamW_HexStrim(iOptions.fRawByteSeparator, "", 0, s) .CopyAllFrom(dataStream); if (iOptions.fRawAsASCII) { dataStream.SetPosition(0); s.Write(" /* "); while (theSize--) { char theChar = dataStream.ReadInt8(); if (theChar < 0x20 || theChar > 0x7E) s.WriteCP('.'); else s.WriteCP(theChar); } s.Write(" */"); } s.Write(")"); } } break; } default: { // We've got something other than a tuple or a vector. sSimpleTupleValueToStrim(s, iTV, iLevel, iOptions); break; } } }
static void sSimpleTupleValueToStrim(const ZStrimW& s, const ZTupleValue& iTV, size_t iLevel, const ZUtil_Tuple::Options& iOptions) { switch (iTV.TypeOf()) { case eZType_Null: s.Write("Null"); break; case eZType_Type: { s.Write("Type("); s.Write(ZTypeAsString(iTV.GetType())); s.Write(")"); break; } case eZType_ID: { s.Writef("ID(0x%0llX)", iTV.GetID()); if (iOptions.fIDsHaveDecimalVersionComment) s.Writef(" /* %lld */", iTV.GetID()); break; } case eZType_Int8: s.Writef("int8(%d)", iTV.GetInt8()); break; case eZType_Int16: s.Writef("int16(%d)", iTV.GetInt16()); break; case eZType_Int32: s.Writef("int32(%d)", iTV.GetInt32()); break; case eZType_Int64: s.Writef("int64(0x%0llX)", iTV.GetInt64()); break; case eZType_Bool: { if (iTV.GetBool()) s.Write("true"); else s.Write("false"); break; } case eZType_Float: { // 9 decimal digits are necessary and sufficient for single precision IEEE 754. // "What Every Computer Scientist Should Know About Floating Point", Goldberg, 1991. // <http://docs.sun.com/source/806-3568/ncg_goldberg.html> s.Writef("float(%.9g)", iTV.GetFloat()); break; } case eZType_Double: { // 17 decimal digits are necessary and sufficient for double precision IEEE 754. s.Writef("double(%.17g)", iTV.GetDouble()); break; } case eZType_Time: { // For the moment I'm just writing times as a count of seconds, putting // the broken-out Gregorian version in a comment. Later we can improve // the parsing of dates, and then we can write them in human readable form. if (ZTime theTime = iTV.GetTime()) { s.Writef("time(%.17g)", theTime.fVal); if (iOptions.fTimesHaveUserLegibleComment) { s << " /*" << ZUtil_Time::sAsStringUTC(theTime, "%Y-%m-%dZ%H:%M:"); // We've got about 10 significant digits in year (-10,000 to +10,000), // month, day, hour, minutes, and seconds, and no more than 17 in a double. // To get a leading zero in the seconds' tens column we add 100 // to the count of seconds, so to get up to 7 digits in the fraction we // need to allow ten digits overall. s << ZString::sFormat("%.10g", 100.0 + fmod(theTime.fVal, 60)).substr(1); s << "*/"; }; } else { // We're now allowing empty parens to represent invalid times. s.Write("time()"); } break; } case eZType_Pointer: s.Writef("pointer(%08X)", iTV.GetPointer()); break; case eZType_Rect: { const ZRectPOD& theRect = iTV.GetRect(); s.Writef("Rect(%d, %d, %d, %d)", theRect.left, theRect.top, theRect.right, theRect.bottom); break; } case eZType_Point: { const ZPointPOD& thePoint = iTV.GetPoint(); s.Writef("Point(%d, %d)", thePoint.h, thePoint.v); break; } case eZType_String: { const string& theString = iTV.GetString(); if (iOptions.fBreakStrings && iOptions.DoIndentation()) { if (string::npos != theString.find_first_of("\n\r")) { // We put a newline after the opening """, which will be // ignored by sFromStrim, so the first line of theString // will be in column zero. s << "\"\"\"\n"; ZStrimU_String strim_String(theString); ZStrimR_Boundary strim_Boundary("\"\"\"", strim_String); for (;;) { s.CopyAllFrom(strim_Boundary); if (!strim_Boundary.HitBoundary()) { // We've returned without having hit the boundary, so we're done. break; } strim_Boundary.Reset(); // Close the triple quotes. s << "\"\"\""; // A space to separate the triple-quote from the single quote s << " "; // An open quote s << "\""; // Three escaped quotes. s << "\\\"\\\"\\\""; // A close quote. s << "\""; // Another space, for symmetry s << " "; // And re-open triple quotes again. s << "\"\"\""; // With a newline, so the text will again // start in column zero. s << "\n"; } s << "\"\"\""; break; } } string delimiter = "\""; bool quoteQuotes = true; if (string::npos != theString.find('"') && string::npos == theString.find('\'')) { delimiter = "'"; quoteQuotes = false; } s.Write(delimiter); ZStrimW_Escapify::Options theOptions; theOptions.fQuoteQuotes = quoteQuotes; theOptions.fEscapeHighUnicode = false; ZStrimW_Escapify(theOptions, s).Write(theString); s.Write(delimiter); break; } case eZType_RefCounted: s.Writef("RefCounted(%08X)", iTV.GetRefCounted().GetObject()); break; case eZType_Raw: case eZType_Tuple: case eZType_Vector: { ZDebugStopf(0, ("sSimpleTupleValueToStrim should only be called on simple tuple values")); break; } default: { ZDebugStopf(0, ("Unrecognized type %d", iTV.TypeOf())); break; } } }