|
1 /* |
|
2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: CNcdParserImpl implementation |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <xml/parser.h> |
|
20 #include <xml/documentparameters.h> |
|
21 #include <xml/taginfo.h> |
|
22 #include <xml/attribute.h> |
|
23 |
|
24 #include <s32file.h> |
|
25 |
|
26 #include "ncdparserimpl.h" |
|
27 #include "ncdparserobserverbundleimpl.h" |
|
28 #include "ncdtoplevelparser.h" |
|
29 #include "ncdprotocolutils.h" |
|
30 #include "catalogsdebug.h" |
|
31 #include "ncdprotocoldefaultobserver.h" |
|
32 |
|
33 |
|
34 // Input buffer grow size for CBufSeg when appending new xml data in async mode |
|
35 const TInt KInputBufferGrowSize( 4096 ); |
|
36 |
|
37 // Size of the buffer for the data to be processed in one async step. |
|
38 // This is an important figure as it determines the time used in the parser |
|
39 // in each step. Too big -> too unresponsive a system, too small --> too slow |
|
40 // a parsing operation. |
|
41 const TInt KFeedBufferSize( 1024 ); |
|
42 |
|
43 CNcdParserImpl* CNcdParserImpl::NewL( |
|
44 MNcdProtocolDefaultObserver* aDefaultObserver ) |
|
45 { |
|
46 CNcdParserImpl* self = new(ELeave) CNcdParserImpl( aDefaultObserver ); |
|
47 CleanupStack::PushL( self ); |
|
48 self->ConstructL(); |
|
49 CleanupStack::Pop( self ); |
|
50 return self; |
|
51 } |
|
52 |
|
53 |
|
54 CNcdParserImpl::CNcdParserImpl( |
|
55 MNcdProtocolDefaultObserver* aDefaultObserver ) |
|
56 : CActive( EPriorityStandard ), |
|
57 iDefaultObserver( aDefaultObserver ) |
|
58 { |
|
59 CActiveScheduler::Add( this ); |
|
60 } |
|
61 |
|
62 CNcdParserImpl::~CNcdParserImpl() |
|
63 { |
|
64 DLTRACEIN(("")); |
|
65 CancelParsing(); |
|
66 |
|
67 delete iXmlParser; |
|
68 |
|
69 DLINFO(("")); |
|
70 delete iSubParser; |
|
71 |
|
72 DLINFO(("")); |
|
73 delete iInputBuffer; |
|
74 DLINFO(("")); |
|
75 delete iFeedBuffer; |
|
76 DLINFO(("")); |
|
77 delete iObservers; |
|
78 DLINFO(("")); |
|
79 delete iDefaultObserver; |
|
80 DLTRACEOUT(("")); |
|
81 } |
|
82 |
|
83 void CNcdParserImpl::ConstructL() |
|
84 { |
|
85 iObservers = CNcdParserObserverBundleImpl::NewL( iDefaultObserver ); |
|
86 } |
|
87 |
|
88 |
|
89 |
|
90 MNcdParserObserverBundle& CNcdParserImpl::Observers() const |
|
91 { |
|
92 return *iObservers; |
|
93 } |
|
94 |
|
95 MNcdProtocolDefaultObserver& CNcdParserImpl::DefaultObserver() const |
|
96 { |
|
97 return *iDefaultObserver; |
|
98 } |
|
99 |
|
100 |
|
101 void CNcdParserImpl::BeginSyncL() |
|
102 { |
|
103 DLTRACEIN(("")); |
|
104 BeginSyncL( NULL ); |
|
105 } |
|
106 |
|
107 |
|
108 void CNcdParserImpl::BeginSyncL( CNcdSubParser* aSubParser ) |
|
109 { |
|
110 DLTRACEIN(("")); |
|
111 iSynchronous = ETrue; |
|
112 BeginL( aSubParser ); |
|
113 } |
|
114 |
|
115 |
|
116 void CNcdParserImpl::BeginAsyncL() |
|
117 { |
|
118 DLTRACEIN(("")); |
|
119 BeginAsyncL( NULL ); |
|
120 } |
|
121 |
|
122 |
|
123 void CNcdParserImpl::BeginAsyncL( CNcdSubParser* aSubParser ) |
|
124 { |
|
125 DLTRACEIN(("")); |
|
126 iSynchronous = EFalse; |
|
127 iPleaseFinish = EFalse; |
|
128 CleanupStack::PushL( aSubParser ); |
|
129 delete iFeedBuffer; |
|
130 iFeedBuffer = 0; |
|
131 iFeedBuffer = HBufC8::NewL( KFeedBufferSize ); |
|
132 CleanupStack::Pop( aSubParser ); |
|
133 |
|
134 BeginL( aSubParser ); |
|
135 } |
|
136 |
|
137 |
|
138 void CNcdParserImpl::BeginL( CNcdSubParser* aSubParser ) |
|
139 { |
|
140 DLTRACEIN(("begin")); |
|
141 |
|
142 DASSERT( iObservers->ParserObserver() ); |
|
143 |
|
144 iCancelled = EFalse; |
|
145 |
|
146 delete iSubParser; |
|
147 iSubParser = 0; |
|
148 |
|
149 if ( aSubParser ) |
|
150 { |
|
151 DLTRACE(("Using given subparser")); |
|
152 iSubParser = aSubParser; |
|
153 } |
|
154 else |
|
155 { |
|
156 DLTRACE(("Using toplevel parser")); |
|
157 iSubParser = CNcdTopLevelParser::NewL( |
|
158 *iObservers, *this, 0 /*initial depth=0*/ ); |
|
159 } |
|
160 |
|
161 delete iInputBuffer; |
|
162 iInputBuffer = 0; |
|
163 iInputBuffer = CBufSeg::NewL( KInputBufferGrowSize ); |
|
164 |
|
165 delete iXmlParser; |
|
166 iXmlParser = 0; |
|
167 |
|
168 _LIT8( KXmlType, "text/xml" ); |
|
169 iXmlParser = Xml::CParser::NewL( KXmlType, *iSubParser ); |
|
170 iXmlParser->ParseBeginL(); |
|
171 } |
|
172 |
|
173 void CNcdParserImpl::EndL() |
|
174 { |
|
175 DLTRACEIN(("data left=%d",iInputBuffer->Size())); |
|
176 |
|
177 if( iSynchronous || ( !IsActive() && iInputBuffer->Size() == 0 ) ) |
|
178 { |
|
179 DLINFO(("sync end")); |
|
180 // After ParseEndL() OnError() call may come if the end of the data |
|
181 // is screwed. |
|
182 iXmlParser->ParseEndL(); |
|
183 |
|
184 // Cancel callback removed according to users' wishes. |
|
185 if ( !iCancelled ) |
|
186 iObservers->ParserObserver()->ParseCompleteL( KErrNone ); |
|
187 } |
|
188 else |
|
189 { |
|
190 DLINFO(("please finish")); |
|
191 iPleaseFinish = ETrue; |
|
192 } |
|
193 DLTRACEOUT(("")); |
|
194 } |
|
195 |
|
196 void CNcdParserImpl::SetOriginL( const TDesC& aOrigin ) |
|
197 { |
|
198 iObservers->SetSessionOriginL( aOrigin ); |
|
199 } |
|
200 |
|
201 void CNcdParserImpl::ParseL( const TDesC8& aData ) |
|
202 { |
|
203 DLTRACEIN(("8-bit parse, length=%d",aData.Length())); |
|
204 DLINFO(("data=%S",&aData)); |
|
205 |
|
206 if( iSynchronous ) |
|
207 { |
|
208 iXmlParser->ParseL( aData ); |
|
209 } |
|
210 else |
|
211 { |
|
212 DLINFO(("inserting, buffer size=%d",iInputBuffer->Size())); |
|
213 // Compress to free some memory if possible. |
|
214 iInputBuffer->Compress(); |
|
215 iInputBuffer->InsertL( iInputBuffer->Size(), aData ); |
|
216 if( ! IsActive() ) |
|
217 { |
|
218 DLINFO(("activating")); |
|
219 iStatus = KRequestPending; |
|
220 SetActive(); |
|
221 TRequestStatus* status = &iStatus; |
|
222 User::RequestComplete( status, KErrNone ); |
|
223 } |
|
224 } |
|
225 } |
|
226 |
|
227 void CNcdParserImpl::ParseL( const TDesC16& aData ) |
|
228 { |
|
229 DLTRACEIN(("16-bit parse, length=%d",aData.Length())); |
|
230 HBufC8* utf8 = NcdProtocolUtils::ConvertUnicodeToUtf8L( aData ); |
|
231 CleanupStack::PushL( utf8 ); |
|
232 ParseL( *utf8 ); |
|
233 CleanupStack::PopAndDestroy( utf8 ); |
|
234 } |
|
235 |
|
236 |
|
237 void CNcdParserImpl::SubParserFinishedL( const TDesC8& /*aTag*/, TInt /*aErrorCode*/ ) |
|
238 { |
|
239 DLTRACE(("")); |
|
240 } |
|
241 |
|
242 |
|
243 void CNcdParserImpl::CancelParsing() |
|
244 { |
|
245 DLTRACE(("active=%d", IsActive() )); |
|
246 if( !IsActive() ) |
|
247 { |
|
248 iCancelled = ETrue; |
|
249 } |
|
250 |
|
251 // Prevent another Cancel-call while handling the first one |
|
252 if ( !iCancelled ) |
|
253 { |
|
254 Cancel(); |
|
255 } |
|
256 } |
|
257 |
|
258 void CNcdParserImpl::DoCancel() |
|
259 { |
|
260 DLTRACE(("iCancelled=%d", iCancelled )); |
|
261 |
|
262 // iCancelled is never ETrue when coming here unless someone |
|
263 // errorneously calls CNcdParserImpl::Cancel() from outside this class |
|
264 iCancelled = ETrue; |
|
265 TRAP_IGNORE( |
|
266 { |
|
267 // this usually causes a parse error callback to the observer |
|
268 iXmlParser->ParseEndL(); |
|
269 } ); |
|
270 } |
|
271 |
|
272 TInt CNcdParserImpl::RunError( TInt aError ) |
|
273 { |
|
274 DLERROR(("Fatal parser error %d",aError)); |
|
275 iObservers->ParserObserver()->ParseError( aError ); |
|
276 return KErrNone; |
|
277 } |
|
278 |
|
279 void CNcdParserImpl::RunL() |
|
280 { |
|
281 TRequestStatus* status = &iStatus; |
|
282 DLTRACEIN(("data left=%d status=%d",iInputBuffer->Size(),status->Int())); |
|
283 |
|
284 if( iCancelled ) |
|
285 { |
|
286 DLINFO(("user cancelled!")); |
|
287 return; |
|
288 } |
|
289 |
|
290 // @ Is it even possible to get != KErrNone here? |
|
291 if( status->Int() != KErrNone ) |
|
292 { |
|
293 DLERROR(("RunL() error, canceling!")); |
|
294 CancelParsing(); |
|
295 return; |
|
296 } |
|
297 |
|
298 if( iInputBuffer->Size() == 0 ) |
|
299 { |
|
300 // All done. |
|
301 DLINFO(("all done")); |
|
302 if( iPleaseFinish ) |
|
303 { |
|
304 EndL(); |
|
305 } |
|
306 return; |
|
307 } |
|
308 |
|
309 TPtr8 buf = iFeedBuffer->Des(); |
|
310 TInt length = buf.MaxSize(); |
|
311 if( iInputBuffer->Size() < length ) |
|
312 { |
|
313 length = iInputBuffer->Size(); |
|
314 } |
|
315 iInputBuffer->Read( 0, buf, length ); |
|
316 iInputBuffer->Delete( 0, buf.Length() ); |
|
317 iXmlParser->ParseL( buf ); |
|
318 |
|
319 // Next step |
|
320 |
|
321 // Check again if the parser is cancelled. It is possible since callbacks occur |
|
322 // as consequence of calling ParseL. |
|
323 if ( iCancelled ) |
|
324 { |
|
325 return; |
|
326 } |
|
327 |
|
328 iStatus = KRequestPending; |
|
329 SetActive(); |
|
330 User::RequestComplete( status, KErrNone ); |
|
331 |
|
332 } |
|
333 |
|
334 |
|
335 |