Back to index

lightning-sunbird  0.9+nobinonly
txBufferingHandler.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Jonas Sicking.
00019  * Portions created by the Initial Developer are Copyright (C) 2003
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Jonas Sicking <jonas@sicking.cc>
00024  *   Peter Van der Beken <peterv@propagandism.org>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "txBufferingHandler.h"
00041 
00042 class txOutputTransaction
00043 {
00044 public:
00045     enum txTransactionType {
00046         eAttributeTransaction,
00047         eCharacterTransaction,
00048         eCharacterNoOETransaction,
00049         eCommentTransaction,
00050         eEndDocumentTransaction,
00051         eEndElementTransaction,
00052         ePITransaction,
00053         eStartDocumentTransaction,
00054         eStartElementTransaction
00055     };
00056     txOutputTransaction(txTransactionType aType)
00057         : mType(aType)
00058     {
00059     }
00060     virtual ~txOutputTransaction()
00061     {
00062     }
00063     txTransactionType mType;
00064 };
00065 
00066 class txCharacterTransaction : public txOutputTransaction
00067 {
00068 public:
00069     txCharacterTransaction(txTransactionType aType, PRUint32 aLength)
00070         : txOutputTransaction(aType),
00071           mLength(aLength)
00072     {
00073     }
00074     PRUint32 mLength;
00075 };
00076 
00077 class txCommentTransaction : public txOutputTransaction
00078 {
00079 public:
00080     txCommentTransaction(const nsAString& aValue)
00081         : txOutputTransaction(eCommentTransaction),
00082           mValue(aValue)
00083     {
00084     }
00085     nsString mValue;
00086 };
00087 
00088 class txPITransaction : public txOutputTransaction
00089 {
00090 public:
00091     txPITransaction(const nsAString& aTarget, const nsAString& aData)
00092         : txOutputTransaction(ePITransaction),
00093           mTarget(aTarget),
00094           mData(aData)
00095     {
00096     }
00097     nsString mTarget;
00098     nsString mData;
00099 };
00100 
00101 class txElementTransaction : public txOutputTransaction
00102 {
00103 public:
00104     txElementTransaction(txTransactionType aType, const nsAString& aName,
00105                          PRInt32 aNsID)
00106         : txOutputTransaction(aType),
00107           mName(aName),
00108           mNsID(aNsID)
00109     {
00110     }
00111     nsString mName;
00112     PRInt32 mNsID;
00113 };
00114 
00115 class txAttributeTransaction : public txOutputTransaction
00116 {
00117 public:
00118     txAttributeTransaction(const nsAString& aName, PRInt32 aNsID,
00119                            const nsAString& aValue)
00120         : txOutputTransaction(eAttributeTransaction),
00121           mName(aName),
00122           mNsID(aNsID),
00123           mValue(aValue)
00124     {
00125     }
00126     nsString mName;
00127     PRInt32 mNsID;
00128     nsString mValue;
00129 };
00130 
00131 txBufferingHandler::txBufferingHandler() : mCanAddAttribute(PR_FALSE)
00132 {
00133     mBuffer = new txResultBuffer();
00134 }
00135 
00136 txBufferingHandler::~txBufferingHandler()
00137 {
00138 }
00139 
00140 void
00141 txBufferingHandler::attribute(const nsAString& aName, const PRInt32 aNsID,
00142                               const nsAString& aValue)
00143 {
00144     if (!mBuffer) {
00145         return;
00146     }
00147 
00148     if (!mCanAddAttribute) {
00149         // XXX ErrorReport: Can't add attributes without element
00150         return;
00151     }
00152 
00153     txOutputTransaction* transaction =
00154         new txAttributeTransaction(aName, aNsID, aValue);
00155     if (!transaction) {
00156         NS_ASSERTION(0, "Out of memory!");
00157         return;
00158     }
00159     mBuffer->addTransaction(transaction);
00160 }
00161 
00162 void
00163 txBufferingHandler::characters(const nsAString& aData, PRBool aDOE)
00164 {
00165     if (!mBuffer) {
00166         return;
00167     }
00168 
00169     mCanAddAttribute = PR_FALSE;
00170 
00171     txOutputTransaction::txTransactionType type =
00172          aDOE ? txOutputTransaction::eCharacterNoOETransaction
00173               : txOutputTransaction::eCharacterTransaction;
00174 
00175     txOutputTransaction* transaction = mBuffer->getLastTransaction();
00176     if (transaction && transaction->mType == type) {
00177         mBuffer->mStringValue.Append(aData);
00178         NS_STATIC_CAST(txCharacterTransaction*, transaction)->mLength +=
00179             aData.Length();
00180         return;
00181     }
00182 
00183     transaction = new txCharacterTransaction(type, aData.Length());
00184     if (!transaction) {
00185         NS_ASSERTION(0, "Out of memory!");
00186         return;
00187     }
00188 
00189     mBuffer->mStringValue.Append(aData);
00190     mBuffer->addTransaction(transaction);
00191 }
00192 
00193 void
00194 txBufferingHandler::comment(const nsAString& aData)
00195 {
00196     if (!mBuffer) {
00197         return;
00198     }
00199 
00200     mCanAddAttribute = PR_FALSE;
00201 
00202     txOutputTransaction* transaction = new txCommentTransaction(aData);
00203     if (!transaction) {
00204         NS_ASSERTION(0, "Out of memory!");
00205         return;
00206     }
00207     mBuffer->addTransaction(transaction);
00208 }
00209 
00210 void
00211 txBufferingHandler::endDocument(nsresult aResult)
00212 {
00213     if (!mBuffer) {
00214         return;
00215     }
00216 
00217     txOutputTransaction* transaction =
00218         new txOutputTransaction(txOutputTransaction::eEndDocumentTransaction);
00219     if (!transaction) {
00220         NS_ASSERTION(0, "Out of memory!");
00221         return;
00222     }
00223     mBuffer->addTransaction(transaction);
00224 }
00225 
00226 void
00227 txBufferingHandler::endElement(const nsAString& aName, const PRInt32 aNsID)
00228 {
00229     if (!mBuffer) {
00230         return;
00231     }
00232 
00233     mCanAddAttribute = PR_FALSE;
00234 
00235     txOutputTransaction* transaction =
00236         new txElementTransaction(txOutputTransaction::eEndElementTransaction,
00237                                  aName, aNsID);
00238     if (!transaction) {
00239         NS_ASSERTION(0, "Out of memory!");
00240         return;
00241     }
00242     mBuffer->addTransaction(transaction);
00243 }
00244 
00245 void
00246 txBufferingHandler::processingInstruction(const nsAString& aTarget,
00247                                           const nsAString& aData)
00248 {
00249     if (!mBuffer) {
00250         return;
00251     }
00252 
00253     mCanAddAttribute = PR_FALSE;
00254 
00255     txOutputTransaction* transaction =
00256         new txPITransaction(aTarget, aData);
00257     if (!transaction) {
00258         NS_ASSERTION(0, "Out of memory!");
00259         return;
00260     }
00261     mBuffer->addTransaction(transaction);
00262 }
00263 
00264 void txBufferingHandler::startDocument()
00265 {
00266     if (!mBuffer) {
00267         return;
00268     }
00269 
00270     txOutputTransaction* transaction =
00271         new txOutputTransaction(txOutputTransaction::eStartDocumentTransaction);
00272     if (!transaction) {
00273         NS_ASSERTION(0, "Out of memory!");
00274         return;
00275     }
00276     mBuffer->addTransaction(transaction);
00277 }
00278 
00279 void
00280 txBufferingHandler::startElement(const nsAString& aName, const PRInt32 aNsID)
00281 {
00282     if (!mBuffer) {
00283         return;
00284     }
00285 
00286     mCanAddAttribute = PR_TRUE;
00287 
00288     txOutputTransaction* transaction =
00289         new txElementTransaction(txOutputTransaction::eStartElementTransaction,
00290                                  aName, aNsID);
00291     if (!transaction) {
00292         NS_ASSERTION(0, "Out of memory!");
00293         return;
00294     }
00295     mBuffer->addTransaction(transaction);
00296 }
00297 
00298 PR_STATIC_CALLBACK(PRBool)
00299 deleteTransaction(void* aElement, void *aData)
00300 {
00301     delete NS_STATIC_CAST(txOutputTransaction*, aElement);
00302     return PR_TRUE;
00303 }
00304 
00305 txResultBuffer::~txResultBuffer()
00306 {
00307     mTransactions.EnumerateForwards(deleteTransaction, nsnull);
00308 }
00309 
00310 nsresult
00311 txResultBuffer::addTransaction(txOutputTransaction* aTransaction)
00312 {
00313     if (!mTransactions.AppendElement(aTransaction)) {
00314         return NS_ERROR_OUT_OF_MEMORY;
00315     }
00316     return NS_OK;
00317 }
00318 
00319 struct Holder
00320 {
00321     txAXMLEventHandler** mHandler;
00322     nsAFlatString::const_char_iterator mIter;
00323 };
00324 
00325 PR_STATIC_CALLBACK(PRBool)
00326 flushTransaction(void* aElement, void *aData)
00327 {
00328     Holder* holder = NS_STATIC_CAST(Holder*, aData);
00329     txAXMLEventHandler* handler = *holder->mHandler;
00330     txOutputTransaction* transaction =
00331         NS_STATIC_CAST(txOutputTransaction*, aElement);
00332 
00333     switch (transaction->mType) {
00334         case txOutputTransaction::eAttributeTransaction:
00335         {
00336             txAttributeTransaction* attrTransaction =
00337                 NS_STATIC_CAST(txAttributeTransaction*, aElement);
00338             handler->attribute(attrTransaction->mName,
00339                                attrTransaction->mNsID,
00340                                attrTransaction->mValue);
00341             break;
00342         }
00343         case txOutputTransaction::eCharacterTransaction:
00344         case txOutputTransaction::eCharacterNoOETransaction:
00345         {
00346             txCharacterTransaction* charTransaction =
00347                 NS_STATIC_CAST(txCharacterTransaction*, aElement);
00348             nsAFlatString::const_char_iterator& start =
00349                 NS_STATIC_CAST(Holder*, aData)->mIter;
00350             nsAFlatString::const_char_iterator end =
00351                 start + charTransaction->mLength;
00352             handler->characters(Substring(start, end),
00353                                 transaction->mType ==
00354                                 txOutputTransaction::eCharacterNoOETransaction);
00355             start = end;
00356             break;
00357         }
00358         case txOutputTransaction::eCommentTransaction:
00359         {
00360             txCommentTransaction* commentTransaction =
00361                 NS_STATIC_CAST(txCommentTransaction*, aElement);
00362             handler->comment(commentTransaction->mValue);
00363             break;
00364         }
00365         case txOutputTransaction::eEndElementTransaction:
00366         {
00367             txElementTransaction* elementTransaction =
00368                 NS_STATIC_CAST(txElementTransaction*, aElement);
00369             handler->endElement(elementTransaction->mName,
00370                                 elementTransaction->mNsID);
00371             break;
00372         }
00373         case txOutputTransaction::ePITransaction:
00374         {
00375             txPITransaction* piTransaction =
00376                 NS_STATIC_CAST(txPITransaction*, aElement);
00377             handler->processingInstruction(piTransaction->mTarget,
00378                                            piTransaction->mData);
00379             break;
00380         }
00381         case txOutputTransaction::eStartDocumentTransaction:
00382         {
00383             handler->startDocument();
00384             break;
00385         }
00386         case txOutputTransaction::eStartElementTransaction:
00387         {
00388             txElementTransaction* elementTransaction =
00389                 NS_STATIC_CAST(txElementTransaction*, aElement);
00390             handler->startElement(elementTransaction->mName,
00391                                   elementTransaction->mNsID);
00392             break;
00393         }
00394     }
00395 
00396     return PR_TRUE;
00397 }
00398 
00399 nsresult
00400 txResultBuffer::flushToHandler(txAXMLEventHandler** aHandler)
00401 {
00402     Holder data = { aHandler };
00403     mStringValue.BeginReading(data.mIter);
00404     mTransactions.EnumerateForwards(flushTransaction, &data);
00405     return NS_OK;
00406 }
00407 
00408 txOutputTransaction*
00409 txResultBuffer::getLastTransaction()
00410 {
00411     PRInt32 last = mTransactions.Count() - 1;
00412     if (last < 0) {
00413         return nsnull;
00414     }
00415     return NS_STATIC_CAST(txOutputTransaction*, mTransactions[last]);
00416 }