blob: cec08d5a6fff9cec0d464b0b002f188afcc504dc [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2013-2015. All rights reserved.
Jon Medhurstaaf37a32013-06-11 12:10:56 +01003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "EventsXML.h"
10
11#include "CapturedXML.h"
12#include "Logging.h"
13#include "OlyUtility.h"
14#include "SessionData.h"
15
Jon Medhurstb1d07442015-05-08 12:04:18 +010016class XMLList {
17public:
18 XMLList(XMLList *const prev, mxml_node_t *const node) : mPrev(prev), mNode(node) {}
19
20 XMLList *getPrev() { return mPrev; }
21 mxml_node_t *getNode() const { return mNode; }
22 void setNode(mxml_node_t *const node) { mNode = node; }
23
24 static void free(XMLList *list) {
25 while (list != NULL) {
26 XMLList *prev = list->getPrev();
27 delete list;
28 list = prev;
29 }
30 }
31
32private:
33 XMLList *const mPrev;
34 mxml_node_t *mNode;
35
36 // Intentionally unimplemented
37 XMLList(const XMLList &);
38 XMLList &operator=(const XMLList &);
39};
40
Jon Medhurste31266f2014-08-04 15:47:44 +010041mxml_node_t *EventsXML::getTree() {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010042#include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
43 char path[PATH_MAX];
Jon Medhurstb1d07442015-05-08 12:04:18 +010044 mxml_node_t *xml = NULL;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010045 FILE *fl;
46
47 // Avoid unused variable warning
48 (void)events_xml_len;
49
50 // Load the provided or default events xml
51 if (gSessionData->mEventsXMLPath) {
52 strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
Jon Medhurstb1d07442015-05-08 12:04:18 +010053 fl = fopen(path, "r");
54 if (fl) {
55 xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
56 fclose(fl);
57 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +010058 }
Jon Medhurstb1d07442015-05-08 12:04:18 +010059 if (xml == NULL) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010060 logg->logMessage("Unable to locate events.xml, using default");
Jon Medhurst15ce78d2014-04-10 09:02:02 +010061 xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK);
Jon Medhurstaaf37a32013-06-11 12:10:56 +010062 }
63
Jon Medhurstb1d07442015-05-08 12:04:18 +010064 // Append additional events XML
65 if (gSessionData->mEventsXMLAppend) {
66 fl = fopen(gSessionData->mEventsXMLAppend, "r");
67 if (fl == NULL) {
68 logg->logError("Unable to open additional events XML %s", gSessionData->mEventsXMLAppend);
69 handleException();
70 }
71 mxml_node_t *append = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
72 fclose(fl);
73
74 mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
75 if (!events) {
76 logg->logError("Unable to find <events> node in the events.xml, please ensure the first two lines of events XML starts with:\n"
77 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
78 "<events>");
79 handleException();
80 }
81
82 XMLList *categoryList = NULL;
83 XMLList *eventList = NULL;
84 {
85 // Make list of all categories in xml
86 mxml_node_t *node = xml;
87 while (true) {
88 node = mxmlFindElement(node, xml, "category", NULL, NULL, MXML_DESCEND);
89 if (node == NULL) {
90 break;
91 }
92 categoryList = new XMLList(categoryList, node);
93 }
94
95 // Make list of all events in xml
96 node = xml;
97 while (true) {
98 node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
99 if (node == NULL) {
100 break;
101 }
102 eventList = new XMLList(eventList, node);
103 }
104 }
105
106 // Handle events
107 for (mxml_node_t *node = mxmlFindElement(append, append, "event", NULL, NULL, MXML_DESCEND),
108 *next = mxmlFindElement(node, append, "event", NULL, NULL, MXML_DESCEND);
109 node != NULL;
110 node = next, next = mxmlFindElement(node, append, "event", NULL, NULL, MXML_DESCEND)) {
111 const char *const category = mxmlElementGetAttr(mxmlGetParent(node), "name");
112 const char *const title = mxmlElementGetAttr(node, "title");
113 const char *const name = mxmlElementGetAttr(node, "name");
114 if (category == NULL || title == NULL || name == NULL) {
115 logg->logError("Not all event XML nodes have the required title and name and parent name attributes");
116 handleException();
117 }
118
119 // Replace any duplicate events
120 for (XMLList *event = eventList; event != NULL; event = event->getPrev()) {
121 const char *const category2 = mxmlElementGetAttr(mxmlGetParent(event->getNode()), "name");
122 const char *const title2 = mxmlElementGetAttr(event->getNode(), "title");
123 const char *const name2 = mxmlElementGetAttr(event->getNode(), "name");
124 if (category2 == NULL || title2 == NULL || name2 == NULL) {
125 logg->logError("Not all event XML nodes have the required title and name and parent name attributes");
126 handleException();
127 }
128
129 if (strcmp(category, category2) == 0 && strcmp(title, title2) == 0 && strcmp(name, name2) == 0) {
130 logg->logMessage("Replacing counter %s %s: %s", category, title, name);
131 mxml_node_t *parent = mxmlGetParent(event->getNode());
132 mxmlDelete(event->getNode());
133 mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
134 event->setNode(node);
135 break;
136 }
137 }
138 }
139
140 // Handle categories
141 for (mxml_node_t *node = strcmp(mxmlGetElement(append), "category") == 0 ? append : mxmlFindElement(append, append, "category", NULL, NULL, MXML_DESCEND),
142 *next = mxmlFindElement(node, append, "category", NULL, NULL, MXML_DESCEND);
143 node != NULL;
144 node = next, next = mxmlFindElement(node, append, "category", NULL, NULL, MXML_DESCEND)) {
145 // After replacing duplicate events, a category may be empty
146 if (mxmlGetFirstChild(node) == NULL) {
147 continue;
148 }
149
150 const char *const name = mxmlElementGetAttr(node, "name");
151 if (name == NULL) {
152 logg->logError("Not all event XML categories have the required name attribute");
153 handleException();
154 }
155
156 // Merge identically named categories
157 bool merged = false;
158 for (XMLList *category = categoryList; category != NULL; category = category->getPrev()) {
159 const char *const name2 = mxmlElementGetAttr(category->getNode(), "name");
160 if (name2 == NULL) {
161 logg->logError("Not all event XML categories have the required name attribute");
162 handleException();
163 }
164
165 if (strcmp(name, name2) == 0) {
166 logg->logMessage("Merging category %s", name);
167 while (true) {
168 mxml_node_t *child = mxmlGetFirstChild(node);
169 if (child == NULL) {
170 break;
171 }
172 mxmlAdd(category->getNode(), MXML_ADD_AFTER, mxmlGetLastChild(category->getNode()), child);
173 }
174 merged = true;
175 break;
176 }
177 }
178
179 if (merged) {
180 continue;
181 }
182
183 // Add new categories
184 logg->logMessage("Appending category %s", name);
185 mxmlAdd(events, MXML_ADD_AFTER, mxmlGetLastChild(events), node);
186 }
187
188 XMLList::free(eventList);
189 XMLList::free(categoryList);
190
191 mxmlDelete(append);
192 }
193
Jon Medhurste31266f2014-08-04 15:47:44 +0100194 return xml;
195}
196
197char *EventsXML::getXML() {
198 mxml_node_t *xml = getTree();
199
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100200 // Add dynamic events from the drivers
201 mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
202 if (!events) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100203 logg->logError("Unable to find <events> node in the events.xml, please ensure the first two lines of events XML are:\n"
204 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
205 "<events>");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100206 handleException();
207 }
208 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
209 driver->writeEvents(events);
210 }
211
Jon Medhurste31266f2014-08-04 15:47:44 +0100212 char *string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100213 mxmlDelete(xml);
214
215 return string;
216}
217
Jon Medhurste31266f2014-08-04 15:47:44 +0100218void EventsXML::write(const char *path) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100219 char file[PATH_MAX];
220
221 // Set full path
222 snprintf(file, PATH_MAX, "%s/events.xml", path);
Jon Medhurste31266f2014-08-04 15:47:44 +0100223
224 char *buf = getXML();
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100225 if (util->writeToDisk(file, buf) < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100226 logg->logError("Error writing %s\nPlease verify the path.", file);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100227 handleException();
228 }
229
230 free(buf);
231}