1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "txBufferingHandler.h"
8 using mozilla::MakeUnique
;
10 class txOutputTransaction
{
12 enum txTransactionType
{
13 eAttributeTransaction
,
14 eAttributeAtomTransaction
,
15 eCharacterTransaction
,
16 eCharacterNoOETransaction
,
18 eEndDocumentTransaction
,
19 eEndElementTransaction
,
21 eStartDocumentTransaction
,
22 eStartElementAtomTransaction
,
23 eStartElementTransaction
25 explicit txOutputTransaction(txTransactionType aType
) : mType(aType
) {
26 MOZ_COUNT_CTOR(txOutputTransaction
);
28 MOZ_COUNTED_DTOR_VIRTUAL(txOutputTransaction
)
29 txTransactionType mType
;
32 class txCharacterTransaction
: public txOutputTransaction
{
34 txCharacterTransaction(txTransactionType aType
, uint32_t aLength
)
35 : txOutputTransaction(aType
), mLength(aLength
) {
36 MOZ_COUNT_CTOR_INHERITED(txCharacterTransaction
, txOutputTransaction
);
38 virtual ~txCharacterTransaction() {
39 MOZ_COUNT_DTOR_INHERITED(txCharacterTransaction
, txOutputTransaction
);
44 class txCommentTransaction
: public txOutputTransaction
{
46 explicit txCommentTransaction(const nsAString
& aValue
)
47 : txOutputTransaction(eCommentTransaction
), mValue(aValue
) {
48 MOZ_COUNT_CTOR_INHERITED(txCommentTransaction
, txOutputTransaction
);
50 virtual ~txCommentTransaction() {
51 MOZ_COUNT_DTOR_INHERITED(txCommentTransaction
, txOutputTransaction
);
56 class txPITransaction
: public txOutputTransaction
{
58 txPITransaction(const nsAString
& aTarget
, const nsAString
& aData
)
59 : txOutputTransaction(ePITransaction
), mTarget(aTarget
), mData(aData
) {
60 MOZ_COUNT_CTOR_INHERITED(txPITransaction
, txOutputTransaction
);
62 virtual ~txPITransaction() {
63 MOZ_COUNT_DTOR_INHERITED(txPITransaction
, txOutputTransaction
);
69 class txStartElementAtomTransaction
: public txOutputTransaction
{
71 txStartElementAtomTransaction(nsAtom
* aPrefix
, nsAtom
* aLocalName
,
72 nsAtom
* aLowercaseLocalName
, int32_t aNsID
)
73 : txOutputTransaction(eStartElementAtomTransaction
),
75 mLocalName(aLocalName
),
76 mLowercaseLocalName(aLowercaseLocalName
),
78 MOZ_COUNT_CTOR_INHERITED(txStartElementAtomTransaction
,
81 virtual ~txStartElementAtomTransaction() {
82 MOZ_COUNT_DTOR_INHERITED(txStartElementAtomTransaction
,
85 RefPtr
<nsAtom
> mPrefix
;
86 RefPtr
<nsAtom
> mLocalName
;
87 RefPtr
<nsAtom
> mLowercaseLocalName
;
91 class txStartElementTransaction
: public txOutputTransaction
{
93 txStartElementTransaction(nsAtom
* aPrefix
, const nsAString
& aLocalName
,
95 : txOutputTransaction(eStartElementTransaction
),
97 mLocalName(aLocalName
),
99 MOZ_COUNT_CTOR_INHERITED(txStartElementTransaction
, txOutputTransaction
);
101 virtual ~txStartElementTransaction() {
102 MOZ_COUNT_DTOR_INHERITED(txStartElementTransaction
, txOutputTransaction
);
104 RefPtr
<nsAtom
> mPrefix
;
109 class txAttributeTransaction
: public txOutputTransaction
{
111 txAttributeTransaction(nsAtom
* aPrefix
, const nsAString
& aLocalName
,
112 int32_t aNsID
, const nsString
& aValue
)
113 : txOutputTransaction(eAttributeTransaction
),
115 mLocalName(aLocalName
),
118 MOZ_COUNT_CTOR_INHERITED(txAttributeTransaction
, txOutputTransaction
);
120 virtual ~txAttributeTransaction() {
121 MOZ_COUNT_DTOR_INHERITED(txAttributeTransaction
, txOutputTransaction
);
123 RefPtr
<nsAtom
> mPrefix
;
129 class txAttributeAtomTransaction
: public txOutputTransaction
{
131 txAttributeAtomTransaction(nsAtom
* aPrefix
, nsAtom
* aLocalName
,
132 nsAtom
* aLowercaseLocalName
, int32_t aNsID
,
133 const nsString
& aValue
)
134 : txOutputTransaction(eAttributeAtomTransaction
),
136 mLocalName(aLocalName
),
137 mLowercaseLocalName(aLowercaseLocalName
),
140 MOZ_COUNT_CTOR_INHERITED(txAttributeAtomTransaction
, txOutputTransaction
);
142 virtual ~txAttributeAtomTransaction() {
143 MOZ_COUNT_DTOR_INHERITED(txAttributeAtomTransaction
, txOutputTransaction
);
145 RefPtr
<nsAtom
> mPrefix
;
146 RefPtr
<nsAtom
> mLocalName
;
147 RefPtr
<nsAtom
> mLowercaseLocalName
;
152 txBufferingHandler::txBufferingHandler() : mCanAddAttribute(false) {
153 MOZ_COUNT_CTOR(txBufferingHandler
);
154 mBuffer
= MakeUnique
<txResultBuffer
>();
157 txBufferingHandler::~txBufferingHandler() {
158 MOZ_COUNT_DTOR(txBufferingHandler
);
161 nsresult
txBufferingHandler::attribute(nsAtom
* aPrefix
, nsAtom
* aLocalName
,
162 nsAtom
* aLowercaseLocalName
,
163 int32_t aNsID
, const nsString
& aValue
) {
164 NS_ENSURE_TRUE(mBuffer
, NS_ERROR_OUT_OF_MEMORY
);
166 if (!mCanAddAttribute
) {
167 // XXX ErrorReport: Can't add attributes without element
171 txOutputTransaction
* transaction
= new txAttributeAtomTransaction(
172 aPrefix
, aLocalName
, aLowercaseLocalName
, aNsID
, aValue
);
173 return mBuffer
->addTransaction(transaction
);
176 nsresult
txBufferingHandler::attribute(nsAtom
* aPrefix
,
177 const nsAString
& aLocalName
,
179 const nsString
& aValue
) {
180 NS_ENSURE_TRUE(mBuffer
, NS_ERROR_OUT_OF_MEMORY
);
182 if (!mCanAddAttribute
) {
183 // XXX ErrorReport: Can't add attributes without element
187 txOutputTransaction
* transaction
=
188 new txAttributeTransaction(aPrefix
, aLocalName
, aNsID
, aValue
);
189 return mBuffer
->addTransaction(transaction
);
192 nsresult
txBufferingHandler::characters(const nsAString
& aData
, bool aDOE
) {
193 NS_ENSURE_TRUE(mBuffer
, NS_ERROR_OUT_OF_MEMORY
);
195 mCanAddAttribute
= false;
197 txOutputTransaction::txTransactionType type
=
198 aDOE
? txOutputTransaction::eCharacterNoOETransaction
199 : txOutputTransaction::eCharacterTransaction
;
201 txOutputTransaction
* transaction
= mBuffer
->getLastTransaction();
202 if (transaction
&& transaction
->mType
== type
) {
203 mBuffer
->mStringValue
.Append(aData
);
204 static_cast<txCharacterTransaction
*>(transaction
)->mLength
+=
209 transaction
= new txCharacterTransaction(type
, aData
.Length());
210 mBuffer
->mStringValue
.Append(aData
);
211 return mBuffer
->addTransaction(transaction
);
214 nsresult
txBufferingHandler::comment(const nsString
& aData
) {
215 NS_ENSURE_TRUE(mBuffer
, NS_ERROR_OUT_OF_MEMORY
);
217 mCanAddAttribute
= false;
219 txOutputTransaction
* transaction
= new txCommentTransaction(aData
);
220 return mBuffer
->addTransaction(transaction
);
223 nsresult
txBufferingHandler::endDocument(nsresult aResult
) {
224 NS_ENSURE_TRUE(mBuffer
, NS_ERROR_OUT_OF_MEMORY
);
226 txOutputTransaction
* transaction
=
227 new txOutputTransaction(txOutputTransaction::eEndDocumentTransaction
);
228 return mBuffer
->addTransaction(transaction
);
231 nsresult
txBufferingHandler::endElement() {
232 NS_ENSURE_TRUE(mBuffer
, NS_ERROR_OUT_OF_MEMORY
);
234 mCanAddAttribute
= false;
236 txOutputTransaction
* transaction
=
237 new txOutputTransaction(txOutputTransaction::eEndElementTransaction
);
238 return mBuffer
->addTransaction(transaction
);
241 nsresult
txBufferingHandler::processingInstruction(const nsString
& aTarget
,
242 const nsString
& aData
) {
243 NS_ENSURE_TRUE(mBuffer
, NS_ERROR_OUT_OF_MEMORY
);
245 mCanAddAttribute
= false;
247 txOutputTransaction
* transaction
= new txPITransaction(aTarget
, aData
);
248 return mBuffer
->addTransaction(transaction
);
251 nsresult
txBufferingHandler::startDocument() {
252 NS_ENSURE_TRUE(mBuffer
, NS_ERROR_OUT_OF_MEMORY
);
254 txOutputTransaction
* transaction
=
255 new txOutputTransaction(txOutputTransaction::eStartDocumentTransaction
);
256 return mBuffer
->addTransaction(transaction
);
259 nsresult
txBufferingHandler::startElement(nsAtom
* aPrefix
, nsAtom
* aLocalName
,
260 nsAtom
* aLowercaseLocalName
,
262 NS_ENSURE_TRUE(mBuffer
, NS_ERROR_OUT_OF_MEMORY
);
264 mCanAddAttribute
= true;
266 txOutputTransaction
* transaction
= new txStartElementAtomTransaction(
267 aPrefix
, aLocalName
, aLowercaseLocalName
, aNsID
);
268 return mBuffer
->addTransaction(transaction
);
271 nsresult
txBufferingHandler::startElement(nsAtom
* aPrefix
,
272 const nsAString
& aLocalName
,
273 const int32_t aNsID
) {
274 NS_ENSURE_TRUE(mBuffer
, NS_ERROR_OUT_OF_MEMORY
);
276 mCanAddAttribute
= true;
278 txOutputTransaction
* transaction
=
279 new txStartElementTransaction(aPrefix
, aLocalName
, aNsID
);
280 return mBuffer
->addTransaction(transaction
);
283 txResultBuffer::txResultBuffer() { MOZ_COUNT_CTOR(txResultBuffer
); }
285 txResultBuffer::~txResultBuffer() {
286 MOZ_COUNT_DTOR(txResultBuffer
);
287 for (uint32_t i
= 0, len
= mTransactions
.Length(); i
< len
; ++i
) {
288 delete mTransactions
[i
];
292 nsresult
txResultBuffer::addTransaction(txOutputTransaction
* aTransaction
) {
293 // XXX(Bug 1631371) Check if this should use a fallible operation as it
294 // pretended earlier, or change the return type to void.
295 mTransactions
.AppendElement(aTransaction
);
299 static nsresult
flushTransaction(txOutputTransaction
* aTransaction
,
300 txAXMLEventHandler
* aHandler
,
301 nsString::const_char_iterator
& aIter
) {
302 switch (aTransaction
->mType
) {
303 case txOutputTransaction::eAttributeAtomTransaction
: {
304 txAttributeAtomTransaction
* transaction
=
305 static_cast<txAttributeAtomTransaction
*>(aTransaction
);
306 return aHandler
->attribute(transaction
->mPrefix
, transaction
->mLocalName
,
307 transaction
->mLowercaseLocalName
,
308 transaction
->mNsID
, transaction
->mValue
);
310 case txOutputTransaction::eAttributeTransaction
: {
311 txAttributeTransaction
* attrTransaction
=
312 static_cast<txAttributeTransaction
*>(aTransaction
);
313 return aHandler
->attribute(
314 attrTransaction
->mPrefix
, attrTransaction
->mLocalName
,
315 attrTransaction
->mNsID
, attrTransaction
->mValue
);
317 case txOutputTransaction::eCharacterTransaction
:
318 case txOutputTransaction::eCharacterNoOETransaction
: {
319 txCharacterTransaction
* charTransaction
=
320 static_cast<txCharacterTransaction
*>(aTransaction
);
321 nsString::const_char_iterator start
= aIter
;
322 nsString::const_char_iterator end
= start
+ charTransaction
->mLength
;
324 return aHandler
->characters(
325 Substring(start
, end
),
326 aTransaction
->mType
==
327 txOutputTransaction::eCharacterNoOETransaction
);
329 case txOutputTransaction::eCommentTransaction
: {
330 txCommentTransaction
* commentTransaction
=
331 static_cast<txCommentTransaction
*>(aTransaction
);
332 return aHandler
->comment(commentTransaction
->mValue
);
334 case txOutputTransaction::eEndElementTransaction
: {
335 return aHandler
->endElement();
337 case txOutputTransaction::ePITransaction
: {
338 txPITransaction
* piTransaction
=
339 static_cast<txPITransaction
*>(aTransaction
);
340 return aHandler
->processingInstruction(piTransaction
->mTarget
,
341 piTransaction
->mData
);
343 case txOutputTransaction::eStartDocumentTransaction
: {
344 return aHandler
->startDocument();
346 case txOutputTransaction::eStartElementAtomTransaction
: {
347 txStartElementAtomTransaction
* transaction
=
348 static_cast<txStartElementAtomTransaction
*>(aTransaction
);
349 return aHandler
->startElement(
350 transaction
->mPrefix
, transaction
->mLocalName
,
351 transaction
->mLowercaseLocalName
, transaction
->mNsID
);
353 case txOutputTransaction::eStartElementTransaction
: {
354 txStartElementTransaction
* transaction
=
355 static_cast<txStartElementTransaction
*>(aTransaction
);
356 return aHandler
->startElement(
357 transaction
->mPrefix
, transaction
->mLocalName
, transaction
->mNsID
);
360 MOZ_ASSERT_UNREACHABLE("Unexpected transaction type");
364 return NS_ERROR_UNEXPECTED
;
367 nsresult
txResultBuffer::flushToHandler(txAXMLEventHandler
* aHandler
) {
368 nsString::const_char_iterator iter
;
369 mStringValue
.BeginReading(iter
);
371 for (uint32_t i
= 0, len
= mTransactions
.Length(); i
< len
; ++i
) {
372 nsresult rv
= flushTransaction(mTransactions
[i
], aHandler
, iter
);
373 NS_ENSURE_SUCCESS(rv
, rv
);
379 txOutputTransaction
* txResultBuffer::getLastTransaction() {
380 int32_t last
= mTransactions
.Length() - 1;
384 return mTransactions
[last
];