- fixed potential xml parsing bug in 6802
[public/netxms.git] / src / libnxlp / parser.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Log Parsing Library
2dd24569 4** Copyright (C) 2003-2012 Victor Kirhenshtein
5039dede
AK
5**
6** This program is free software; you can redistribute it and/or modify
65d2c384
VK
7** it under the terms of the GNU Lesser General Public License as published by
8** the Free Software Foundation; either version 3 of the License, or
5039dede
AK
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
65d2c384 16** You should have received a copy of the GNU Lesser General Public License
5039dede
AK
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: parser.cpp
21**
22**/
23
24#include "libnxlp.h"
5039dede 25#include <expat.h>
5039dede
AK
26
27
28//
29// Context state texts
30//
31
6646dca4 32static const TCHAR *s_states[] = { _T("MANUAL"), _T("AUTO"), _T("INACTIVE") };
5039dede
AK
33
34
35//
36// XML parser state for creating LogParser object from XML
37//
38
39#define XML_STATE_INIT -1
40#define XML_STATE_END -2
41#define XML_STATE_ERROR -255
42#define XML_STATE_PARSER 0
43#define XML_STATE_RULES 1
44#define XML_STATE_RULE 2
45#define XML_STATE_MATCH 3
46#define XML_STATE_EVENT 4
47#define XML_STATE_FILE 5
48#define XML_STATE_ID 6
49#define XML_STATE_LEVEL 7
50#define XML_STATE_SOURCE 8
51#define XML_STATE_CONTEXT 9
52#define XML_STATE_MACROS 10
53#define XML_STATE_MACRO 11
54#define XML_STATE_DESCRIPTION 12
55
56
565a8f28 57struct XML_PARSER_STATE
5039dede
AK
58{
59 LogParser *parser;
60 int state;
61 String regexp;
62 String event;
721fc691 63 String file;
565a8f28
AK
64 StringList files;
65 ObjectArray<int> encodings;
5039dede
AK
66 String id;
67 String level;
68 String source;
69 String context;
70 String description;
71 int contextAction;
72 String ruleContext;
73 int numEventParams;
74 String errorText;
75 String macroName;
76 String macro;
6d738067
VK
77 bool invertedRule;
78 bool breakFlag;
565a8f28
AK
79 XML_PARSER_STATE(): encodings(1, 1, true) {}
80};
5039dede
AK
81
82
83//
84// Parser default constructor
85//
86
87LogParser::LogParser()
88{
89 m_numRules = 0;
90 m_rules = NULL;
91 m_cb = NULL;
92 m_userArg = NULL;
e464b7dc 93 m_name = NULL;
5039dede 94 m_fileName = NULL;
6646dca4 95 m_fileEncoding = LP_FCP_ACP;
5039dede
AK
96 m_eventNameList = NULL;
97 m_eventResolver = NULL;
98 m_thread = INVALID_THREAD_HANDLE;
99 m_recordsProcessed = 0;
100 m_recordsMatched = 0;
101 m_processAllRules = FALSE;
102 m_traceLevel = 0;
103 m_traceCallback = NULL;
e464b7dc 104 _tcscpy(m_status, LPS_INIT);
5039dede
AK
105}
106
107
108//
109// Destructor
110//
111
112LogParser::~LogParser()
113{
114 int i;
115
116 for(i = 0; i < m_numRules; i++)
117 delete m_rules[i];
118 safe_free(m_rules);
e464b7dc 119 safe_free(m_name);
5039dede
AK
120 safe_free(m_fileName);
121}
122
123
124//
8a5ba964 125// Trace
5039dede
AK
126//
127
6646dca4 128void LogParser::trace(int level, const TCHAR *format, ...)
5039dede
AK
129{
130 va_list args;
131
132 if ((m_traceCallback == NULL) || (level > m_traceLevel))
133 return;
134
135 va_start(args, format);
136 m_traceCallback(format, args);
137 va_end(args);
138}
139
140
141//
142// Add rule
143//
144
6d738067 145bool LogParser::addRule(LogParserRule *rule)
5039dede 146{
6d738067 147 bool isOK;
5039dede 148
6d738067 149 isOK = rule->isValid();
5039dede
AK
150 if (isOK)
151 {
152 m_rules = (LogParserRule **)realloc(m_rules, sizeof(LogParserRule *) * (m_numRules + 1));
153 m_rules[m_numRules++] = rule;
154 }
155 else
156 {
157 delete rule;
158 }
159 return isOK;
160}
161
6646dca4 162bool LogParser::addRule(const TCHAR *regexp, DWORD eventCode, const TCHAR *eventName, int numParams)
5039dede 163{
2dd24569 164 return addRule(new LogParserRule(this, regexp, eventCode, eventName, numParams));
5039dede
AK
165}
166
167
168//
169// Check context
170//
171
6646dca4 172const TCHAR *LogParser::checkContext(LogParserRule *rule)
5039dede 173{
6646dca4 174 const TCHAR *state;
5039dede 175
6d738067 176 if (rule->getContext() == NULL)
32ec6391 177 {
6d738067
VK
178 trace(5, _T(" rule has no context"));
179 return s_states[CONTEXT_SET_MANUAL];
32ec6391 180 }
5039dede 181
fb986055 182 state = m_contexts.get(rule->getContext());
5039dede 183 if (state == NULL)
32ec6391 184 {
6d738067 185 trace(5, _T(" context '%s' inactive, rule should be skipped"), rule->getContext());
5039dede 186 return NULL; // Context inactive, don't use this rule
32ec6391 187 }
5039dede 188
6d738067 189 if (!_tcscmp(state, s_states[CONTEXT_CLEAR]))
32ec6391 190 {
6d738067 191 trace(5, _T(" context '%s' inactive, rule should be skipped"), rule->getContext());
32ec6391
VK
192 return NULL;
193 }
194 else
195 {
6d738067 196 trace(5, _T(" context '%s' active (mode=%s)"), rule->getContext(), state);
32ec6391
VK
197 return state;
198 }
5039dede
AK
199}
200
201
202//
6d738067 203// Match log record
5039dede
AK
204//
205
6646dca4
VK
206bool LogParser::matchLogRecord(bool hasAttributes, const TCHAR *source, DWORD eventId,
207 DWORD level, const TCHAR *line, DWORD objectId)
5039dede
AK
208{
209 int i;
6646dca4 210 const TCHAR *state;
6d738067
VK
211 bool matched = false;
212
213 if (hasAttributes)
214 trace(2, _T("Match event: source=\"%s\" id=%u level=%d text=\"%s\""), source, eventId, level, line);
215 else
216 trace(2, _T("Match line: \"%s\""), line);
5039dede 217
5039dede
AK
218 m_recordsProcessed++;
219 for(i = 0; i < m_numRules; i++)
220 {
6d738067 221 trace(4, _T("checking rule %d \"%s\""), i + 1, m_rules[i]->getDescription());
7c09239b 222 if ((state = checkContext(m_rules[i])) != NULL)
5039dede 223 {
7c09239b
VK
224 bool ruleMatched = hasAttributes ?
225 m_rules[i]->matchEx(source, eventId, level, line, m_cb, objectId, m_userArg) :
226 m_rules[i]->match(line, m_cb, objectId, m_userArg);
227 if (ruleMatched)
5039dede 228 {
7c09239b
VK
229 trace(1, _T("rule %d \"%s\" matched"), i + 1, m_rules[i]->getDescription());
230 if (!matched)
231 m_recordsMatched++;
232
233 // Update context
234 if (m_rules[i]->getContextToChange() != NULL)
235 {
fb986055 236 m_contexts.set(m_rules[i]->getContextToChange(), s_states[m_rules[i]->getContextAction()]);
7c09239b
VK
237 trace(2, _T("rule %d \"%s\": context %s set to %s"), i + 1, m_rules[i]->getDescription(), m_rules[i]->getContextToChange(), s_states[m_rules[i]->getContextAction()]);
238 }
239
240 // Set context of this rule to inactive if rule context mode is "automatic reset"
241 if (!_tcscmp(state, s_states[CONTEXT_SET_AUTOMATIC]))
242 {
fb986055 243 m_contexts.set(m_rules[i]->getContext(), s_states[CONTEXT_CLEAR]);
7c09239b
VK
244 trace(2, _T("rule %d \"%s\": context %s cleared because it was set to automatic reset mode"),
245 i + 1, m_rules[i]->getDescription(), m_rules[i]->getContext());
246 }
247 matched = true;
248 if (!m_processAllRules || m_rules[i]->getBreakFlag())
249 break;
5039dede 250 }
5039dede
AK
251 }
252 }
253 if (i < m_numRules)
6d738067
VK
254 trace(2, _T("processing stopped at rule %d \"%s\"; result = %s"), i + 1,
255 m_rules[i]->getDescription(), matched ? _T("true") : _T("false"));
5039dede 256 else
6d738067 257 trace(2, _T("Processing stopped at end of rules list; result = %s"), matched ? _T("true") : _T("false"));
5039dede
AK
258 return matched;
259}
260
261
6d738067
VK
262//
263// Match simple log line
264//
265
6646dca4 266bool LogParser::matchLine(const TCHAR *line, DWORD objectId)
6d738067
VK
267{
268 return matchLogRecord(false, NULL, 0, 0, line, objectId);
269}
270
271
272//
273// Match log event (text with additional attributes - source, severity, event id)
274//
275
6646dca4 276bool LogParser::matchEvent(const TCHAR *source, DWORD eventId, DWORD level, const TCHAR *line, DWORD objectId)
6d738067
VK
277{
278 return matchLogRecord(true, source, eventId, level, line, objectId);
279}
280
281
5039dede
AK
282//
283// Set associated file name
284//
285
6646dca4 286void LogParser::setFileName(const TCHAR *name)
5039dede
AK
287{
288 safe_free(m_fileName);
289 m_fileName = (name != NULL) ? _tcsdup(name) : NULL;
e464b7dc
VK
290 if (m_name == NULL)
291 m_name = _tcsdup(name); // Set parser name to file name
292}
293
294
295//
296// Set parser name
297//
298
6646dca4 299void LogParser::setName(const TCHAR *name)
e464b7dc
VK
300{
301 safe_free(m_name);
302 m_name = _tcsdup((name != NULL) ? name : CHECK_NULL(m_fileName));
5039dede
AK
303}
304
305
306//
307// Add macro
308//
309
6646dca4 310void LogParser::addMacro(const TCHAR *name, const TCHAR *value)
5039dede 311{
fb986055 312 m_macros.set(name, value);
5039dede
AK
313}
314
315
316//
317// Get macro
318//
319
6646dca4 320const TCHAR *LogParser::getMacro(const TCHAR *name)
5039dede
AK
321{
322 const TCHAR *value;
323
fb986055 324 value = m_macros.get(name);
5039dede
AK
325 return CHECK_NULL_EX(value);
326}
327
328
329//
330// Create parser configuration from XML
331//
332
5039dede
AK
333static void StartElement(void *userData, const char *name, const char **attrs)
334{
335 XML_PARSER_STATE *ps = (XML_PARSER_STATE *)userData;
336
337 if (!strcmp(name, "parser"))
338 {
339 ps->state = XML_STATE_PARSER;
6d738067
VK
340 ps->parser->setProcessAllFlag(XMLGetAttrBoolean(attrs, "processAll", false));
341 ps->parser->setTraceLevel(XMLGetAttrInt(attrs, "trace", 0));
e464b7dc
VK
342 const char *name = XMLGetAttr(attrs, "name");
343 if (name != NULL)
6646dca4
VK
344 {
345#ifdef UNICODE
346 WCHAR *wname = WideStringFromUTF8String(name);
347 ps->parser->setName(wname);
348 free(wname);
349#else
e464b7dc 350 ps->parser->setName(name);
6646dca4
VK
351#endif
352 }
5039dede
AK
353 }
354 else if (!strcmp(name, "file"))
355 {
356 ps->state = XML_STATE_FILE;
6646dca4
VK
357 const char *encoding = XMLGetAttr(attrs, "encoding");
358 if (encoding != NULL)
359 {
360 if (!stricmp(encoding, "acp") || (*encoding == 0))
361 {
565a8f28 362 ps->encodings.add(new int(LP_FCP_ACP));
6646dca4
VK
363 }
364 else if (!stricmp(encoding, "utf8") || !stricmp(encoding, "utf-8"))
365 {
565a8f28 366 ps->encodings.add(new int(LP_FCP_UTF8));
6646dca4
VK
367 }
368 else if (!stricmp(encoding, "ucs2") || !stricmp(encoding, "ucs-2") || !stricmp(encoding, "utf-16"))
369 {
565a8f28 370 ps->encodings.add(new int(LP_FCP_UCS2));
6646dca4
VK
371 }
372 else if (!stricmp(encoding, "ucs4") || !stricmp(encoding, "ucs-4") || !stricmp(encoding, "utf-32"))
373 {
565a8f28 374 ps->encodings.add(new int(LP_FCP_UCS4));
6646dca4
VK
375 }
376 else
377 {
378 ps->errorText = _T("Invalid file encoding");
379 ps->state = XML_STATE_ERROR;
380 }
381 }
382 else
383 {
565a8f28 384 ps->encodings.add(new int(LP_FCP_ACP));
6646dca4 385 }
5039dede
AK
386 }
387 else if (!strcmp(name, "macros"))
388 {
389 ps->state = XML_STATE_MACROS;
390 }
391 else if (!strcmp(name, "macro"))
392 {
393 const char *name;
394
395 ps->state = XML_STATE_MACRO;
396 name = XMLGetAttr(attrs, "name");
6646dca4
VK
397#ifdef UNICODE
398 ps->macroName = L"";
84880c89 399 ps->macroName.addMultiByteString(name, (DWORD)strlen(name), CP_UTF8);
6646dca4 400#else
5039dede 401 ps->macroName = CHECK_NULL_A(name);
6646dca4 402#endif
5039dede
AK
403 ps->macro = NULL;
404 }
405 else if (!strcmp(name, "rules"))
406 {
407 ps->state = XML_STATE_RULES;
408 }
409 else if (!strcmp(name, "rule"))
410 {
411 ps->regexp = NULL;
6d738067 412 ps->invertedRule = false;
5039dede
AK
413 ps->event = NULL;
414 ps->context = NULL;
415 ps->contextAction = CONTEXT_SET_AUTOMATIC;
416 ps->description = NULL;
6d738067
VK
417 ps->id = NULL;
418 ps->source = NULL;
419 ps->level = NULL;
6646dca4
VK
420#ifdef UNICODE
421 ps->ruleContext = L"";
422 const char *context = XMLGetAttr(attrs, "context");
423 if (context != NULL)
84880c89 424 ps->ruleContext.addMultiByteString(context, (DWORD)strlen(context), CP_UTF8);
6646dca4 425#else
5039dede 426 ps->ruleContext = XMLGetAttr(attrs, "context");
6646dca4 427#endif
6d738067 428 ps->breakFlag = XMLGetAttrBoolean(attrs, "break", false);
5039dede 429 ps->state = XML_STATE_RULE;
9eb288e6 430 ps->numEventParams = 0;
5039dede
AK
431 }
432 else if (!strcmp(name, "match"))
433 {
434 ps->state = XML_STATE_MATCH;
6d738067 435 ps->invertedRule = XMLGetAttrBoolean(attrs, "invert", false);
5039dede 436 }
d43aee56 437 else if (!strcmp(name, "id") || !strcmp(name, "facility"))
5039dede
AK
438 {
439 ps->state = XML_STATE_ID;
440 }
d43aee56 441 else if (!strcmp(name, "level") || !strcmp(name, "severity"))
5039dede
AK
442 {
443 ps->state = XML_STATE_LEVEL;
444 }
d43aee56 445 else if (!strcmp(name, "source") || !strcmp(name, "tag"))
5039dede
AK
446 {
447 ps->state = XML_STATE_SOURCE;
448 }
449 else if (!strcmp(name, "event"))
450 {
451 ps->numEventParams = XMLGetAttrDWORD(attrs, "params", 0);
452 ps->state = XML_STATE_EVENT;
453 }
454 else if (!strcmp(name, "context"))
455 {
456 const char *action;
457
458 ps->state = XML_STATE_CONTEXT;
459
460 action = XMLGetAttr(attrs, "action");
461 if (action == NULL)
462 action = "set";
463
464 if (!strcmp(action, "set"))
465 {
466 const char *mode;
467
468 mode = XMLGetAttr(attrs, "reset");
469 if (mode == NULL)
470 mode = "auto";
471
472 if (!strcmp(mode, "auto"))
473 {
474 ps->contextAction = CONTEXT_SET_AUTOMATIC;
475 }
476 else if (!strcmp(mode, "manual"))
477 {
478 ps->contextAction = CONTEXT_SET_MANUAL;
479 }
480 else
481 {
482 ps->errorText = _T("Invalid context reset mode");
483 ps->state = XML_STATE_ERROR;
484 }
485 }
486 else if (!strcmp(action, "clear"))
487 {
488 ps->contextAction = CONTEXT_CLEAR;
489 }
490 else
491 {
492 ps->errorText = _T("Invalid context action");
493 ps->state = XML_STATE_ERROR;
494 }
495 }
496 else if (!strcmp(name, "description"))
497 {
498 ps->state = XML_STATE_DESCRIPTION;
499 }
500 else
501 {
502 ps->state = XML_STATE_ERROR;
503 }
504}
505
506static void EndElement(void *userData, const char *name)
507{
508 XML_PARSER_STATE *ps = (XML_PARSER_STATE *)userData;
509
510 if (!strcmp(name, "parser"))
511 {
512 ps->state = XML_STATE_END;
513 }
514 else if (!strcmp(name, "file"))
515 {
721fc691
AK
516 ps->files.add(ps->file);
517 ps->file = _T("");
5039dede
AK
518 ps->state = XML_STATE_PARSER;
519 }
520 else if (!strcmp(name, "macros"))
521 {
522 ps->state = XML_STATE_PARSER;
523 }
524 else if (!strcmp(name, "macro"))
525 {
6d738067 526 ps->parser->addMacro(ps->macroName, ps->macro);
5039dede
AK
527 ps->state = XML_STATE_MACROS;
528 }
529 else if (!strcmp(name, "rules"))
530 {
531 ps->state = XML_STATE_PARSER;
532 }
533 else if (!strcmp(name, "rule"))
534 {
2dd24569 535 DWORD eventCode;
2dd24569 536 const TCHAR *eventName = NULL;
6646dca4 537 TCHAR *eptr;
5039dede
AK
538 LogParserRule *rule;
539
0bbab9d3 540 ps->event.trim();
6646dca4 541 eventCode = _tcstoul(ps->event, &eptr, 0);
5039dede 542 if (*eptr != 0)
2dd24569
VK
543 {
544 eventCode = ps->parser->resolveEventName(ps->event, 0);
545 if (eventCode == 0)
546 {
6646dca4 547 eventName = (const TCHAR *)ps->event;
2dd24569
VK
548 }
549 }
ce7565e7 550 if (ps->regexp.isEmpty())
d43aee56 551 ps->regexp = _T(".*");
6646dca4 552 rule = new LogParserRule(ps->parser, (const TCHAR *)ps->regexp, eventCode, eventName, ps->numEventParams);
ce7565e7 553 if (!ps->ruleContext.isEmpty())
6d738067 554 rule->setContext(ps->ruleContext);
ce7565e7 555 if (!ps->context.isEmpty())
5039dede 556 {
6d738067
VK
557 rule->setContextToChange(ps->context);
558 rule->setContextAction(ps->contextAction);
5039dede 559 }
6d738067 560
ce7565e7 561 if (!ps->description.isEmpty())
6d738067
VK
562 rule->setDescription(ps->description);
563
ce7565e7 564 if (!ps->source.isEmpty())
6d738067
VK
565 rule->setSource(ps->source);
566
ce7565e7 567 if (!ps->level.isEmpty())
6d738067
VK
568 rule->setLevel(_tcstoul(ps->level, NULL, 0));
569
ce7565e7 570 if (!ps->id.isEmpty())
6d738067
VK
571 {
572 DWORD start, end;
573 TCHAR *eptr;
574
6646dca4 575 start = _tcstoul(ps->id, &eptr, 0);
6d738067
VK
576 if (*eptr == 0)
577 {
578 end = start;
579 }
580 else /* TODO: add better error handling */
581 {
582 while(!_istdigit(*eptr))
583 eptr++;
6646dca4 584 end = _tcstoul(eptr, NULL, 0);
6d738067
VK
585 }
586 rule->setIdRange(start, end);
587 }
588
589 rule->setInverted(ps->invertedRule);
590 rule->setBreakFlag(ps->breakFlag);
591
592 ps->parser->addRule(rule);
5039dede
AK
593 ps->state = XML_STATE_RULES;
594 }
595 else if (!strcmp(name, "match"))
596 {
597 ps->state = XML_STATE_RULE;
598 }
d43aee56 599 else if (!strcmp(name, "id") || !strcmp(name, "facility"))
5039dede
AK
600 {
601 ps->state = XML_STATE_RULE;
602 }
d43aee56 603 else if (!strcmp(name, "level") || !strcmp(name, "severity"))
5039dede
AK
604 {
605 ps->state = XML_STATE_RULE;
606 }
d43aee56 607 else if (!strcmp(name, "source") || !strcmp(name, "tag"))
5039dede
AK
608 {
609 ps->state = XML_STATE_RULE;
610 }
611 else if (!strcmp(name, "event"))
612 {
613 ps->state = XML_STATE_RULE;
614 }
615 else if (!strcmp(name, "context"))
616 {
617 ps->state = XML_STATE_RULE;
618 }
619 else if (!strcmp(name, "description"))
620 {
621 ps->state = XML_STATE_RULE;
622 }
623}
624
625static void CharData(void *userData, const XML_Char *s, int len)
626{
627 XML_PARSER_STATE *ps = (XML_PARSER_STATE *)userData;
565a8f28 628 String str;
5039dede
AK
629
630 switch(ps->state)
631 {
632 case XML_STATE_MATCH:
6646dca4 633 ps->regexp.addMultiByteString(s, len, CP_UTF8);
5039dede
AK
634 break;
635 case XML_STATE_ID:
6646dca4 636 ps->id.addMultiByteString(s, len, CP_UTF8);
5039dede
AK
637 break;
638 case XML_STATE_LEVEL:
6646dca4 639 ps->level.addMultiByteString(s, len, CP_UTF8);
5039dede
AK
640 break;
641 case XML_STATE_SOURCE:
6646dca4 642 ps->source.addMultiByteString(s, len, CP_UTF8);
5039dede
AK
643 break;
644 case XML_STATE_EVENT:
6646dca4 645 ps->event.addMultiByteString(s, len, CP_UTF8);
5039dede
AK
646 break;
647 case XML_STATE_FILE:
721fc691 648 ps->file.addMultiByteString(s, len, CP_UTF8);
5039dede
AK
649 break;
650 case XML_STATE_CONTEXT:
6646dca4 651 ps->context.addMultiByteString(s, len, CP_UTF8);
5039dede
AK
652 break;
653 case XML_STATE_DESCRIPTION:
6646dca4 654 ps->description.addMultiByteString(s, len, CP_UTF8);
5039dede
AK
655 break;
656 case XML_STATE_MACRO:
6646dca4 657 ps->macro.addMultiByteString(s, len, CP_UTF8);
5039dede
AK
658 break;
659 default:
660 break;
661 }
662}
663
565a8f28 664ObjectArray<LogParser>* LogParser::createFromXml(const char *xml, int xmlLen, TCHAR *errorText, int errBufSize)
5039dede 665{
565a8f28 666 ObjectArray<LogParser>* parsers = NULL;
6d738067 667 bool success;
5039dede 668
565a8f28
AK
669 for (int k = 0; ; k++)
670 {
671 XML_Parser parser = XML_ParserCreate(NULL);
672 XML_PARSER_STATE state;
673 state.parser = new LogParser;
674 state.state = -1;
675 XML_SetUserData(parser, &state);
676 XML_SetElementHandler(parser, StartElement, EndElement);
677 XML_SetCharacterDataHandler(parser, CharData);
678 success = (XML_Parse(parser, xml, (xmlLen == -1) ? (int)strlen(xml) : xmlLen, TRUE) != XML_STATUS_ERROR);
679 if (!success && (errorText != NULL))
680 {
681 _sntprintf(errorText, errBufSize, _T("%hs at line %d"),
682 XML_ErrorString(XML_GetErrorCode(parser)),
683 (int)XML_GetCurrentLineNumber(parser));
684 break;
685 }
686 XML_ParserFree(parser);
687 if (success && (state.state == XML_STATE_ERROR))
688 {
689 success = false;
690 if (errorText != NULL)
691 _tcsncpy(errorText, state.errorText, errBufSize);
692 break;
693 }
694 else if (success)
695 {
696 if (parsers == NULL)
697 parsers = new ObjectArray<LogParser>;
698 parsers->add(state.parser);
699 if (k <= state.encodings.size() - 1)
700 {
701 state.parser->setFileName(state.files.getValue(k));
702 state.parser->setFileEncoding(*state.encodings.get(k));
703 }
704 if (k >= state.encodings.size() - 1)
705 break;
706 }
5039dede 707 }
5039dede 708
565a8f28 709 if (!success && parsers != NULL)
5039dede 710 {
565a8f28
AK
711 delete parsers;
712 parsers = NULL;
5039dede 713 }
565a8f28
AK
714
715 return parsers;
5039dede
AK
716}
717
718
719//
720// Resolve event name
721//
722
6646dca4 723DWORD LogParser::resolveEventName(const TCHAR *name, DWORD defVal)
5039dede
AK
724{
725 if (m_eventNameList != NULL)
726 {
727 int i;
728
729 for(i = 0; m_eventNameList[i].text != NULL; i++)
730 if (!_tcsicmp(name, m_eventNameList[i].text))
731 return m_eventNameList[i].code;
732 }
733
734 if (m_eventResolver != NULL)
735 {
736 DWORD val;
737
738 if (m_eventResolver(name, &val))
739 return val;
740 }
741
742 return defVal;
743}