rdf/base/src/nsRDFXMLSerializer.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=4 sw=4 et tw=80:
     3  *
     4  * This Source Code Form is subject to the terms of the Mozilla Public
     5  * License, v. 2.0. If a copy of the MPL was not distributed with this
     6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     8 #include "nsRDFXMLSerializer.h"
    10 #include "nsIAtom.h"
    11 #include "nsIOutputStream.h"
    12 #include "nsIRDFService.h"
    13 #include "nsIRDFContainerUtils.h"
    14 #include "nsIServiceManager.h"
    15 #include "nsString.h"
    16 #include "nsXPIDLString.h"
    17 #include "nsTArray.h"
    18 #include "rdf.h"
    19 #include "rdfutil.h"
    20 #include "mozilla/Attributes.h"
    22 #include "rdfIDataSource.h"
    24 int32_t nsRDFXMLSerializer::gRefCnt = 0;
    25 nsIRDFContainerUtils* nsRDFXMLSerializer::gRDFC;
    26 nsIRDFResource* nsRDFXMLSerializer::kRDF_instanceOf;
    27 nsIRDFResource* nsRDFXMLSerializer::kRDF_type;
    28 nsIRDFResource* nsRDFXMLSerializer::kRDF_nextVal;
    29 nsIRDFResource* nsRDFXMLSerializer::kRDF_Bag;
    30 nsIRDFResource* nsRDFXMLSerializer::kRDF_Seq;
    31 nsIRDFResource* nsRDFXMLSerializer::kRDF_Alt;
    33 static const char kRDFDescriptionOpen[]      = "  <RDF:Description";
    34 static const char kIDAttr[]                  = " RDF:ID=\"";
    35 static const char kAboutAttr[]               = " RDF:about=\"";
    36 static const char kRDFDescriptionClose[]     = "  </RDF:Description>\n";
    37 static const char kRDFResource1[] = " RDF:resource=\"";
    38 static const char kRDFResource2[] = "\"/>\n";
    39 static const char kRDFParseTypeInteger[] = " NC:parseType=\"Integer\">";
    40 static const char kRDFParseTypeDate[] = " NC:parseType=\"Date\">";
    41 static const char kRDFUnknown[] = "><!-- unknown node type -->";
    43 nsresult
    44 nsRDFXMLSerializer::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
    45 {
    46     if (aOuter)
    47         return NS_ERROR_NO_AGGREGATION;
    49     nsCOMPtr<nsIRDFXMLSerializer> result = new nsRDFXMLSerializer();
    50     if (! result)
    51         return NS_ERROR_OUT_OF_MEMORY;
    52     // The serializer object is here, addref gRefCnt so that the
    53     // destructor can safely release it.
    54     gRefCnt++;
    56     nsresult rv;
    57     rv = result->QueryInterface(aIID, aResult);
    59     if (NS_FAILED(rv)) return rv;
    61     if (gRefCnt == 1) do {
    62         nsCOMPtr<nsIRDFService> rdf = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
    63         if (NS_FAILED(rv)) break;
    65         rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"),
    66                               &kRDF_instanceOf);
    67         if (NS_FAILED(rv)) break;
    69         rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"),
    70                               &kRDF_type);
    71         if (NS_FAILED(rv)) break;
    73         rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
    74                               &kRDF_nextVal);
    75         if (NS_FAILED(rv)) break;
    77         rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Bag"),
    78                               &kRDF_Bag);
    79         if (NS_FAILED(rv)) break;
    81         rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Seq"),
    82                               &kRDF_Seq);
    83         if (NS_FAILED(rv)) break;
    85         rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Alt"),
    86                               &kRDF_Alt);
    87         if (NS_FAILED(rv)) break;
    89         rv = CallGetService("@mozilla.org/rdf/container-utils;1", &gRDFC);
    90         if (NS_FAILED(rv)) break;
    91     } while (0);
    93     return rv;
    94 }
    96 nsRDFXMLSerializer::nsRDFXMLSerializer()
    97 {
    98     MOZ_COUNT_CTOR(nsRDFXMLSerializer);
    99 }
   101 nsRDFXMLSerializer::~nsRDFXMLSerializer()
   102 {
   103     MOZ_COUNT_DTOR(nsRDFXMLSerializer);
   105     if (--gRefCnt == 0) {
   106         NS_IF_RELEASE(kRDF_Bag);
   107         NS_IF_RELEASE(kRDF_Seq);
   108         NS_IF_RELEASE(kRDF_Alt);
   109         NS_IF_RELEASE(kRDF_instanceOf);
   110         NS_IF_RELEASE(kRDF_type);
   111         NS_IF_RELEASE(kRDF_nextVal);
   112         NS_IF_RELEASE(gRDFC);
   113     }
   114 }
   116 NS_IMPL_ISUPPORTS(nsRDFXMLSerializer, nsIRDFXMLSerializer, nsIRDFXMLSource)
   118 NS_IMETHODIMP
   119 nsRDFXMLSerializer::Init(nsIRDFDataSource* aDataSource)
   120 {
   121     if (! aDataSource)
   122         return NS_ERROR_NULL_POINTER;
   124     mDataSource = aDataSource;
   125     mDataSource->GetURI(getter_Copies(mBaseURLSpec));
   127     // Add the ``RDF'' prefix, by default.
   128     nsCOMPtr<nsIAtom> prefix;
   130     prefix = do_GetAtom("RDF");
   131     AddNameSpace(prefix, NS_LITERAL_STRING("http://www.w3.org/1999/02/22-rdf-syntax-ns#"));
   133     prefix = do_GetAtom("NC");
   134     AddNameSpace(prefix, NS_LITERAL_STRING("http://home.netscape.com/NC-rdf#"));
   136     mPrefixID = 0;
   138     return NS_OK;
   139 }
   141 NS_IMETHODIMP
   142 nsRDFXMLSerializer::AddNameSpace(nsIAtom* aPrefix, const nsAString& aURI)
   143 {
   144     nsCOMPtr<nsIAtom> prefix = aPrefix;
   145     if (!prefix) {
   146         // Make up a prefix, we don't want default namespaces, so
   147         // that we can use QNames for elements and attributes alike.
   148         prefix = EnsureNewPrefix();
   149     }
   150     mNameSpaces.Put(aURI, prefix);
   151     return NS_OK;
   152 }
   154 static nsresult
   155 rdf_BlockingWrite(nsIOutputStream* stream, const char* buf, uint32_t size)
   156 {
   157     uint32_t written = 0;
   158     uint32_t remaining = size;
   159     while (remaining > 0) {
   160         nsresult rv;
   161         uint32_t cb;
   163         if (NS_FAILED(rv = stream->Write(buf + written, remaining, &cb)))
   164             return rv;
   166         written += cb;
   167         remaining -= cb;
   168     }
   169     return NS_OK;
   170 }
   172 static nsresult
   173 rdf_BlockingWrite(nsIOutputStream* stream, const nsCSubstring& s)
   174 {
   175     return rdf_BlockingWrite(stream, s.BeginReading(), s.Length());
   176 }
   178 static nsresult
   179 rdf_BlockingWrite(nsIOutputStream* stream, const nsAString& s)
   180 {
   181     NS_ConvertUTF16toUTF8 utf8(s);
   182     return rdf_BlockingWrite(stream, utf8.get(), utf8.Length());
   183 }
   185 already_AddRefed<nsIAtom>
   186 nsRDFXMLSerializer::EnsureNewPrefix()
   187 {
   188     nsAutoString qname;
   189     nsCOMPtr<nsIAtom> prefix;
   190     bool isNewPrefix;
   191     do {
   192         isNewPrefix = true;
   193         qname.AssignLiteral("NS");
   194         qname.AppendInt(++mPrefixID, 10);
   195         prefix = do_GetAtom(qname);
   196         nsNameSpaceMap::const_iterator iter = mNameSpaces.first();
   197         while (iter != mNameSpaces.last() && isNewPrefix) {
   198             isNewPrefix = (iter->mPrefix != prefix);
   199             ++iter;
   200         } 
   201     } while (!isNewPrefix);
   202     return prefix.forget();
   203 }
   205 // This converts a property resource (like
   206 // "http://www.w3.org/TR/WD-rdf-syntax#Description") into a QName
   207 // ("RDF:Description"), and registers the namespace, if it's made up.
   209 nsresult
   210 nsRDFXMLSerializer::RegisterQName(nsIRDFResource* aResource)
   211 {
   212     nsAutoCString uri, qname;
   213     aResource->GetValueUTF8(uri);
   215     nsNameSpaceMap::const_iterator iter = mNameSpaces.GetNameSpaceOf(uri);
   216     if (iter != mNameSpaces.last()) {
   217         NS_ENSURE_TRUE(iter->mPrefix, NS_ERROR_UNEXPECTED);
   218         iter->mPrefix->ToUTF8String(qname);
   219         qname.Append(':');
   220         qname += StringTail(uri, uri.Length() - iter->mURI.Length());
   221         mQNames.Put(aResource, qname);
   222         return NS_OK;
   223     }
   225     // Okay, so we don't have it in our map. Try to make one up. This
   226     // is very bogus.
   227     int32_t i = uri.RFindChar('#'); // first try a '#'
   228     if (i == -1) {
   229         i = uri.RFindChar('/');
   230         if (i == -1) {
   231             // Okay, just punt and assume there is _no_ namespace on
   232             // this thing...
   233             mQNames.Put(aResource, uri);
   234             return NS_OK;
   235         }
   236     }
   238     // Take whatever is to the right of the '#' or '/' and call it the
   239     // local name, make up a prefix.
   240     nsCOMPtr<nsIAtom> prefix = EnsureNewPrefix();
   241     mNameSpaces.Put(StringHead(uri, i+1), prefix);
   242     prefix->ToUTF8String(qname);
   243     qname.Append(':');
   244     qname += StringTail(uri, uri.Length() - (i + 1));
   246     mQNames.Put(aResource, qname);
   247     return NS_OK;
   248 }
   250 nsresult
   251 nsRDFXMLSerializer::GetQName(nsIRDFResource* aResource, nsCString& aQName)
   252 {
   253     return mQNames.Get(aResource, &aQName) ? NS_OK : NS_ERROR_UNEXPECTED;
   254 }
   256 bool
   257 nsRDFXMLSerializer::IsContainerProperty(nsIRDFResource* aProperty)
   258 {
   259     // Return `true' if the property is an internal property related
   260     // to being a container.
   261     if (aProperty == kRDF_instanceOf)
   262         return true;
   264     if (aProperty == kRDF_nextVal)
   265         return true;
   267     bool isOrdinal = false;
   268     gRDFC->IsOrdinalProperty(aProperty, &isOrdinal);
   269     if (isOrdinal)
   270         return true;
   272     return false;
   273 } 
   276 // convert '&', '<', and '>' into "&amp;", "&lt;", and "&gt", respectively.
   277 static const char amp[] = "&amp;";
   278 static const char lt[] = "&lt;";
   279 static const char gt[] = "&gt;";
   280 static const char quot[] = "&quot;";
   282 static void
   283 rdf_EscapeAmpersandsAndAngleBrackets(nsCString& s)
   284 {
   285     uint32_t newLength, origLength;
   286     newLength = origLength = s.Length();
   288     // Compute the length of the result string.
   289     const char* start = s.BeginReading();
   290     const char* end = s.EndReading();
   291     const char* c = start;
   292     while (c != end) {
   293         switch (*c) {
   294         case '&' :
   295             newLength += sizeof(amp) - 2;
   296             break;
   297         case '<':
   298         case '>':
   299             newLength += sizeof(gt) - 2;
   300             break;
   301         default:
   302             break;
   303         }
   304         ++c;
   305     }
   306     if (newLength == origLength) {
   307         // nothing to escape
   308         return;
   309     }
   311     // escape the chars from the end back to the front.
   312     s.SetLength(newLength);
   314     // Buffer might have changed, get the pointers again
   315     start = s.BeginReading(); // begin of string
   316     c = start + origLength - 1; // last char in original string
   317     char* w = s.EndWriting() - 1; // last char in grown buffer
   318     while (c >= start) {
   319         switch (*c) {
   320         case '&' :
   321             w -= 4;
   322             nsCharTraits<char>::copy(w, amp, sizeof(amp) - 1);
   323             break;
   324         case '<':
   325             w -= 3;
   326             nsCharTraits<char>::copy(w, lt, sizeof(lt) - 1);
   327             break;
   328         case '>':
   329             w -= 3;
   330             nsCharTraits<char>::copy(w, gt, sizeof(gt) - 1);
   331             break;
   332         default:
   333             *w = *c;
   334         }
   335         --w;
   336         --c;
   337     }
   338 }
   340 // convert '"' to "&quot;"
   341 static void
   342 rdf_EscapeQuotes(nsCString& s)
   343 {
   344     int32_t i = 0;
   345     while ((i = s.FindChar('"', i)) != -1) {
   346         s.Replace(i, 1, quot, sizeof(quot) - 1);
   347         i += sizeof(quot) - 2;
   348     }
   349 }
   351 static void
   352 rdf_EscapeAttributeValue(nsCString& s)
   353 {
   354     rdf_EscapeAmpersandsAndAngleBrackets(s);
   355     rdf_EscapeQuotes(s);
   356 }
   359 nsresult
   360 nsRDFXMLSerializer::SerializeInlineAssertion(nsIOutputStream* aStream,
   361                                              nsIRDFResource* aResource,
   362                                              nsIRDFResource* aProperty,
   363                                              nsIRDFLiteral* aValue)
   364 {
   365     nsresult rv;
   366     nsCString qname;
   367     rv = GetQName(aProperty, qname);
   368     NS_ENSURE_SUCCESS(rv, rv);
   370     rv = rdf_BlockingWrite(aStream,
   371                            NS_LITERAL_CSTRING("\n                   "));
   372     if (NS_FAILED(rv)) return rv;
   374     const char16_t* value;
   375     aValue->GetValueConst(&value);
   376     NS_ConvertUTF16toUTF8 s(value);
   378     rdf_EscapeAttributeValue(s);
   380     rv = rdf_BlockingWrite(aStream, qname);
   381     if (NS_FAILED(rv)) return rv;
   382     rv = rdf_BlockingWrite(aStream, "=\"", 2);
   383     if (NS_FAILED(rv)) return rv;
   384     s.Append('"');
   385     return rdf_BlockingWrite(aStream, s);
   386 }
   388 nsresult
   389 nsRDFXMLSerializer::SerializeChildAssertion(nsIOutputStream* aStream,
   390                                             nsIRDFResource* aResource,
   391                                             nsIRDFResource* aProperty,
   392                                             nsIRDFNode* aValue)
   393 {
   394     nsCString qname;
   395     nsresult rv = GetQName(aProperty, qname);
   396     NS_ENSURE_SUCCESS(rv, rv);
   398     rv = rdf_BlockingWrite(aStream, "    <", 5);
   399     if (NS_FAILED(rv)) return rv;
   400     rv = rdf_BlockingWrite(aStream, qname);
   401     if (NS_FAILED(rv)) return rv;
   403     nsCOMPtr<nsIRDFResource> resource;
   404     nsCOMPtr<nsIRDFLiteral> literal;
   405     nsCOMPtr<nsIRDFInt> number;
   406     nsCOMPtr<nsIRDFDate> date;
   408     if ((resource = do_QueryInterface(aValue)) != nullptr) {
   409         nsAutoCString uri;
   410         resource->GetValueUTF8(uri);
   412         rdf_MakeRelativeRef(mBaseURLSpec, uri);
   413         rdf_EscapeAttributeValue(uri);
   415         rv = rdf_BlockingWrite(aStream, kRDFResource1,
   416                                sizeof(kRDFResource1) - 1);
   417         if (NS_FAILED(rv)) return rv;
   418         rv = rdf_BlockingWrite(aStream, uri);
   419         if (NS_FAILED(rv)) return rv;
   420         rv = rdf_BlockingWrite(aStream, kRDFResource2,
   421                                sizeof(kRDFResource2) - 1);
   422         if (NS_FAILED(rv)) return rv;
   424         goto no_close_tag;
   425     }
   426     else if ((literal = do_QueryInterface(aValue)) != nullptr) {
   427         const char16_t *value;
   428         literal->GetValueConst(&value);
   429         NS_ConvertUTF16toUTF8 s(value);
   431         rdf_EscapeAmpersandsAndAngleBrackets(s);
   433         rv = rdf_BlockingWrite(aStream, ">", 1);
   434         if (NS_FAILED(rv)) return rv;
   435         rv = rdf_BlockingWrite(aStream, s);
   436         if (NS_FAILED(rv)) return rv;
   437     }
   438     else if ((number = do_QueryInterface(aValue)) != nullptr) {
   439         int32_t value;
   440         number->GetValue(&value);
   442         nsAutoCString n;
   443         n.AppendInt(value);
   445         rv = rdf_BlockingWrite(aStream, kRDFParseTypeInteger, 
   446                                sizeof(kRDFParseTypeInteger) - 1);
   447         if (NS_FAILED(rv)) return rv;
   448         rv = rdf_BlockingWrite(aStream, n);
   449         if (NS_FAILED(rv)) return rv;
   450     }
   451     else if ((date = do_QueryInterface(aValue)) != nullptr) {
   452         PRTime value;
   453         date->GetValue(&value);
   455         nsAutoCString s;
   456         rdf_FormatDate(value, s);
   458         rv = rdf_BlockingWrite(aStream, kRDFParseTypeDate, 
   459                                sizeof(kRDFParseTypeDate) - 1);
   460         if (NS_FAILED(rv)) return rv;
   461         rv = rdf_BlockingWrite(aStream, s);
   462         if (NS_FAILED(rv)) return rv;
   463     }
   464     else {
   465         // XXX it doesn't support nsIRDFResource _or_ nsIRDFLiteral???
   466         // We should serialize nsIRDFInt, nsIRDFDate, etc...
   467         NS_WARNING("unknown RDF node type");
   469         rv = rdf_BlockingWrite(aStream, kRDFUnknown, sizeof(kRDFUnknown) - 1);
   470         if (NS_FAILED(rv)) return rv;
   471     }
   473     rv = rdf_BlockingWrite(aStream, "</", 2);
   474     if (NS_FAILED(rv)) return rv;
   475     rv = rdf_BlockingWrite(aStream, qname);
   476     if (NS_FAILED(rv)) return rv;
   477     return rdf_BlockingWrite(aStream, ">\n", 2);
   479  no_close_tag:
   480     return NS_OK;
   481 }
   483 nsresult
   484 nsRDFXMLSerializer::SerializeProperty(nsIOutputStream* aStream,
   485                                       nsIRDFResource* aResource,
   486                                       nsIRDFResource* aProperty,
   487                                       bool aInline,
   488                                       int32_t* aSkipped)
   489 {
   490     nsresult rv = NS_OK;
   492     int32_t skipped = 0;
   494     nsCOMPtr<nsISimpleEnumerator> assertions;
   495     mDataSource->GetTargets(aResource, aProperty, true, getter_AddRefs(assertions));
   496     if (! assertions)
   497         return NS_ERROR_FAILURE;
   499     // Serializing the assertion inline is ok as long as the property has
   500     // only one target value, and it is a literal that doesn't include line
   501     // breaks.
   502     bool needsChild = false;
   504     while (1) {
   505         bool hasMore = false;
   506         assertions->HasMoreElements(&hasMore);
   507         if (! hasMore)
   508             break;
   510         nsCOMPtr<nsISupports> isupports;
   511         assertions->GetNext(getter_AddRefs(isupports));
   512         nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(isupports);
   513         needsChild |= (!literal);
   515         if (!needsChild) {
   516             assertions->HasMoreElements(&needsChild);
   517             if (!needsChild) {
   518                 const char16_t* literalVal = nullptr;
   519                 literal->GetValueConst(&literalVal);
   520                 if (literalVal) {
   521                     for (; *literalVal; literalVal++) {
   522                         if (*literalVal == char16_t('\n') ||
   523                             *literalVal == char16_t('\r')) {
   524                             needsChild = true;
   525                             break;
   526                         }
   527                     }
   528                 }
   529             }
   530         }
   532         if (aInline && !needsChild) {
   533             rv = SerializeInlineAssertion(aStream, aResource, aProperty, literal);
   534         }
   535         else if (!aInline && needsChild) {
   536             nsCOMPtr<nsIRDFNode> value = do_QueryInterface(isupports);
   537             rv = SerializeChildAssertion(aStream, aResource, aProperty, value);
   538         }
   539         else {
   540             ++skipped;
   541             rv = NS_OK;
   542         }
   544         if (NS_FAILED(rv))
   545             break;
   546     }
   548     *aSkipped += skipped;
   549     return rv;
   550 }
   553 nsresult
   554 nsRDFXMLSerializer::SerializeDescription(nsIOutputStream* aStream,
   555                                          nsIRDFResource* aResource)
   556 {
   557     nsresult rv;
   559     bool isTypedNode = false;
   560     nsCString typeQName;
   562     nsCOMPtr<nsIRDFNode> typeNode;
   563     mDataSource->GetTarget(aResource, kRDF_type, true, getter_AddRefs(typeNode));
   564     if (typeNode) {
   565         nsCOMPtr<nsIRDFResource> type = do_QueryInterface(typeNode, &rv);
   566         if (type) {
   567             // Try to get a namespace prefix.  If none is available,
   568             // just treat the description as if it weren't a typed node 
   569             // after all and emit rdf:type as a normal property.  This 
   570             // seems preferable to using a bogus (invented) prefix.
   571             isTypedNode = NS_SUCCEEDED(GetQName(type, typeQName));
   572         }
   573     }
   575     nsAutoCString uri;
   576     rv = aResource->GetValueUTF8(uri);
   577     if (NS_FAILED(rv)) return rv;
   579     rdf_MakeRelativeRef(mBaseURLSpec, uri);
   580     rdf_EscapeAttributeValue(uri);
   582     // Emit an open tag and the subject
   583     if (isTypedNode) {
   584         rv = rdf_BlockingWrite(aStream, NS_LITERAL_STRING("  <"));
   585         if (NS_FAILED(rv)) return rv;
   586         // Watch out for the default namespace!
   587         rv = rdf_BlockingWrite(aStream, typeQName);
   588         if (NS_FAILED(rv)) return rv;
   589     }
   590     else {
   591         rv = rdf_BlockingWrite(aStream, kRDFDescriptionOpen,
   592                                sizeof(kRDFDescriptionOpen) - 1);
   593         if (NS_FAILED(rv)) return rv;
   594     }
   595     if (uri[0] == char16_t('#')) {
   596         uri.Cut(0, 1);
   597         rv = rdf_BlockingWrite(aStream, kIDAttr, sizeof(kIDAttr) - 1);
   598     }
   599     else {
   600         rv = rdf_BlockingWrite(aStream, kAboutAttr, sizeof(kAboutAttr) - 1);
   601     }
   602     if (NS_FAILED(rv)) return rv;
   604     uri.Append('"');
   605     rv = rdf_BlockingWrite(aStream, uri);
   606     if (NS_FAILED(rv)) return rv;
   608     // Any value that's a literal we can write out as an inline
   609     // attribute on the RDF:Description
   610     nsAutoTArray<nsIRDFResource*, 8> visited;
   611     int32_t skipped = 0;
   613     nsCOMPtr<nsISimpleEnumerator> arcs;
   614     mDataSource->ArcLabelsOut(aResource, getter_AddRefs(arcs));
   616     if (arcs) {
   617         // Don't re-serialize rdf:type later on
   618         if (isTypedNode)
   619             visited.AppendElement(kRDF_type);
   621         while (1) {
   622             bool hasMore = false;
   623             arcs->HasMoreElements(&hasMore);
   624             if (! hasMore)
   625                 break;
   627             nsCOMPtr<nsISupports> isupports;
   628             arcs->GetNext(getter_AddRefs(isupports));
   630             nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
   631             if (! property)
   632                 continue;
   634             // Ignore properties that pertain to containers; we may be
   635             // called from SerializeContainer() if the container resource
   636             // has been assigned non-container properties.
   637             if (IsContainerProperty(property))
   638                 continue;
   640             // Only serialize values for the property once.
   641             if (visited.Contains(property.get()))
   642                 continue;
   644             visited.AppendElement(property.get());
   646             SerializeProperty(aStream, aResource, property, true, &skipped);
   647         }
   648     }
   650     if (skipped) {
   651         // Close the RDF:Description tag.
   652         rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING(">\n"));
   653         if (NS_FAILED(rv)) return rv;
   655         // Now write out resources (which might have their own
   656         // substructure) as children.
   657         mDataSource->ArcLabelsOut(aResource, getter_AddRefs(arcs));
   659         if (arcs) {
   660             // Forget that we've visited anything
   661             visited.Clear();
   662             // ... except for rdf:type
   663             if (isTypedNode)
   664                 visited.AppendElement(kRDF_type);
   666             while (1) {
   667                 bool hasMore = false;
   668                 arcs->HasMoreElements(&hasMore);
   669                 if (! hasMore)
   670                     break;
   672                 nsCOMPtr<nsISupports> isupports;
   673                 arcs->GetNext(getter_AddRefs(isupports));
   675                 nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
   676                 if (! property)
   677                     continue;
   679                 // Ignore properties that pertain to containers; we may be
   680                 // called from SerializeContainer() if the container
   681                 // resource has been assigned non-container properties.
   682                 if (IsContainerProperty(property))
   683                     continue;
   685                 // have we already seen this property?  If so, don't write it
   686                 // out again; serialize property will write each instance.
   687                 if (visited.Contains(property.get()))
   688                     continue;
   690                 visited.AppendElement(property.get());
   692                 SerializeProperty(aStream, aResource, property, false, &skipped);
   693             }
   694         }
   696         // Emit a proper close-tag.
   697         if (isTypedNode) {
   698             rv = rdf_BlockingWrite(aStream,  NS_LITERAL_CSTRING("  </"));
   699             if (NS_FAILED(rv)) return rv;
   700             // Watch out for the default namespace!
   701             rdf_BlockingWrite(aStream, typeQName);
   702             if (NS_FAILED(rv)) return rv;
   703             rdf_BlockingWrite(aStream, ">\n", 2);
   704             if (NS_FAILED(rv)) return rv;
   705         }
   706         else {
   707             rv = rdf_BlockingWrite(aStream, kRDFDescriptionClose,
   708                                    sizeof(kRDFDescriptionClose) - 1);
   709             if (NS_FAILED(rv)) return rv;
   710         }
   711     }
   712     else {
   713         // If we saw _no_ child properties, then we can don't need a
   714         // close-tag.
   715         rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING(" />\n"));
   716         if (NS_FAILED(rv)) return rv;
   717     }
   719     return NS_OK;
   720 }
   722 nsresult
   723 nsRDFXMLSerializer::SerializeMember(nsIOutputStream* aStream,
   724                                       nsIRDFResource* aContainer,
   725                                       nsIRDFNode* aMember)
   726 {
   727     // If it's a resource, then output a "<RDF:li RDF:resource=... />"
   728     // tag, because we'll be dumping the resource separately. (We
   729     // iterate thru all the resources in the datasource,
   730     // remember?) Otherwise, output the literal value.
   732     nsCOMPtr<nsIRDFResource> resource;
   733     nsCOMPtr<nsIRDFLiteral> literal;
   734     nsCOMPtr<nsIRDFInt> number;
   735     nsCOMPtr<nsIRDFDate> date;
   737 static const char kRDFLIOpen[] = "    <RDF:li";
   738     nsresult rv = rdf_BlockingWrite(aStream, kRDFLIOpen,
   739                                     sizeof(kRDFLIOpen) - 1); 
   740     if (NS_FAILED(rv)) return rv;
   742     if ((resource = do_QueryInterface(aMember)) != nullptr) {
   743         nsAutoCString uri;
   744         resource->GetValueUTF8(uri);
   746         rdf_MakeRelativeRef(mBaseURLSpec, uri);
   747         rdf_EscapeAttributeValue(uri);
   749         rv = rdf_BlockingWrite(aStream, kRDFResource1,
   750                                sizeof(kRDFResource1) - 1);
   751         if (NS_FAILED(rv)) return rv;
   752         rv = rdf_BlockingWrite(aStream, uri);
   753         if (NS_FAILED(rv)) return rv;
   754         rv = rdf_BlockingWrite(aStream, kRDFResource2,
   755                                sizeof(kRDFResource2) - 1);
   756         if (NS_FAILED(rv)) return rv;
   758         goto no_close_tag;
   759     }
   760     else if ((literal = do_QueryInterface(aMember)) != nullptr) {
   761         const char16_t *value;
   762         literal->GetValueConst(&value);
   763 static const char kRDFLIOpenGT[] = ">";
   764         // close the '<RDF:LI' before adding the literal
   765         rv = rdf_BlockingWrite(aStream, kRDFLIOpenGT,
   766                                sizeof(kRDFLIOpenGT) - 1);
   767         if (NS_FAILED(rv)) return rv;
   769         NS_ConvertUTF16toUTF8 s(value);
   770         rdf_EscapeAmpersandsAndAngleBrackets(s);
   772         rv = rdf_BlockingWrite(aStream, s);
   773         if (NS_FAILED(rv)) return rv;
   774     }
   775     else if ((number = do_QueryInterface(aMember)) != nullptr) {
   776         int32_t value;
   777         number->GetValue(&value);
   779         nsAutoCString n;
   780         n.AppendInt(value);
   782         rv = rdf_BlockingWrite(aStream, kRDFParseTypeInteger, 
   783                                sizeof(kRDFParseTypeInteger) - 1);
   784         if (NS_FAILED(rv)) return rv;
   785         rv = rdf_BlockingWrite(aStream, n);
   786         if (NS_FAILED(rv)) return rv;
   787     }
   788     else if ((date = do_QueryInterface(aMember)) != nullptr) {
   789         PRTime value;
   790         date->GetValue(&value);
   792         nsAutoCString s;
   793         rdf_FormatDate(value, s);
   795         rv = rdf_BlockingWrite(aStream, kRDFParseTypeDate, 
   796                                sizeof(kRDFParseTypeDate) - 1);
   797         if (NS_FAILED(rv)) return rv;
   798         rv = rdf_BlockingWrite(aStream, s);
   799         if (NS_FAILED(rv)) return rv;
   800     }
   801     else {
   802         // XXX it doesn't support nsIRDFResource _or_ nsIRDFLiteral???
   803         // We should serialize nsIRDFInt, nsIRDFDate, etc...
   804         NS_WARNING("unknown RDF node type");
   806         rv = rdf_BlockingWrite(aStream, kRDFUnknown, sizeof(kRDFUnknown) - 1);
   807         if (NS_FAILED(rv)) return rv;
   808     }
   810     {
   811 static const char kRDFLIClose[] = "</RDF:li>\n";
   812         rv = rdf_BlockingWrite(aStream, kRDFLIClose, sizeof(kRDFLIClose) - 1);
   813         if (NS_FAILED(rv)) return rv;
   814     }
   816  no_close_tag:
   817     return NS_OK;
   818 }
   821 nsresult
   822 nsRDFXMLSerializer::SerializeContainer(nsIOutputStream* aStream,
   823                                          nsIRDFResource* aContainer)
   824 {
   825     nsresult rv;
   826     nsAutoCString tag;
   828     // Decide if it's a sequence, bag, or alternation, and print the
   829     // appropriate tag-open sequence
   831     if (IsA(mDataSource, aContainer, kRDF_Bag)) {
   832         tag.AssignLiteral("RDF:Bag");
   833     }
   834     else if (IsA(mDataSource, aContainer, kRDF_Seq)) {
   835         tag.AssignLiteral("RDF:Seq");
   836     }
   837     else if (IsA(mDataSource, aContainer, kRDF_Alt)) {
   838         tag.AssignLiteral("RDF:Alt");
   839     }
   840     else {
   841         NS_ASSERTION(false, "huh? this is _not_ a container.");
   842         return NS_ERROR_UNEXPECTED;
   843     }
   845     rv = rdf_BlockingWrite(aStream, "  <", 3);
   846     if (NS_FAILED(rv)) return rv;
   847     rv = rdf_BlockingWrite(aStream, tag);
   848     if (NS_FAILED(rv)) return rv;
   851     // Unfortunately, we always need to print out the identity of the
   852     // resource, even if was constructed "anonymously". We need to do
   853     // this because we never really know who else might be referring
   854     // to it...
   856     nsAutoCString uri;
   857     if (NS_SUCCEEDED(aContainer->GetValueUTF8(uri))) {
   858         rdf_MakeRelativeRef(mBaseURLSpec, uri);
   860         rdf_EscapeAttributeValue(uri);
   862         if (uri.First() == '#') {
   863             // Okay, it's actually identified as an element in the
   864             // current document, not trying to decorate some absolute
   865             // URI. We can use the 'ID=' attribute...
   867             uri.Cut(0, 1); // chop the '#'
   868             rv = rdf_BlockingWrite(aStream, kIDAttr, sizeof(kIDAttr) - 1);
   869             if (NS_FAILED(rv)) return rv;
   870         }
   871         else {
   872             // We need to cheat and spit out an illegal 'about=' on
   873             // the sequence. 
   874             rv = rdf_BlockingWrite(aStream, kAboutAttr,
   875                                    sizeof(kAboutAttr) - 1);
   876             if (NS_FAILED(rv)) return rv;
   877         }
   879         rv = rdf_BlockingWrite(aStream, uri);
   880         if (NS_FAILED(rv)) return rv;
   881         rv = rdf_BlockingWrite(aStream, "\"", 1);
   882         if (NS_FAILED(rv)) return rv;
   883     }
   885     rv = rdf_BlockingWrite(aStream, ">\n", 2);
   886     if (NS_FAILED(rv)) return rv;
   888     // First iterate through each of the ordinal elements (the RDF/XML
   889     // syntax doesn't allow us to place properties on RDF container
   890     // elements).
   891     nsCOMPtr<nsISimpleEnumerator> elements;
   892     rv = NS_NewContainerEnumerator(mDataSource, aContainer, getter_AddRefs(elements));
   894     if (NS_SUCCEEDED(rv)) {
   895         while (1) {
   896             bool hasMore;
   897             rv = elements->HasMoreElements(&hasMore);
   898             if (NS_FAILED(rv)) break;
   900             if (! hasMore)
   901                 break;
   903             nsCOMPtr<nsISupports> isupports;
   904             elements->GetNext(getter_AddRefs(isupports));
   906             nsCOMPtr<nsIRDFNode> element = do_QueryInterface(isupports);
   907             NS_ASSERTION(element != nullptr, "not an nsIRDFNode");
   908             if (! element)
   909                 continue;
   911             SerializeMember(aStream, aContainer, element);
   912         }
   913     }
   915     // close the container tag
   916     rv = rdf_BlockingWrite(aStream, "  </", 4);
   917     if (NS_FAILED(rv)) return rv;
   918     tag.Append(">\n", 2);
   919     rv = rdf_BlockingWrite(aStream, tag);
   920     if (NS_FAILED(rv)) return rv;
   922     // Now, we iterate through _all_ of the arcs, in case someone has
   923     // applied properties to the bag itself. These'll be placed in a
   924     // separate RDF:Description element.
   925     nsCOMPtr<nsISimpleEnumerator> arcs;
   926     mDataSource->ArcLabelsOut(aContainer, getter_AddRefs(arcs));
   928     bool wroteDescription = false;
   929     while (! wroteDescription) {
   930         bool hasMore = false;
   931         rv = arcs->HasMoreElements(&hasMore);
   932         if (NS_FAILED(rv)) break;
   934         if (! hasMore)
   935             break;
   937         nsIRDFResource* property;
   938         rv = arcs->GetNext((nsISupports**) &property);
   939         if (NS_FAILED(rv)) break;
   941         // If it's a membership property, then output a "LI"
   942         // tag. Otherwise, output a property.
   943         if (! IsContainerProperty(property)) {
   944             rv = SerializeDescription(aStream, aContainer);
   945             wroteDescription = true;
   946         }
   948         NS_RELEASE(property);
   949         if (NS_FAILED(rv))
   950             break;
   951     }
   953     return NS_OK;
   954 }
   957 nsresult
   958 nsRDFXMLSerializer::SerializePrologue(nsIOutputStream* aStream)
   959 {
   960 static const char kXMLVersion[] = "<?xml version=\"1.0\"?>\n";
   962     nsresult rv;
   963     rv = rdf_BlockingWrite(aStream, kXMLVersion, sizeof(kXMLVersion) - 1);
   964     if (NS_FAILED(rv)) return rv;
   966     // global name space declarations
   967     rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("<RDF:RDF "));
   968     if (NS_FAILED(rv)) return rv;
   970     nsNameSpaceMap::const_iterator first = mNameSpaces.first();
   971     nsNameSpaceMap::const_iterator last = mNameSpaces.last();
   972     for (nsNameSpaceMap::const_iterator entry = first; entry != last; ++entry) {
   973         if (entry != first) {
   974             rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("\n         "));
   975             if (NS_FAILED(rv)) return rv;
   976         }
   977         rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("xmlns"));
   978         if (NS_FAILED(rv)) return rv;
   980         if (entry->mPrefix) {
   981             rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING(":"));
   982             if (NS_FAILED(rv)) return rv;
   983             nsAutoCString prefix;
   984             entry->mPrefix->ToUTF8String(prefix);
   985             rv = rdf_BlockingWrite(aStream, prefix);
   986             if (NS_FAILED(rv)) return rv;
   987         }
   989         rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("=\""));
   990         if (NS_FAILED(rv)) return rv;
   991         nsAutoCString uri(entry->mURI);
   992         rdf_EscapeAttributeValue(uri);
   993         rv = rdf_BlockingWrite(aStream, uri);
   994         if (NS_FAILED(rv)) return rv;
   995         rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("\""));
   996         if (NS_FAILED(rv)) return rv;
   997     }
   999     return rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING(">\n"));
  1003 nsresult
  1004 nsRDFXMLSerializer::SerializeEpilogue(nsIOutputStream* aStream)
  1006     return rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("</RDF:RDF>\n"));
  1009 class QNameCollector MOZ_FINAL : public rdfITripleVisitor {
  1010 public:
  1011     NS_DECL_ISUPPORTS
  1012     NS_DECL_RDFITRIPLEVISITOR
  1013     QNameCollector(nsRDFXMLSerializer* aParent)
  1014         : mParent(aParent){}
  1015 private:
  1016     nsRDFXMLSerializer* mParent;
  1017 };
  1019 NS_IMPL_ISUPPORTS(QNameCollector, rdfITripleVisitor)
  1020 nsresult
  1021 QNameCollector::Visit(nsIRDFNode* aSubject, nsIRDFResource* aPredicate,
  1022                       nsIRDFNode* aObject, bool aTruthValue)
  1024     if (aPredicate == mParent->kRDF_type) {
  1025         // try to get a type QName for aObject, should be a resource
  1026         nsCOMPtr<nsIRDFResource> resType = do_QueryInterface(aObject);
  1027         if (!resType) {
  1028             // ignore error
  1029             return NS_OK;
  1031         if (mParent->mQNames.Get(resType, nullptr)) {
  1032             return NS_OK;
  1034         mParent->RegisterQName(resType);
  1035         return NS_OK;
  1038     if (mParent->mQNames.Get(aPredicate, nullptr)) {
  1039         return NS_OK;
  1041     if (aPredicate == mParent->kRDF_instanceOf ||
  1042         aPredicate == mParent->kRDF_nextVal)
  1043         return NS_OK;
  1044     bool isOrdinal = false;
  1045     mParent->gRDFC->IsOrdinalProperty(aPredicate, &isOrdinal);
  1046     if (isOrdinal)
  1047         return NS_OK;
  1049     mParent->RegisterQName(aPredicate);
  1051     return NS_OK;
  1054 nsresult
  1055 nsRDFXMLSerializer::CollectNamespaces()
  1057     // Iterate over all Triples to get namespaces for subject resource types
  1058     // and Predicates and cache all the QNames we want to use.
  1059     nsCOMPtr<rdfITripleVisitor> collector = 
  1060         new QNameCollector(this);
  1061     nsCOMPtr<rdfIDataSource> ds = do_QueryInterface(mDataSource); // XXX API
  1062     NS_ENSURE_TRUE(collector && ds, NS_ERROR_FAILURE);
  1063     return ds->VisitAllTriples(collector);
  1066 //----------------------------------------------------------------------
  1068 NS_IMETHODIMP
  1069 nsRDFXMLSerializer::Serialize(nsIOutputStream* aStream)
  1071     nsresult rv;
  1073     rv = CollectNamespaces();
  1074     if (NS_FAILED(rv)) return rv;
  1076     nsCOMPtr<nsISimpleEnumerator> resources;
  1077     rv = mDataSource->GetAllResources(getter_AddRefs(resources));
  1078     if (NS_FAILED(rv)) return rv;
  1080     rv = SerializePrologue(aStream);
  1081     if (NS_FAILED(rv))
  1082         return rv;
  1084     while (1) {
  1085         bool hasMore = false;
  1086         resources->HasMoreElements(&hasMore);
  1087         if (! hasMore)
  1088             break;
  1090         nsCOMPtr<nsISupports> isupports;
  1091         resources->GetNext(getter_AddRefs(isupports));
  1093         nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(isupports);
  1094         if (! resource)
  1095             continue;
  1097         if (IsA(mDataSource, resource, kRDF_Bag) ||
  1098             IsA(mDataSource, resource, kRDF_Seq) ||
  1099             IsA(mDataSource, resource, kRDF_Alt)) {
  1100             rv = SerializeContainer(aStream, resource);
  1102         else {
  1103             rv = SerializeDescription(aStream, resource);
  1106         if (NS_FAILED(rv))
  1107             break;
  1110     rv = SerializeEpilogue(aStream);
  1112     return rv;
  1116 bool
  1117 nsRDFXMLSerializer::IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType)
  1119     nsresult rv;
  1121     bool result;
  1122     rv = aDataSource->HasAssertion(aResource, kRDF_instanceOf, aType, true, &result);
  1123     if (NS_FAILED(rv)) return false;
  1125     return result;

mercurial