|
1 /* |
|
2 * Copyright (c) 2007 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: Parses the XML command file (VPN command file) |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 #include <e32std.h> |
|
21 |
|
22 // XML parser includes |
|
23 #include "XwImpl.h" |
|
24 #include "XppImpl.h" |
|
25 |
|
26 #include "cmdfilexmltags.h" |
|
27 #include "cmdfileparser.h" |
|
28 #include "policyinstaller_constants.h" |
|
29 #include "log_r6.h" |
|
30 |
|
31 |
|
32 CCmdFileParser::CCmdFileParser() |
|
33 { |
|
34 } |
|
35 |
|
36 CCmdFileParser::~CCmdFileParser() |
|
37 { |
|
38 LOG_("-> CCmdFileParser::~CCmdFileParser()"); |
|
39 ReleaseResources(); |
|
40 LOG_("<- CCmdFileParser::~CCmdFileParser()"); |
|
41 } |
|
42 |
|
43 void CCmdFileParser::ParseL(const TDesC8& aInputData) |
|
44 { |
|
45 LOG_("-> CCmdFileParser::ParseL()"); |
|
46 // Release any allocated resources, for a clean parse |
|
47 ReleaseResources(); |
|
48 |
|
49 iParserStack = new (ELeave) CArrayFixFlat<HBufC8*>(3); |
|
50 iParsedValuesArray = new (ELeave) CArrayFixFlat<HBufC8*>(3); |
|
51 |
|
52 // Parse XML and extract the parameters |
|
53 ParseXmlL(aInputData); |
|
54 |
|
55 iParseReady = ETrue; |
|
56 |
|
57 LOG_("<- CCmdFileParser::ParseL()"); |
|
58 } |
|
59 |
|
60 void CCmdFileParser::ReleaseResources() |
|
61 { |
|
62 LOG_("-> CCmdFileParser::ReleaseResources()"); |
|
63 |
|
64 iParseReady = EFalse; |
|
65 |
|
66 delete iFileContents; |
|
67 iFileContents = NULL; |
|
68 |
|
69 delete iPKCS12Pwd; |
|
70 iPKCS12Pwd = NULL; |
|
71 |
|
72 delete iFileName; |
|
73 iFileName = NULL; |
|
74 |
|
75 // Delete parser stack entries before deleting |
|
76 // the stack pointer |
|
77 if (iParserStack) |
|
78 { |
|
79 LOG_(" Deleting items from parser stack"); |
|
80 |
|
81 for (TInt i = iParserStack->Count() - 1; i >= 0; i--) |
|
82 { |
|
83 LOG_1(" Deleting at %d", i); |
|
84 delete iParserStack->At(i); |
|
85 iParserStack->At(i) = NULL; |
|
86 } |
|
87 |
|
88 LOG_(" Reset parser"); |
|
89 iParserStack->Reset(); |
|
90 } |
|
91 |
|
92 delete iParserStack; |
|
93 iParserStack = NULL; |
|
94 |
|
95 // Delete parsed values entries before deleting |
|
96 // the array pointer |
|
97 if (iParsedValuesArray) |
|
98 { |
|
99 LOG_(" Deleting items from parsed values"); |
|
100 for (TInt i = iParsedValuesArray->Count() - 1; i >= 0; i--) |
|
101 { |
|
102 LOG_1(" Deleting at %d", i); |
|
103 delete iParsedValuesArray->At(i); |
|
104 iParsedValuesArray->At(i) = NULL; |
|
105 } |
|
106 |
|
107 LOG_(" Reset parsed values"); |
|
108 iParsedValuesArray->Reset(); |
|
109 } |
|
110 |
|
111 delete iParsedValuesArray; |
|
112 iParsedValuesArray = NULL; |
|
113 |
|
114 LOG_("<- CCmdFileParser::ReleaseResources()"); |
|
115 } |
|
116 |
|
117 void CCmdFileParser::PushNodeL(const TDesC8& aName) |
|
118 { |
|
119 LOG_("-> CCmdFileParser::PushNodeL()"); |
|
120 |
|
121 HBufC8* node = aName.AllocLC(); |
|
122 |
|
123 LOG8_1(" PUSH Node: '%S'", node); |
|
124 |
|
125 iParserStack->AppendL(node); |
|
126 CleanupStack::Pop(node); |
|
127 |
|
128 LOG_("<- CCmdFileParser::PushNodeL()"); |
|
129 } |
|
130 |
|
131 void CCmdFileParser::PopNode() |
|
132 { |
|
133 LOG_("-> CCmdFileParser::PopNode()"); |
|
134 |
|
135 // Just pop, unless we ought to stop |
|
136 TInt lastIdx = iParserStack->Count()-1; |
|
137 if (lastIdx >= 0) |
|
138 { |
|
139 LOG8_1(" POP Node: '%S'", iParserStack->At(lastIdx)); |
|
140 LOG_1(" Removing from parserstack index %d", lastIdx); |
|
141 |
|
142 delete iParserStack->At(lastIdx); |
|
143 iParserStack->Delete(lastIdx); |
|
144 } |
|
145 |
|
146 LOG_("<- CCmdFileParser::PopNode()"); |
|
147 } |
|
148 |
|
149 TBool CCmdFileParser::IsTopmostNode(const TDesC8& aName) const |
|
150 { |
|
151 LOG_("-> CCmdFileParser::IsTopmostNode()"); |
|
152 LOG8_1(" CHECKING: '%S'", &aName); |
|
153 |
|
154 TBool ret(EFalse); |
|
155 if (iParserStack) |
|
156 { |
|
157 TInt lastIdx = iParserStack->Count()-1; |
|
158 TPtrC8 top = *(iParserStack->At(lastIdx)); |
|
159 |
|
160 LOG8_1(" FOUND: '%S'", &top); |
|
161 |
|
162 if (aName.Compare(top) == 0) |
|
163 { |
|
164 ret = ETrue; |
|
165 } |
|
166 } |
|
167 |
|
168 LOG_1("<- CCmdFileParser::IsTopmostNode() val: %d", ret); |
|
169 |
|
170 return ret; |
|
171 } |
|
172 |
|
173 HBufC8* CCmdFileParser::ParseTreeUriL(const TDesC8& aText) const |
|
174 { |
|
175 LOG_("-> CCmdFileParser::ParseTreeUriL()"); |
|
176 LOG8_1(" Input: '%S'", &aText); |
|
177 |
|
178 HBufC8* ret(NULL); |
|
179 TInt uriLen(aText.Length()); |
|
180 TInt itemCount(0); |
|
181 if (iParserStack) |
|
182 { |
|
183 // First, with precise scientifical approach establish |
|
184 // the amount of wide bytes required for storing the URI |
|
185 itemCount = iParserStack->Count(); |
|
186 |
|
187 LOG_1(" Items in stack: %d", itemCount); |
|
188 |
|
189 for (TInt i = 0; i < itemCount; i++) |
|
190 { |
|
191 uriLen += iParserStack->At(i)->Length(); |
|
192 } |
|
193 |
|
194 // The number of "slash" ("/") characters required, |
|
195 // with utmost precision |
|
196 uriLen += itemCount; |
|
197 ret = HBufC8::NewL(uriLen); |
|
198 |
|
199 // And then store the URI to a new string. |
|
200 for (TInt i = 0; i < itemCount; i++) |
|
201 { |
|
202 ret->Des().Append(*(iParserStack->At(i))); |
|
203 ret->Des().Append(KCmdUriSeparator); |
|
204 } |
|
205 ret->Des().Append(aText); |
|
206 } |
|
207 |
|
208 LOG_("<- CCmdFileParser::ParseTreeUriL()"); |
|
209 return ret; |
|
210 } |
|
211 |
|
212 TBool CCmdFileParser::IsValidText(const TDesC8& aText) const |
|
213 { |
|
214 LOG_("-> CCmdFileParser::IsValidText()"); |
|
215 TBool ret(ETrue); |
|
216 |
|
217 // We don't support "CR/LF" characters in the |
|
218 // beginning of valid value names |
|
219 TInt idx = aText.Find(KCmdCr); |
|
220 if (idx >= 0 && idx < 2) |
|
221 { |
|
222 ret = EFalse; |
|
223 } |
|
224 else |
|
225 { |
|
226 idx = aText.Find(KCmdLf); |
|
227 if (idx >= 0 && idx < 2) |
|
228 { |
|
229 ret = EFalse; |
|
230 } |
|
231 } |
|
232 |
|
233 LOG_1("<- CCmdFileParser::IsValidText() ret: %d", ret); |
|
234 return ret; |
|
235 } |
|
236 |
|
237 void CCmdFileParser::ParseXmlL(const TDesC8& aInputData) |
|
238 { |
|
239 LOG_("-> CCmdFileParser::ParseXmlL()"); |
|
240 |
|
241 LOG_(" Instantiate parser array"); |
|
242 |
|
243 CDesC8ArrayFlat* parserValueArray = new (ELeave) CDesC8ArrayFlat(10); |
|
244 CleanupStack::PushL(parserValueArray); |
|
245 |
|
246 LOG_(" Instantiate XML parser"); |
|
247 CXmlPullParser* parser = CXmlPullParser::NewLC(*parserValueArray); |
|
248 |
|
249 TPtrC8 name; |
|
250 TPtrC8 attribute; |
|
251 |
|
252 LOG_(" Set input"); |
|
253 parser->SetInput(aInputData); |
|
254 |
|
255 LOG_(" Get length"); |
|
256 TInt len = parser->Length(); |
|
257 LOG_1(" XML length: %d bytes", len); |
|
258 |
|
259 // Check the first element |
|
260 LOG_(" Get the next (first) element"); |
|
261 parser->NextL(); |
|
262 |
|
263 if (parser->State() != CXmlPullParser::EStateStartTag) |
|
264 { |
|
265 LOG_(" LEAVE: XML data is not in VPN's required format!"); |
|
266 User::Leave(KErrCorrupt); |
|
267 } |
|
268 |
|
269 LOG_(" Starting the main parser loop"); |
|
270 TPtrC8 text; |
|
271 |
|
272 // Main loop: |
|
273 // - While XML nodes still exist do: |
|
274 // - If "opening" node (<start>), push to the stack |
|
275 // - If "closing" node (</start>), pop from the stack |
|
276 // - If a text node, make sure it's valid and then store |
|
277 // the URI so the value can be fetched later on. |
|
278 while (parser->State() != CXmlPullParser::EStateEndDocument) |
|
279 { |
|
280 parser->Name(name); |
|
281 |
|
282 if (parser->State() == CXmlPullParser::EStateStartTag) |
|
283 { |
|
284 LOG8_1(" START: '%S'", &name); |
|
285 PushNodeL(name); |
|
286 } |
|
287 else if (parser->State() == CXmlPullParser::EStateEndTag) |
|
288 { |
|
289 LOG8_1(" END: '%S'", &name); |
|
290 if (IsTopmostNode(name)) |
|
291 { |
|
292 PopNode(); |
|
293 } |
|
294 else |
|
295 { |
|
296 // Item on top of the stack wasn't what was |
|
297 // expected. Indicates corrupted XML. |
|
298 LOG_(" ERROR: Node end tag mismatch with expected"); |
|
299 User::Leave(KErrCorrupt); |
|
300 } |
|
301 } |
|
302 else if (parser->State() == CXmlPullParser::EStateText) |
|
303 { |
|
304 parser->TextL(text); |
|
305 if (IsValidText(text)) |
|
306 { |
|
307 LOG8_1(" Text: '%S'", &text); |
|
308 |
|
309 HBufC8* uri = ParseTreeUriL(text); |
|
310 |
|
311 LOG8_1(" URI: '%S'", uri); |
|
312 |
|
313 CleanupStack::PushL(uri); |
|
314 |
|
315 iParsedValuesArray->AppendL(uri); |
|
316 |
|
317 CleanupStack::Pop(uri); |
|
318 } |
|
319 } |
|
320 |
|
321 parser->NextL(); |
|
322 } |
|
323 |
|
324 LOG_(" Popping"); |
|
325 |
|
326 CleanupStack::PopAndDestroy(2, parserValueArray); |
|
327 |
|
328 LOG_("<- CCmdFileParser::ParseXmlL()"); |
|
329 } |
|
330 |
|
331 |
|
332 HBufC* CCmdFileParser::GetParsedValueStrL(const TDesC8& aUri) |
|
333 { |
|
334 LOG_("-> CCmdFileParser::GetParsedValueStrL()"); |
|
335 |
|
336 HBufC* ret(NULL); |
|
337 |
|
338 // Get the "leaf" value (i.e. attribute's value) |
|
339 // and alloc a new string for it |
|
340 TPtrC8 ptr = FindUri(aUri); |
|
341 if (ptr.Length() > 0) |
|
342 { |
|
343 LOG_(" Ptr length > 0"); |
|
344 LOG8_1(" Ptr: '%S'", &ptr); |
|
345 ret = HBufC::NewL(ptr.Length()); |
|
346 ret->Des().Copy(ptr); |
|
347 } |
|
348 else |
|
349 { |
|
350 LOG_(" Ptr length < 1"); |
|
351 } |
|
352 |
|
353 LOG_("<- CCmdFileParser::GetParsedValueStrL()"); |
|
354 |
|
355 return ret; |
|
356 } |
|
357 |
|
358 void CCmdFileParser::GetParsedValueIntL(const TDesC8& aUri, TInt& aVal) |
|
359 { |
|
360 LOG_("-> CCmdFileParser::GetParsedValueIntL()"); |
|
361 |
|
362 // Get the attribute's value as string... |
|
363 HBufC* str = GetParsedValueStrL(aUri); |
|
364 |
|
365 if (str) |
|
366 { |
|
367 LOG_(" Valid string"); |
|
368 CleanupStack::PushL(str); |
|
369 |
|
370 // ... and convert it to an integer |
|
371 LOG_(" Converting string to int"); |
|
372 TLex lexer(*str); |
|
373 TInt status = lexer.Val(aVal); |
|
374 |
|
375 if (status != KErrNone) |
|
376 { |
|
377 LOG_1("<- CCmdFileParser::GetParsedValueIntL() LEAVE: %d", status); |
|
378 User::Leave(status); |
|
379 } |
|
380 |
|
381 CleanupStack::PopAndDestroy(str); |
|
382 } |
|
383 else |
|
384 { |
|
385 aVal = KErrNotFound; |
|
386 } |
|
387 LOG_("<- CCmdFileParser::GetParsedValueIntL()"); |
|
388 } |
|
389 |
|
390 void CCmdFileParser::GetParsedValueBoolL(const TDesC8& aUri, TBool& aVal) |
|
391 { |
|
392 LOG_("-> CCmdFileParser::GetParsedValueBoolL()"); |
|
393 |
|
394 // Get the attribute's value as string... |
|
395 HBufC* str = GetParsedValueStrL(aUri); |
|
396 |
|
397 if (str) |
|
398 { |
|
399 CleanupStack::PushL(str); |
|
400 |
|
401 // ... and see whether it matches "true" |
|
402 // Note that this comparison is extremely case-sensitive |
|
403 if (str->Compare(KTrue) == 0) |
|
404 { |
|
405 aVal = ETrue; |
|
406 } |
|
407 else |
|
408 { |
|
409 aVal = EFalse; |
|
410 } |
|
411 |
|
412 CleanupStack::PopAndDestroy(str); |
|
413 } |
|
414 else |
|
415 { |
|
416 aVal = EFalse; |
|
417 } |
|
418 |
|
419 LOG_("<- CCmdFileParser::GetParsedValueBoolL()"); |
|
420 } |
|
421 |
|
422 /** |
|
423 * Extracts the "leaf value" ie. attribute's value instance |
|
424 * from an uri. |
|
425 * E.g. returns "BEEFFACED" if the full URI was |
|
426 * root/node1/node2/attribute1/BEEFFACED |
|
427 * (Or in XML representation, |
|
428 * <node1> |
|
429 * <node2> |
|
430 * <attribute1>BEEFFACED</attribute1> |
|
431 * </node2> |
|
432 * </node1>) |
|
433 * |
|
434 */ |
|
435 TPtrC8 CCmdFileParser::FindUri(const TDesC8& aUri) const |
|
436 { |
|
437 LOG_("-> CCmdFileParser::FindUri()"); |
|
438 LOG8_1(" Searching URI '%S'", &aUri); |
|
439 |
|
440 TPtrC8 ret(KNullDesC8); |
|
441 |
|
442 if (iParsedValuesArray) |
|
443 { |
|
444 TInt count = iParsedValuesArray->Count(); |
|
445 for (TInt i = 0; i < count; i++) |
|
446 { |
|
447 TPtrC8 fulluri = *(iParsedValuesArray->At(i)); |
|
448 |
|
449 // Check if we find the requested URI from the |
|
450 // very beginning of the parsed value's URI |
|
451 if (fulluri.Find(aUri) == 0) |
|
452 { |
|
453 // Extract the "remaining" string -- the value (assuming correct syntax) |
|
454 ret.Set(fulluri.Right(fulluri.Length() - aUri.Length())); |
|
455 } |
|
456 } |
|
457 } |
|
458 |
|
459 LOG_("<- CCmdFileParser::FindUri()"); |
|
460 |
|
461 return ret; |
|
462 } |
|
463 |
|
464 |