Back to index

lightning-sunbird  0.9+nobinonly
nsSAXXMLReader.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is Robert Sayre.
00018  *
00019  * Portions created by the Initial Developer are Copyright (C) 2005
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Brett Wilson <brettw@gmail.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsIInputStream.h"
00040 #include "nsNetCID.h"
00041 #include "nsNetUtil.h"
00042 #include "nsICharsetAlias.h"
00043 #include "nsParserCIID.h"
00044 #include "nsStreamUtils.h"
00045 #include "nsStringStream.h"
00046 #include "nsSAXAttributes.h"
00047 #include "nsSAXXMLReader.h"
00048 
00049 #define XMLNS_URI "http://www.w3.org/2000/xmlns/"
00050 
00051 static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
00052 
00053 NS_IMPL_ISUPPORTS6(nsSAXXMLReader, nsISAXXMLReader,
00054                    nsIExpatSink, nsIExtendedExpatSink,
00055                    nsIContentSink,  nsIRequestObserver,
00056                    nsIStreamListener)
00057 
00058 nsSAXXMLReader::nsSAXXMLReader() : mIsAsyncParse(PR_FALSE)
00059 {
00060 }
00061 
00062 // nsIContentSink
00063 NS_IMETHODIMP
00064 nsSAXXMLReader::WillBuildModel()
00065 {
00066   if (mContentHandler)
00067     return mContentHandler->StartDocument();
00068 
00069   return NS_OK;
00070 }
00071 
00072 NS_IMETHODIMP
00073 nsSAXXMLReader::DidBuildModel()
00074 {
00075   if (mContentHandler)
00076     return mContentHandler->EndDocument();
00077 
00078   return NS_OK;
00079 }
00080 
00081 NS_IMETHODIMP
00082 nsSAXXMLReader::SetParser(nsIParser *aParser)
00083 {
00084   return NS_OK;
00085 }
00086 
00087 // nsIExtendedExpatSink
00088 NS_IMETHODIMP
00089 nsSAXXMLReader::HandleStartElement(const PRUnichar *aName,
00090                                    const PRUnichar **aAtts,
00091                                    PRUint32 aAttsCount,
00092                                    PRInt32 aIndex,
00093                                    PRUint32 aLineNumber)
00094 {
00095   if (!mContentHandler)
00096     return NS_OK;
00097 
00098   nsCOMPtr<nsSAXAttributes> atts = new nsSAXAttributes();
00099   if (!atts)
00100     return NS_ERROR_OUT_OF_MEMORY;
00101   nsAutoString uri, localName, qName;
00102   for (; *aAtts; aAtts += 2) {
00103     SplitExpatName(aAtts[0], uri, localName, qName);
00104     // XXX don't have attr type information
00105     NS_NAMED_LITERAL_STRING(cdataType, "CDATA");
00106     // could support xmlns reporting, it's a standard SAX feature
00107     if (!uri.EqualsLiteral(XMLNS_URI)) {
00108       NS_ASSERTION(aAtts[1], "null passed to handler");
00109       atts->AddAttribute(uri, localName, qName, cdataType,
00110                          nsDependentString(aAtts[1]));
00111     }
00112   }
00113 
00114   // Deal with the element name
00115   SplitExpatName(aName, uri, localName, qName);
00116   return mContentHandler->StartElement(uri, localName, qName, atts);
00117 }
00118 
00119 NS_IMETHODIMP
00120 nsSAXXMLReader::HandleEndElement(const PRUnichar *aName)
00121 {
00122   if (mContentHandler) {
00123     nsAutoString uri, localName, qName;
00124     SplitExpatName(aName, uri, localName, qName);
00125     return mContentHandler->EndElement(uri, localName, qName);
00126   }
00127   return NS_OK;
00128 }
00129 
00130 NS_IMETHODIMP
00131 nsSAXXMLReader::HandleComment(const PRUnichar *aName)
00132 {
00133   NS_ASSERTION(aName, "null passed to handler");
00134   if (mLexicalHandler)
00135     return mLexicalHandler->Comment(nsDependentString(aName));
00136  
00137   return NS_OK;
00138 }
00139 
00140 NS_IMETHODIMP
00141 nsSAXXMLReader::HandleCDataSection(const PRUnichar *aData,
00142                                    PRUint32 aLength)
00143 {
00144   nsresult rv;
00145   if (mLexicalHandler) {
00146     rv = mLexicalHandler->StartCDATA();
00147     NS_ENSURE_SUCCESS(rv, rv);
00148   }
00149 
00150   if (mContentHandler) {
00151     rv = mContentHandler->Characters(Substring(aData, aData+aLength));
00152     NS_ENSURE_SUCCESS(rv, rv);
00153   }
00154 
00155   if (mLexicalHandler) {
00156     rv = mLexicalHandler->EndCDATA();
00157     NS_ENSURE_SUCCESS(rv, rv);
00158   }
00159 
00160   return NS_OK;
00161 }
00162 
00163 NS_IMETHODIMP
00164 nsSAXXMLReader::HandleStartDTD(const PRUnichar *aName,
00165                                const PRUnichar *aSystemId,
00166                                const PRUnichar *aPublicId)
00167 {
00168   PRUnichar nullChar = PRUnichar(0);
00169   if (!aName)
00170     aName = &nullChar;
00171   if (!aSystemId)
00172     aSystemId = &nullChar;
00173   if (!aPublicId)
00174     aPublicId = &nullChar;
00175 
00176   if (mLexicalHandler) {
00177     return mLexicalHandler->StartDTD(nsDependentString(aName),
00178                                      nsDependentString(aSystemId),
00179                                      nsDependentString(aPublicId));
00180   }
00181 
00182   return NS_OK;
00183 }
00184 
00185 NS_IMETHODIMP
00186 nsSAXXMLReader::HandleDoctypeDecl(const nsAString & aSubset,
00187                                   const nsAString & aName,
00188                                   const nsAString & aSystemId,
00189                                   const nsAString & aPublicId,
00190                                   nsISupports* aCatalogData)
00191 {
00192   if (mLexicalHandler)
00193     return mLexicalHandler->EndDTD();
00194 
00195   return NS_OK;
00196 }
00197 
00198 NS_IMETHODIMP
00199 nsSAXXMLReader::HandleCharacterData(const PRUnichar *aData,
00200                                     PRUint32 aLength)
00201 {
00202   if (mContentHandler)
00203     return mContentHandler->Characters(Substring(aData, aData+aLength));
00204 
00205   return NS_OK;
00206 }
00207 
00208 NS_IMETHODIMP
00209 nsSAXXMLReader::HandleStartNamespaceDecl(const PRUnichar *aPrefix,
00210                                          const PRUnichar *aUri)
00211 {
00212   if (!mContentHandler)
00213     return NS_OK;
00214   
00215   PRUnichar nullChar = PRUnichar(0);
00216   if (!aPrefix)
00217     aPrefix = &nullChar;
00218   if (!aUri)
00219     aUri = &nullChar;
00220 
00221   return mContentHandler->StartPrefixMapping(nsDependentString(aPrefix),
00222                                              nsDependentString(aUri));
00223 }
00224 
00225 NS_IMETHODIMP
00226 nsSAXXMLReader::HandleEndNamespaceDecl(const PRUnichar *aPrefix)
00227 {
00228   if (!mContentHandler)
00229     return NS_OK;
00230   
00231   if (aPrefix)
00232     return mContentHandler->EndPrefixMapping(nsDependentString(aPrefix));
00233 
00234   return mContentHandler->EndPrefixMapping(EmptyString());
00235 }
00236 
00237 NS_IMETHODIMP
00238 nsSAXXMLReader::HandleProcessingInstruction(const PRUnichar *aTarget,
00239                                             const PRUnichar *aData)
00240 {
00241   NS_ASSERTION(aTarget && aData, "null passed to handler");
00242   if (mContentHandler) {
00243     return mContentHandler->ProcessingInstruction(nsDependentString(aTarget),
00244                                                   nsDependentString(aData));
00245   }
00246 
00247   return NS_OK;
00248 }
00249 
00250 NS_IMETHODIMP
00251 nsSAXXMLReader::HandleNotationDecl(const PRUnichar *aNotationName,
00252                                    const PRUnichar *aSystemId,
00253                                    const PRUnichar *aPublicId)
00254 {
00255   NS_ASSERTION(aNotationName, "null passed to handler");
00256   if (mDTDHandler) {
00257     PRUnichar nullChar = PRUnichar(0);
00258     if (!aSystemId)
00259       aSystemId = &nullChar;
00260     if (!aPublicId)
00261       aPublicId = &nullChar;
00262 
00263     return mDTDHandler->NotationDecl(nsDependentString(aNotationName),
00264                                      nsDependentString(aSystemId),
00265                                      nsDependentString(aPublicId));
00266   }
00267 
00268   return NS_OK;
00269 }
00270 
00271 NS_IMETHODIMP
00272 nsSAXXMLReader::HandleUnparsedEntityDecl(const PRUnichar *aEntityName,
00273                                          const PRUnichar *aSystemId,
00274                                          const PRUnichar *aPublicId,
00275                                          const PRUnichar *aNotationName)
00276 {
00277   NS_ASSERTION(aEntityName && aNotationName, "null passed to handler");
00278   if (mDTDHandler) {
00279     PRUnichar nullChar = PRUnichar(0);
00280     if (!aSystemId)
00281       aSystemId = &nullChar;
00282     if (!aPublicId)
00283       aPublicId = &nullChar;
00284 
00285     return mDTDHandler->UnparsedEntityDecl(nsDependentString(aEntityName),
00286                                            nsDependentString(aSystemId),
00287                                            nsDependentString(aPublicId),
00288                                            nsDependentString(aNotationName));
00289   }
00290 
00291   return NS_OK;
00292 }
00293 
00294 NS_IMETHODIMP
00295 nsSAXXMLReader::HandleXMLDeclaration(const PRUnichar *aVersion,
00296                                      const PRUnichar *aEncoding,
00297                                      PRInt32 aStandalone)
00298 {
00299   // XXX need to decide what to do with this. It's a separate
00300   // optional interface in SAX.
00301   return NS_OK;
00302 }
00303 
00304 NS_IMETHODIMP
00305 nsSAXXMLReader::ReportError(const PRUnichar* aErrorText,
00306                             const PRUnichar* aSourceText)
00307 {
00310   if (mErrorHandler)
00311     return mErrorHandler->FatalError(nsnull, nsDependentString(aErrorText));
00312 
00313   return NS_OK;
00314 }
00315 
00316 // nsISAXXMLReader
00317 
00318 NS_IMETHODIMP
00319 nsSAXXMLReader::GetBaseURI(nsIURI **aBaseURI)
00320 {
00321   NS_IF_ADDREF(*aBaseURI = mBaseURI);
00322   return NS_OK;
00323 }
00324 
00325 NS_IMETHODIMP
00326 nsSAXXMLReader::SetBaseURI(nsIURI *aBaseURI)
00327 {
00328   mBaseURI = aBaseURI;
00329   return NS_OK;
00330 }
00331 
00332 NS_IMETHODIMP
00333 nsSAXXMLReader::GetContentHandler(nsISAXContentHandler **aContentHandler)
00334 {
00335   NS_IF_ADDREF(*aContentHandler = mContentHandler);
00336   return NS_OK;
00337 }
00338 
00339 NS_IMETHODIMP
00340 nsSAXXMLReader::SetContentHandler(nsISAXContentHandler *aContentHandler)
00341 {
00342   mContentHandler = aContentHandler;
00343   return NS_OK;
00344 }
00345 
00346 NS_IMETHODIMP
00347 nsSAXXMLReader::GetDtdHandler(nsISAXDTDHandler **aDtdHandler)
00348 {
00349   NS_IF_ADDREF(*aDtdHandler = mDTDHandler);
00350   return NS_OK;
00351 }
00352 
00353 NS_IMETHODIMP
00354 nsSAXXMLReader::SetDtdHandler(nsISAXDTDHandler *aDtdHandler)
00355 {
00356   mDTDHandler = aDtdHandler;
00357   return NS_OK;
00358 }
00359 
00360 NS_IMETHODIMP
00361 nsSAXXMLReader::GetErrorHandler(nsISAXErrorHandler **aErrorHandler)
00362 {
00363   NS_IF_ADDREF(*aErrorHandler = mErrorHandler);
00364   return NS_OK;
00365 }
00366 
00367 NS_IMETHODIMP
00368 nsSAXXMLReader::SetErrorHandler(nsISAXErrorHandler *aErrorHandler)
00369 {
00370   mErrorHandler = aErrorHandler;
00371   return NS_OK;
00372 }
00373 
00374 NS_IMETHODIMP
00375 nsSAXXMLReader::SetFeature(const nsAString &aName, PRBool aValue)
00376 {
00377   return NS_ERROR_NOT_IMPLEMENTED;
00378 }
00379 
00380 NS_IMETHODIMP
00381 nsSAXXMLReader::GetFeature(const nsAString &aName, PRBool *aResult)
00382 {
00383   return NS_ERROR_NOT_IMPLEMENTED;
00384 }
00385 
00386 NS_IMETHODIMP
00387 nsSAXXMLReader::GetLexicalHandler(nsISAXLexicalHandler **aLexicalHandler)
00388 {
00389   NS_IF_ADDREF(*aLexicalHandler = mLexicalHandler);
00390   return NS_OK;
00391 }
00392 
00393 NS_IMETHODIMP
00394 nsSAXXMLReader::SetLexicalHandler(nsISAXLexicalHandler *aLexicalHandler)
00395 {
00396   mLexicalHandler = aLexicalHandler;
00397   return NS_OK;
00398 }
00399 
00400 NS_IMETHODIMP
00401 nsSAXXMLReader::SetProperty(const nsAString &aName, nsISupports* aValue)
00402 {
00403   return NS_ERROR_NOT_IMPLEMENTED;
00404 }
00405 
00406 NS_IMETHODIMP
00407 nsSAXXMLReader::GetProperty(const nsAString &aName, PRBool *aResult)
00408 {
00409   return NS_ERROR_NOT_IMPLEMENTED;
00410 }
00411 
00412 NS_IMETHODIMP
00413 nsSAXXMLReader::ParseFromString(const nsAString &aStr,
00414                                 const char *aContentType)
00415 {
00416   // Don't call this in the middle of an async parse
00417   NS_ENSURE_TRUE(!mIsAsyncParse, NS_ERROR_FAILURE);
00418 
00419   NS_ConvertUTF16toUTF8 data(aStr);
00420 
00421   // The new stream holds a reference to the buffer
00422   nsCOMPtr<nsIInputStream> stream;
00423   nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
00424                                       data.get(), data.Length());
00425   NS_ENSURE_SUCCESS(rv, rv);
00426   return ParseFromStream(stream, "UTF-8", aContentType);
00427 }
00428 
00429 NS_IMETHODIMP
00430 nsSAXXMLReader::ParseFromStream(nsIInputStream *aStream,
00431                                 const char *aCharset,
00432                                 const char *aContentType)
00433 {
00434   // Don't call this in the middle of an async parse
00435   NS_ENSURE_TRUE(!mIsAsyncParse, NS_ERROR_FAILURE);
00436 
00437   NS_ENSURE_ARG(aStream);
00438   NS_ENSURE_ARG(aContentType);
00439 
00440   // Put the nsCOMPtr out here so we hold a ref to the stream as needed
00441   nsresult rv;
00442   nsCOMPtr<nsIInputStream> bufferedStream;
00443   if (!NS_InputStreamIsBuffered(aStream)) {
00444     rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
00445                                    aStream, 4096);
00446     NS_ENSURE_SUCCESS(rv, rv);
00447     aStream = bufferedStream;
00448   }
00449  
00450   rv = EnsureBaseURI();
00451   NS_ENSURE_SUCCESS(rv, rv);
00452 
00453   nsCOMPtr<nsIChannel> parserChannel;
00454   rv = NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mBaseURI,
00455                                 aStream, nsDependentCString(aContentType));
00456   if (!parserChannel || NS_FAILED(rv))
00457     return NS_ERROR_FAILURE;
00458 
00459   if (aCharset)
00460     parserChannel->SetContentCharset(nsDependentCString(aCharset));
00461 
00462   rv = InitParser(nsnull, parserChannel);
00463   NS_ENSURE_SUCCESS(rv, rv);
00464 
00465   rv = mListener->OnStartRequest(parserChannel, nsnull);
00466   if (NS_FAILED(rv))
00467     parserChannel->Cancel(rv);
00468   nsresult status;
00469   parserChannel->GetStatus(&status);
00470   
00471   PRUint32 offset = 0;
00472   while (NS_SUCCEEDED(rv) && NS_SUCCEEDED(status)) {
00473     PRUint32 available;
00474     rv = aStream->Available(&available);
00475     if (rv == NS_BASE_STREAM_CLOSED) {
00476       rv = NS_OK;
00477       available = 0;
00478     }
00479     if (NS_FAILED(rv)) {
00480       parserChannel->Cancel(rv);
00481       break;
00482     }
00483     if (! available)
00484       break; // blocking input stream has none available when done
00485 
00486     rv = mListener->OnDataAvailable(parserChannel, nsnull,
00487                                     aStream, offset, available);
00488     if (NS_SUCCEEDED(rv))
00489       offset += available;
00490     else
00491       parserChannel->Cancel(rv);
00492     parserChannel->GetStatus(&status);
00493   }
00494   rv = mListener->OnStopRequest(parserChannel, nsnull, status);
00495   mListener = nsnull;
00496 
00497   return rv;
00498 }
00499 
00500 NS_IMETHODIMP
00501 nsSAXXMLReader::ParseAsync(nsIRequestObserver *aObserver)
00502 {
00503   mParserObserver = aObserver;
00504   mIsAsyncParse = PR_TRUE;
00505   return NS_OK;
00506 }
00507 
00508 // nsIRequestObserver
00509 
00510 NS_IMETHODIMP
00511 nsSAXXMLReader::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
00512 {
00513   NS_ENSURE_TRUE(mIsAsyncParse, NS_ERROR_FAILURE);
00514   nsresult rv;
00515   rv = EnsureBaseURI();
00516   NS_ENSURE_SUCCESS(rv, rv);
00517   nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
00518   rv = InitParser(mParserObserver, channel);
00519   NS_ENSURE_SUCCESS(rv, rv);
00520   // we don't need or want this anymore
00521   mParserObserver = nsnull;
00522   return mListener->OnStartRequest(aRequest, aContext);
00523 }
00524 
00525 NS_IMETHODIMP
00526 nsSAXXMLReader::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
00527                               nsresult status)
00528 {
00529   NS_ENSURE_TRUE(mIsAsyncParse, NS_ERROR_FAILURE);
00530   NS_ENSURE_STATE(mListener);
00531   nsresult rv = mListener->OnStopRequest(aRequest, aContext, status);
00532   mListener = nsnull;
00533   mIsAsyncParse = PR_FALSE;
00534   return rv;
00535 }
00536 
00537 // nsIStreamListener
00538 
00539 NS_IMETHODIMP
00540 nsSAXXMLReader::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
00541                                 nsIInputStream *aInputStream, PRUint32 offset,
00542                                 PRUint32 count)
00543 {
00544   NS_ENSURE_TRUE(mIsAsyncParse, NS_ERROR_FAILURE);
00545   NS_ENSURE_STATE(mListener);
00546   return mListener->OnDataAvailable(aRequest, aContext, aInputStream, offset,
00547                                     count);
00548 }
00549 
00550 nsresult
00551 nsSAXXMLReader::InitParser(nsIRequestObserver *aObserver, nsIChannel *aChannel)
00552 {
00553   nsresult rv;
00554 
00555   // setup the parser
00556   nsCOMPtr<nsIParser> parser = do_CreateInstance(kParserCID, &rv);
00557   NS_ENSURE_SUCCESS(rv, rv);
00558 
00559   parser->SetContentSink(this);
00560 
00561   PRInt32 charsetSource = kCharsetFromDocTypeDefault;
00562   nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8"));
00563   TryChannelCharset(aChannel, charsetSource, charset);
00564   parser->SetDocumentCharset(charset, charsetSource);
00565 
00566 #ifdef MOZILLA_1_8_BRANCH
00567   rv = parser->Parse(mBaseURI, aObserver, PR_FALSE);
00568 #else
00569   rv = parser->Parse(mBaseURI, aObserver);
00570 #endif
00571   NS_ENSURE_SUCCESS(rv, rv);
00572 
00573   mListener = do_QueryInterface(parser, &rv);
00574 
00575   return rv;
00576 }
00577 
00578 // from nsDocument.cpp
00579 PRBool
00580 nsSAXXMLReader::TryChannelCharset(nsIChannel *aChannel,
00581                                   PRInt32& aCharsetSource,
00582                                   nsACString& aCharset)
00583 {
00584   if (aCharsetSource >= kCharsetFromChannel)
00585     return PR_TRUE;
00586   
00587   if (aChannel) {
00588     nsCAutoString charsetVal;
00589     nsresult rv = aChannel->GetContentCharset(charsetVal);
00590     if (NS_SUCCEEDED(rv)) {
00591       nsCOMPtr<nsICharsetAlias>
00592         calias(do_GetService(NS_CHARSETALIAS_CONTRACTID));
00593       if (calias) {
00594         nsCAutoString preferred;
00595         rv = calias->GetPreferred(charsetVal, preferred);
00596         if (NS_SUCCEEDED(rv)) {
00597           aCharset = preferred;
00598           aCharsetSource = kCharsetFromChannel;
00599           return PR_TRUE;
00600         }
00601       }
00602     }
00603   }
00604 
00605   return PR_FALSE;
00606 }
00607 
00608 nsresult
00609 nsSAXXMLReader::EnsureBaseURI()
00610 {
00611   if (mBaseURI) 
00612     return NS_OK;
00613 
00614   return NS_NewURI(getter_AddRefs(mBaseURI), "about:blank");
00615 }
00616 
00617 nsresult
00618 nsSAXXMLReader::SplitExpatName(const PRUnichar *aExpatName,
00619                                nsString &aURI,
00620                                nsString &aLocalName,
00621                                nsString &aQName)
00622 {
00635   NS_ASSERTION(aExpatName, "null passed to handler");
00636   nsDependentString expatStr(aExpatName);
00637   PRInt32 break1, break2 = kNotFound;
00638   break1 = expatStr.FindChar(PRUnichar(0xFFFF));
00639 
00640   if (break1 == kNotFound) {
00641     aLocalName = expatStr; // no namespace
00642     aURI.Truncate();
00643     aQName = expatStr;
00644   } else {
00645     aURI = StringHead(expatStr, break1);
00646     break2 = expatStr.FindChar(PRUnichar(0xFFFF), break1 + 1);
00647     if (break2 == kNotFound) { // namespace, but no prefix
00648       aLocalName = Substring(expatStr, break1 + 1);
00649       aQName = aLocalName;
00650     } else { // namespace with prefix
00651       aLocalName = Substring(expatStr, break1 + 1, break2 - break1 - 1);
00652       aQName = Substring(expatStr, break2 + 1) +
00653         NS_LITERAL_STRING(":") + aLocalName;
00654     }
00655   }
00656 
00657   return NS_OK;
00658 }