-/*******************************************************************************\r
- * Copyright (c) 2010 Ericsson\r
- * \r
- * All rights reserved. This program and the accompanying materials are\r
- * made available under the terms of the Eclipse Public License v1.0 which\r
- * accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- * \r
- * Contributors:\r
- * Patrick Tasse - Initial API and implementation\r
- *******************************************************************************/\r
-\r
-package org.eclipse.linuxtools.internal.tmf.ui.parsers.custom;\r
-\r
-import java.io.ByteArrayInputStream;\r
-import java.io.File;\r
-import java.io.FileNotFoundException;\r
-import java.io.IOException;\r
-import java.io.RandomAccessFile;\r
-\r
-import javax.xml.parsers.DocumentBuilder;\r
-import javax.xml.parsers.DocumentBuilderFactory;\r
-import javax.xml.parsers.ParserConfigurationException;\r
-\r
-import org.eclipse.core.resources.IProject;\r
-import org.eclipse.core.resources.IResource;\r
-import org.eclipse.linuxtools.internal.tmf.ui.TmfUiPlugin;\r
-import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTraceDefinition.InputAttribute;\r
-import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTraceDefinition.InputElement;\r
-import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;\r
-import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;\r
-import org.eclipse.linuxtools.tmf.core.io.BufferedRandomAccessFile;\r
-import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;\r
-import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser;\r
-import org.eclipse.linuxtools.tmf.core.trace.ITmfLocation;\r
-import org.eclipse.linuxtools.tmf.core.trace.TmfContext;\r
-import org.eclipse.linuxtools.tmf.core.trace.TmfLocation;\r
-import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;\r
-import org.w3c.dom.Document;\r
-import org.w3c.dom.Element;\r
-import org.w3c.dom.Node;\r
-import org.w3c.dom.NodeList;\r
-import org.xml.sax.EntityResolver;\r
-import org.xml.sax.ErrorHandler;\r
-import org.xml.sax.InputSource;\r
-import org.xml.sax.SAXException;\r
-import org.xml.sax.SAXParseException;\r
-\r
-public class CustomXmlTrace extends TmfTrace<CustomXmlEvent> implements ITmfEventParser<CustomXmlEvent> {\r
-\r
- private static final TmfLocation<Long> NULL_LOCATION = new TmfLocation<Long>((Long) null);\r
- private static final int DEFAULT_CACHE_SIZE = 100;\r
-\r
- private final CustomXmlTraceDefinition fDefinition;\r
- private final CustomXmlEventType fEventType;\r
- private final InputElement fRecordInputElement;\r
-\r
- public CustomXmlTrace(final CustomXmlTraceDefinition definition) {\r
- fDefinition = definition;\r
- fEventType = new CustomXmlEventType(fDefinition);\r
- fRecordInputElement = getRecordInputElement(fDefinition.rootInputElement);\r
- }\r
-\r
- public CustomXmlTrace(final IResource resource, final CustomXmlTraceDefinition definition, final String path, final int pageSize) throws TmfTraceException {\r
- super(null, CustomXmlEvent.class, path, (pageSize > 0) ? pageSize : DEFAULT_CACHE_SIZE);\r
- fDefinition = definition;\r
- fEventType = new CustomXmlEventType(fDefinition);\r
- fRecordInputElement = getRecordInputElement(fDefinition.rootInputElement);\r
- }\r
-\r
- @Override\r
- public void initTrace(final IResource resource, final String path, final Class<CustomXmlEvent> eventType) throws TmfTraceException {\r
- super.initTrace(resource, path, eventType);\r
- }\r
-\r
- @Override\r
- public TmfContext seekEvent(final ITmfLocation<?> location) {\r
- final CustomXmlTraceContext context = new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);\r
- if (NULL_LOCATION.equals(location) || !new File(getPath()).isFile())\r
- return context;\r
- try {\r
- context.raFile = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$\r
- if (location != null && location.getLocation() instanceof Long) {\r
- context.raFile.seek((Long)location.getLocation());\r
- }\r
-\r
- String line;\r
- final String recordElementStart = "<" + fRecordInputElement.elementName; //$NON-NLS-1$\r
- long rawPos = context.raFile.getFilePointer();\r
-\r
- while ((line = context.raFile.getNextLine()) != null) {\r
- final int idx = line.indexOf(recordElementStart);\r
- if (idx != -1) {\r
- context.setLocation(new TmfLocation<Long>(rawPos + idx));\r
- return context;\r
- }\r
- rawPos = context.raFile.getFilePointer();\r
- }\r
- return context;\r
- } catch (final FileNotFoundException e) {\r
- TmfUiPlugin.getDefault().logError("Error seeking event. File not found: " + getPath(), e); //$NON-NLS-1$\r
- return context;\r
- } catch (final IOException e) {\r
- TmfUiPlugin.getDefault().logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$\r
- return context;\r
- }\r
-\r
- }\r
-\r
- @Override\r
- public TmfContext seekEvent(final double ratio) {\r
- BufferedRandomAccessFile raFile = null;\r
- try {\r
- raFile = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$\r
- long pos = (long) (ratio * raFile.length());\r
- while (pos > 0) {\r
- raFile.seek(pos - 1);\r
- if (raFile.read() == '\n') {\r
- break;\r
- }\r
- pos--;\r
- }\r
- final ITmfLocation<?> location = new TmfLocation<Long>(pos);\r
- final TmfContext context = seekEvent(location);\r
- context.setRank(ITmfContext.UNKNOWN_RANK);\r
- return context;\r
- } catch (final FileNotFoundException e) {\r
- TmfUiPlugin.getDefault().logError("Error seeking event. File not found: " + getPath(), e); //$NON-NLS-1$\r
- return new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);\r
- } catch (final IOException e) {\r
- TmfUiPlugin.getDefault().logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$\r
- return new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);\r
- } finally {\r
- if (raFile != null) {\r
- try {\r
- raFile.close();\r
- } catch (final IOException e) {\r
- }\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public double getLocationRatio(final ITmfLocation<?> location) {\r
- RandomAccessFile raFile = null;\r
- try {\r
- if (location.getLocation() instanceof Long) {\r
- raFile = new RandomAccessFile(getPath(), "r"); //$NON-NLS-1$\r
- return (double) ((Long) location.getLocation()) / raFile.length();\r
- }\r
- } catch (final FileNotFoundException e) {\r
- TmfUiPlugin.getDefault().logError("Error getting location ration. File not found: " + getPath(), e); //$NON-NLS-1$\r
- } catch (final IOException e) {\r
- TmfUiPlugin.getDefault().logError("Error getting location ration. File: " + getPath(), e); //$NON-NLS-1$\r
- } finally {\r
- if (raFile != null) {\r
- try {\r
- raFile.close();\r
- } catch (final IOException e) {\r
- }\r
- }\r
- }\r
- return 0;\r
- }\r
-\r
- @Override\r
- public ITmfLocation<?> getCurrentLocation() {\r
- // TODO Auto-generated method stub\r
- return null;\r
- }\r
-\r
- @Override\r
- public synchronized CustomXmlEvent getNext(final ITmfContext context) {\r
- final ITmfContext savedContext = context.clone();\r
- final CustomXmlEvent event = parseEvent(context);\r
- if (event != null) {\r
- updateAttributes(savedContext, event.getTimestamp());\r
- context.increaseRank();\r
- }\r
- return event;\r
- }\r
-\r
- @Override\r
- public CustomXmlEvent parseEvent(final ITmfContext tmfContext) {\r
- if (!(tmfContext instanceof CustomXmlTraceContext))\r
- return null;\r
-\r
- final CustomXmlTraceContext context = (CustomXmlTraceContext) tmfContext;\r
- if (!(context.getLocation().getLocation() instanceof Long) || NULL_LOCATION.equals(context.getLocation()))\r
- return null;\r
-\r
- synchronized (context.raFile) {\r
- CustomXmlEvent event = null;\r
- try {\r
- if (context.raFile.getFilePointer() != (Long)context.getLocation().getLocation() + 1)\r
- {\r
- context.raFile.seek((Long)context.getLocation().getLocation() + 1); // +1 is for the <\r
- }\r
- final StringBuffer elementBuffer = new StringBuffer("<"); //$NON-NLS-1$\r
- readElement(elementBuffer, context.raFile);\r
- final Element element = parseElementBuffer(elementBuffer);\r
-\r
- event = extractEvent(element, fRecordInputElement);\r
- ((StringBuffer) event.getContent().getValue()).append(elementBuffer);\r
-\r
- String line;\r
- final String recordElementStart = "<" + fRecordInputElement.elementName; //$NON-NLS-1$\r
- long rawPos = context.raFile.getFilePointer();\r
-\r
- while ((line = context.raFile.getNextLine()) != null) {\r
- final int idx = line.indexOf(recordElementStart);\r
- if (idx != -1) {\r
- context.setLocation(new TmfLocation<Long>(rawPos + idx));\r
- return event;\r
- }\r
- rawPos = context.raFile.getFilePointer();\r
- }\r
- } catch (final IOException e) {\r
- TmfUiPlugin.getDefault().logError("Error pasing event. File: " + getPath(), e); //$NON-NLS-1$\r
- \r
- }\r
- context.setLocation(NULL_LOCATION);\r
- return event;\r
- }\r
- }\r
-\r
- private Element parseElementBuffer(final StringBuffer elementBuffer) {\r
- try {\r
- final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r
- final DocumentBuilder db = dbf.newDocumentBuilder();\r
-\r
- // The following allows xml parsing without access to the dtd\r
- final EntityResolver resolver = new EntityResolver () {\r
- @Override\r
- public InputSource resolveEntity (final String publicId, final String systemId) {\r
- final String empty = ""; //$NON-NLS-1$\r
- final ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());\r
- return new InputSource(bais);\r
- }\r
- };\r
- db.setEntityResolver(resolver);\r
-\r
- // The following catches xml parsing exceptions\r
- db.setErrorHandler(new ErrorHandler(){\r
- @Override\r
- public void error(final SAXParseException saxparseexception) throws SAXException {}\r
- @Override\r
- public void warning(final SAXParseException saxparseexception) throws SAXException {}\r
- @Override\r
- public void fatalError(final SAXParseException saxparseexception) throws SAXException {\r
- throw saxparseexception;\r
- }});\r
-\r
- final Document doc = db.parse(new ByteArrayInputStream(elementBuffer.toString().getBytes()));\r
- return doc.getDocumentElement();\r
- } catch (final ParserConfigurationException e) {\r
- TmfUiPlugin.getDefault().logError("Error parsing element buffer. File:" + getPath(), e); //$NON-NLS-1$\r
- } catch (final SAXException e) {\r
- TmfUiPlugin.getDefault().logError("Error parsing element buffer. File:" + getPath(), e); //$NON-NLS-1$\r
- } catch (final IOException e) {\r
- TmfUiPlugin.getDefault().logError("Error parsing element buffer. File: " + getPath(), e); //$NON-NLS-1$\r
- }\r
- return null;\r
- }\r
-\r
- private void readElement(final StringBuffer buffer, final RandomAccessFile raFile) {\r
- try {\r
- int numRead = 0;\r
- boolean startTagClosed = false;\r
- int i;\r
- while ((i = raFile.read()) != -1) {\r
- numRead++;\r
- final char c = (char)i;\r
- buffer.append(c);\r
- if (c == '"') {\r
- readQuote(buffer, raFile, '"');\r
- } else if (c == '\'') {\r
- readQuote(buffer, raFile, '\'');\r
- } else if (c == '<') {\r
- readElement(buffer, raFile);\r
- } else if (c == '/' && numRead == 1) {\r
- break; // found "</"\r
- } else if (c == '-' && numRead == 3 && buffer.substring(buffer.length() - 3, buffer.length() - 1).equals("!-")) { //$NON-NLS-1$\r
- readComment(buffer, raFile); // found "<!--"\r
- } else if (i == '>')\r
- if (buffer.charAt(buffer.length() - 2) == '/') {\r
- break; // found "/>"\r
- } else if (startTagClosed) {\r
- break; // found "<...>...</...>"\r
- }\r
- else {\r
- startTagClosed = true; // found "<...>"\r
- }\r
- }\r
- return;\r
- } catch (final IOException e) {\r
- return;\r
- }\r
- }\r
-\r
- private void readQuote(final StringBuffer buffer, final RandomAccessFile raFile, final char eq) {\r
- try {\r
- int i;\r
- while ((i = raFile.read()) != -1) {\r
- final char c = (char)i;\r
- buffer.append(c);\r
- if (c == eq)\r
- {\r
- break; // found matching end-quote\r
- }\r
- }\r
- return;\r
- } catch (final IOException e) {\r
- return;\r
- }\r
- }\r
-\r
- private void readComment(final StringBuffer buffer, final RandomAccessFile raFile) {\r
- try {\r
- int numRead = 0;\r
- int i;\r
- while ((i = raFile.read()) != -1) {\r
- numRead++;\r
- final char c = (char)i;\r
- buffer.append(c);\r
- if (c == '>' && numRead >= 2 && buffer.substring(buffer.length() - 3, buffer.length() - 1).equals("--")) //$NON-NLS-1$\r
- {\r
- break; // found "-->"\r
- }\r
- }\r
- return;\r
- } catch (final IOException e) {\r
- return;\r
- }\r
- }\r
-\r
- public static StringBuffer parseElement(final Element parentElement, final StringBuffer buffer) {\r
- final NodeList nodeList = parentElement.getChildNodes();\r
- String separator = null;\r
- for (int i = 0; i < nodeList.getLength(); i++) {\r
- final Node node = nodeList.item(i);\r
- if (node.getNodeType() == Node.ELEMENT_NODE) {\r
- if (separator == null) {\r
- separator = " | "; //$NON-NLS-1$\r
- } else {\r
- buffer.append(separator);\r
- }\r
- final Element element = (Element) node;\r
- if (!element.hasChildNodes()) {\r
- buffer.append(element.getNodeName());\r
- } else if (element.getChildNodes().getLength() == 1 && element.getFirstChild().getNodeType() == Node.TEXT_NODE) {\r
- buffer.append(element.getNodeName() + ":" + element.getFirstChild().getNodeValue().trim()); //$NON-NLS-1$\r
- } else {\r
- buffer.append(element.getNodeName());\r
- buffer.append(" [ "); //$NON-NLS-1$\r
- parseElement(element, buffer);\r
- buffer.append(" ]"); //$NON-NLS-1$\r
- }\r
- } else if (node.getNodeType() == Node.TEXT_NODE)\r
- if (node.getNodeValue().trim().length() != 0) {\r
- buffer.append(node.getNodeValue().trim());\r
- }\r
- }\r
- return buffer;\r
- }\r
-\r
- public InputElement getRecordInputElement(final InputElement inputElement) {\r
- if (inputElement.logEntry)\r
- return inputElement;\r
- else if (inputElement.childElements != null) {\r
- for (final InputElement childInputElement : inputElement.childElements) {\r
- final InputElement recordInputElement = getRecordInputElement(childInputElement);\r
- if (recordInputElement != null)\r
- return recordInputElement;\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- public CustomXmlEvent extractEvent(final Element element, final InputElement inputElement) {\r
- final CustomXmlEvent event = new CustomXmlEvent(fDefinition, this, TmfTimestamp.ZERO, "", fEventType,""); //$NON-NLS-1$ //$NON-NLS-2$\r
- event.setContent(new CustomEventContent(event, "")); //$NON-NLS-1$\r
- parseElement(element, event, inputElement);\r
- return event;\r
- }\r
-\r
- private void parseElement(final Element element, final CustomXmlEvent event, final InputElement inputElement) {\r
- if (inputElement.inputName != null && !inputElement.inputName.equals(CustomXmlTraceDefinition.TAG_IGNORE)) {\r
- event.parseInput(parseElement(element, new StringBuffer()).toString(), inputElement.inputName, inputElement.inputAction, inputElement.inputFormat);\r
- }\r
- if (inputElement.attributes != null) {\r
- for (final InputAttribute attribute : inputElement.attributes) {\r
- event.parseInput(element.getAttribute(attribute.attributeName), attribute.inputName, attribute.inputAction, attribute.inputFormat);\r
- }\r
- }\r
- final NodeList childNodes = element.getChildNodes();\r
- if (inputElement.childElements != null) {\r
- for (int i = 0; i < childNodes.getLength(); i++) {\r
- final Node node = childNodes.item(i);\r
- if (node instanceof Element) {\r
- for (final InputElement child : inputElement.childElements)\r
- if (node.getNodeName().equals(child.elementName)) {\r
- parseElement((Element) node, event, child);\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- return;\r
- }\r
-\r
- public CustomTraceDefinition getDefinition() {\r
- return fDefinition;\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)\r
- */\r
- @Override\r
- public boolean validate(IProject project, String path) {\r
- return fileExists(path);\r
- }\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.ui.parsers.custom;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.linuxtools.internal.tmf.ui.Activator;
+import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTraceDefinition.InputAttribute;
+import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTraceDefinition.InputElement;
+import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
+import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
+import org.eclipse.linuxtools.tmf.core.io.BufferedRandomAccessFile;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfLocation;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
+import org.eclipse.linuxtools.tmf.core.trace.TmfLongLocation;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Trace object for custom XML trace parsers.
+ *
+ * @author Patrick Tassé
+ */
+public class CustomXmlTrace extends TmfTrace implements ITmfEventParser {
+
+ private static final TmfLongLocation NULL_LOCATION = new TmfLongLocation((Long) null);
+ private static final int DEFAULT_CACHE_SIZE = 100;
+
+ private final CustomXmlTraceDefinition fDefinition;
+ private final CustomXmlEventType fEventType;
+ private final InputElement fRecordInputElement;
+ private BufferedRandomAccessFile fFile;
+
+ /**
+ * Basic constructor
+ *
+ * @param definition Trace definition
+ */
+ public CustomXmlTrace(final CustomXmlTraceDefinition definition) {
+ fDefinition = definition;
+ fEventType = new CustomXmlEventType(fDefinition);
+ fRecordInputElement = getRecordInputElement(fDefinition.rootInputElement);
+ setCacheSize(DEFAULT_CACHE_SIZE);
+ }
+
+ /**
+ * Full constructor
+ *
+ * @param resource
+ * Trace resource
+ * @param definition
+ * Trace definition
+ * @param path
+ * Path to the trace/log file
+ * @param pageSize
+ * Page size to use
+ * @throws TmfTraceException
+ * If the trace/log couldn't be opened
+ */
+ public CustomXmlTrace(final IResource resource,
+ final CustomXmlTraceDefinition definition, final String path,
+ final int pageSize) throws TmfTraceException {
+ this(definition);
+ setCacheSize((pageSize > 0) ? pageSize : DEFAULT_CACHE_SIZE);
+ initTrace(resource, path, CustomXmlEvent.class);
+ }
+
+ @Override
+ public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> eventType) throws TmfTraceException {
+ super.initTrace(resource, path, eventType);
+ try {
+ fFile = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$
+ } catch (IOException e) {
+ throw new TmfTraceException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public synchronized void dispose() {
+ super.dispose();
+ if (fFile != null) {
+ try {
+ fFile.close();
+ } catch (IOException e) {
+ } finally {
+ fFile = null;
+ }
+ }
+ }
+
+ @Override
+ public ITmfTraceIndexer getIndexer() {
+ return super.getIndexer();
+ }
+
+ @Override
+ public synchronized TmfContext seekEvent(final ITmfLocation location) {
+ final CustomXmlTraceContext context = new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
+ if (NULL_LOCATION.equals(location) || fFile == null) {
+ return context;
+ }
+ try {
+ if (location == null) {
+ fFile.seek(0);
+ } else if (location.getLocationInfo() instanceof Long) {
+ fFile.seek((Long) location.getLocationInfo());
+ }
+ String line;
+ final String recordElementStart = "<" + fRecordInputElement.elementName; //$NON-NLS-1$
+ long rawPos = fFile.getFilePointer();
+
+ while ((line = fFile.getNextLine()) != null) {
+ final int idx = line.indexOf(recordElementStart);
+ if (idx != -1) {
+ context.setLocation(new TmfLongLocation(rawPos + idx));
+ return context;
+ }
+ rawPos = fFile.getFilePointer();
+ }
+ return context;
+ } catch (final IOException e) {
+ Activator.getDefault().logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
+ return context;
+ }
+
+ }
+
+ @Override
+ public synchronized TmfContext seekEvent(final double ratio) {
+ if (fFile == null) {
+ return new CustomTxtTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
+ }
+ try {
+ long pos = Math.round(ratio * fFile.length());
+ while (pos > 0) {
+ fFile.seek(pos - 1);
+ if (fFile.read() == '\n') {
+ break;
+ }
+ pos--;
+ }
+ final ITmfLocation location = new TmfLongLocation(pos);
+ final TmfContext context = seekEvent(location);
+ context.setRank(ITmfContext.UNKNOWN_RANK);
+ return context;
+ } catch (final IOException e) {
+ Activator.getDefault().logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
+ return new CustomXmlTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
+ }
+ }
+
+ @Override
+ public synchronized double getLocationRatio(final ITmfLocation location) {
+ if (fFile == null) {
+ return 0;
+ }
+ try {
+ if (location.getLocationInfo() instanceof Long) {
+ return (double) ((Long) location.getLocationInfo()) / fFile.length();
+ }
+ } catch (final IOException e) {
+ Activator.getDefault().logError("Error getting location ration. File: " + getPath(), e); //$NON-NLS-1$
+ }
+ return 0;
+ }
+
+ @Override
+ public ITmfLocation getCurrentLocation() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public synchronized CustomXmlEvent parseEvent(final ITmfContext tmfContext) {
+ ITmfContext context = seekEvent(tmfContext.getLocation());
+ return parse(context);
+ }
+
+ @Override
+ public synchronized CustomXmlEvent getNext(final ITmfContext context) {
+ final ITmfContext savedContext = new TmfContext(context.getLocation(), context.getRank());
+ final CustomXmlEvent event = parse(context);
+ if (event != null) {
+ updateAttributes(savedContext, event.getTimestamp());
+ context.increaseRank();
+ }
+ return event;
+ }
+
+ private synchronized CustomXmlEvent parse(final ITmfContext tmfContext) {
+ if (fFile == null) {
+ return null;
+ }
+ if (!(tmfContext instanceof CustomXmlTraceContext)) {
+ return null;
+ }
+
+ final CustomXmlTraceContext context = (CustomXmlTraceContext) tmfContext;
+ if (context.getLocation() == null || !(context.getLocation().getLocationInfo() instanceof Long) || NULL_LOCATION.equals(context.getLocation())) {
+ return null;
+ }
+
+ CustomXmlEvent event = null;
+ try {
+ if (fFile.getFilePointer() != (Long)context.getLocation().getLocationInfo() + 1)
+ {
+ fFile.seek((Long)context.getLocation().getLocationInfo() + 1); // +1 is for the <
+ }
+ final StringBuffer elementBuffer = new StringBuffer("<"); //$NON-NLS-1$
+ readElement(elementBuffer, fFile);
+ final Element element = parseElementBuffer(elementBuffer);
+
+ event = extractEvent(element, fRecordInputElement);
+ ((StringBuffer) event.getContent().getValue()).append(elementBuffer);
+
+ String line;
+ final String recordElementStart = "<" + fRecordInputElement.elementName; //$NON-NLS-1$
+ long rawPos = fFile.getFilePointer();
+
+ while ((line = fFile.getNextLine()) != null) {
+ final int idx = line.indexOf(recordElementStart);
+ if (idx != -1) {
+ context.setLocation(new TmfLongLocation(rawPos + idx));
+ return event;
+ }
+ rawPos = fFile.getFilePointer();
+ }
+ } catch (final IOException e) {
+ Activator.getDefault().logError("Error parsing event. File: " + getPath(), e); //$NON-NLS-1$
+
+ }
+ context.setLocation(NULL_LOCATION);
+ return event;
+ }
+
+ private Element parseElementBuffer(final StringBuffer elementBuffer) {
+ try {
+ final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ final DocumentBuilder db = dbf.newDocumentBuilder();
+
+ // The following allows xml parsing without access to the dtd
+ final EntityResolver resolver = new EntityResolver () {
+ @Override
+ public InputSource resolveEntity (final String publicId, final String systemId) {
+ final String empty = ""; //$NON-NLS-1$
+ final ByteArrayInputStream bais = new ByteArrayInputStream(empty.getBytes());
+ return new InputSource(bais);
+ }
+ };
+ db.setEntityResolver(resolver);
+
+ // The following catches xml parsing exceptions
+ db.setErrorHandler(new ErrorHandler(){
+ @Override
+ public void error(final SAXParseException saxparseexception) throws SAXException {}
+ @Override
+ public void warning(final SAXParseException saxparseexception) throws SAXException {}
+ @Override
+ public void fatalError(final SAXParseException saxparseexception) throws SAXException {
+ throw saxparseexception;
+ }});
+
+ final Document doc = db.parse(new ByteArrayInputStream(elementBuffer.toString().getBytes()));
+ return doc.getDocumentElement();
+ } catch (final ParserConfigurationException e) {
+ Activator.getDefault().logError("Error parsing element buffer. File:" + getPath(), e); //$NON-NLS-1$
+ } catch (final SAXException e) {
+ Activator.getDefault().logError("Error parsing element buffer. File:" + getPath(), e); //$NON-NLS-1$
+ } catch (final IOException e) {
+ Activator.getDefault().logError("Error parsing element buffer. File: " + getPath(), e); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ private void readElement(final StringBuffer buffer, final RandomAccessFile raFile) {
+ try {
+ int numRead = 0;
+ boolean startTagClosed = false;
+ int i;
+ while ((i = raFile.read()) != -1) {
+ numRead++;
+ final char c = (char)i;
+ buffer.append(c);
+ if (c == '"') {
+ readQuote(buffer, raFile, '"');
+ } else if (c == '\'') {
+ readQuote(buffer, raFile, '\'');
+ } else if (c == '<') {
+ readElement(buffer, raFile);
+ } else if (c == '/' && numRead == 1) {
+ break; // found "</"
+ } else if (c == '-' && numRead == 3 && buffer.substring(buffer.length() - 3, buffer.length() - 1).equals("!-")) { //$NON-NLS-1$
+ readComment(buffer, raFile); // found "<!--"
+ } else if (i == '>') {
+ if (buffer.charAt(buffer.length() - 2) == '/') {
+ break; // found "/>"
+ } else if (startTagClosed) {
+ break; // found "<...>...</...>"
+ }
+ else {
+ startTagClosed = true; // found "<...>"
+ }
+ }
+ }
+ return;
+ } catch (final IOException e) {
+ return;
+ }
+ }
+
+ private static void readQuote(final StringBuffer buffer,
+ final RandomAccessFile raFile, final char eq) {
+ try {
+ int i;
+ while ((i = raFile.read()) != -1) {
+ final char c = (char)i;
+ buffer.append(c);
+ if (c == eq)
+ {
+ break; // found matching end-quote
+ }
+ }
+ return;
+ } catch (final IOException e) {
+ return;
+ }
+ }
+
+ private static void readComment(final StringBuffer buffer,
+ final RandomAccessFile raFile) {
+ try {
+ int numRead = 0;
+ int i;
+ while ((i = raFile.read()) != -1) {
+ numRead++;
+ final char c = (char)i;
+ buffer.append(c);
+ if (c == '>' && numRead >= 2 && buffer.substring(buffer.length() - 3, buffer.length() - 1).equals("--")) //$NON-NLS-1$
+ {
+ break; // found "-->"
+ }
+ }
+ return;
+ } catch (final IOException e) {
+ return;
+ }
+ }
+
+ /**
+ * Parse an XML element.
+ *
+ * @param parentElement
+ * The parent element
+ * @param buffer
+ * The contents to parse
+ * @return The parsed content
+ */
+ public static StringBuffer parseElement(final Element parentElement, final StringBuffer buffer) {
+ final NodeList nodeList = parentElement.getChildNodes();
+ String separator = null;
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ final Node node = nodeList.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ if (separator == null) {
+ separator = " | "; //$NON-NLS-1$
+ } else {
+ buffer.append(separator);
+ }
+ final Element element = (Element) node;
+ if (!element.hasChildNodes()) {
+ buffer.append(element.getNodeName());
+ } else if (element.getChildNodes().getLength() == 1 && element.getFirstChild().getNodeType() == Node.TEXT_NODE) {
+ buffer.append(element.getNodeName() + ":" + element.getFirstChild().getNodeValue().trim()); //$NON-NLS-1$
+ } else {
+ buffer.append(element.getNodeName());
+ buffer.append(" [ "); //$NON-NLS-1$
+ parseElement(element, buffer);
+ buffer.append(" ]"); //$NON-NLS-1$
+ }
+ } else if (node.getNodeType() == Node.TEXT_NODE) {
+ if (node.getNodeValue().trim().length() != 0) {
+ buffer.append(node.getNodeValue().trim());
+ }
+ }
+ }
+ return buffer;
+ }
+
+ /**
+ * Get an input element if it is a valid record input. If not, we will look
+ * into its children for valid inputs.
+ *
+ * @param inputElement
+ * The main element to check for.
+ * @return The record element
+ */
+ public InputElement getRecordInputElement(final InputElement inputElement) {
+ if (inputElement.logEntry) {
+ return inputElement;
+ } else if (inputElement.childElements != null) {
+ for (final InputElement childInputElement : inputElement.childElements) {
+ final InputElement recordInputElement = getRecordInputElement(childInputElement);
+ if (recordInputElement != null) {
+ return recordInputElement;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Extract a trace event from an XML element.
+ *
+ * @param element
+ * The element
+ * @param inputElement
+ * The input element
+ * @return The extracted event
+ */
+ public CustomXmlEvent extractEvent(final Element element, final InputElement inputElement) {
+ final CustomXmlEvent event = new CustomXmlEvent(fDefinition, this, TmfTimestamp.ZERO, "", fEventType,""); //$NON-NLS-1$ //$NON-NLS-2$
+ event.setContent(new CustomEventContent(event, new StringBuffer()));
+ parseElement(element, event, inputElement);
+ return event;
+ }
+
+ private void parseElement(final Element element, final CustomXmlEvent event, final InputElement inputElement) {
+ if (inputElement.inputName != null && !inputElement.inputName.equals(CustomXmlTraceDefinition.TAG_IGNORE)) {
+ event.parseInput(parseElement(element, new StringBuffer()).toString(), inputElement.inputName, inputElement.inputAction, inputElement.inputFormat);
+ }
+ if (inputElement.attributes != null) {
+ for (final InputAttribute attribute : inputElement.attributes) {
+ event.parseInput(element.getAttribute(attribute.attributeName), attribute.inputName, attribute.inputAction, attribute.inputFormat);
+ }
+ }
+ final NodeList childNodes = element.getChildNodes();
+ if (inputElement.childElements != null) {
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ final Node node = childNodes.item(i);
+ if (node instanceof Element) {
+ for (final InputElement child : inputElement.childElements) {
+ if (node.getNodeName().equals(child.elementName)) {
+ parseElement((Element) node, event, child);
+ break;
+ }
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ /**
+ * Retrieve the trace definition.
+ *
+ * @return The trace definition
+ */
+ public CustomTraceDefinition getDefinition() {
+ return fDefinition;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
+ */
+ @Override
+ public boolean validate(IProject project, String path) {
+ return fileExists(path);
+ }
+}