LCOV - code coverage report
Current view: directory - rdf/base/src - nsRDFXMLSerializer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 574 421 73.3 %
Date: 2012-06-02 Functions: 35 33 94.3 %

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

Generated by: LCOV version 1.7