trace/traceviewer/com.nokia.trace.dictionary/src/com/nokia/trace/dictionary/model/handlers/DefHandler.java
author Matti Laitinen <matti.t.laitinen@nokia.com>
Wed, 23 Jun 2010 14:49:59 +0300
changeset 11 5b9d4d8641ce
permissions -rw-r--r--
TraceViewer 2.6.0

/*
 * Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). 
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of "Eclipse Public License v1.0"
 * which accompanies this distribution, and is available
 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
 *
 * Initial Contributors:
 * Nokia Corporation - initial contribution.
 *
 * Contributors:
 *
 * Description:
 *
 * Def handler
 *
 */
package com.nokia.trace.dictionary.model.handlers;

import org.xml.sax.Attributes;

import com.nokia.trace.dictionary.TraceDictionaryEngine;
import com.nokia.trace.dictionary.model.DecodeObject;
import com.nokia.trace.dictionary.model.DictionaryContentHandler;
import com.nokia.trace.dictionary.model.DictionaryDecodeModel;
import com.nokia.trace.dictionary.model.TraceData;
import com.nokia.trace.dictionary.model.decodeparameters.ArrayParameter;
import com.nokia.trace.dictionary.model.decodeparameters.ConstantParameter;
import com.nokia.trace.dictionary.model.decodeparameters.DecodeParameter;
import com.nokia.trace.dictionary.model.decodeparameters.HexParameter;
import com.nokia.trace.dictionary.model.decodeparameters.IntegerParameter;
import com.nokia.trace.eventrouter.TraceEvent;

/**
 * Def handler
 */
final class DefHandler extends BaseHandler {

	/**
	 * Tag name this handler handles
	 */
	private static final String DEF_TAG = "def"; //$NON-NLS-1$

	/**
	 * Bytes in block
	 */
	private int bytesInBlock;

	/**
	 * Constructor
	 * 
	 * @param model
	 *            the model
	 */
	DefHandler(DictionaryDecodeModel model) {
		super(model, DEF_TAG);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.trace.dictionary.model.handlers.BaseHandler#
	 * processStartElement(org.xml.sax.Attributes,
	 * com.nokia.trace.dictionary.model.DictionaryContentHandler)
	 */
	@Override
	public void processStartElement(Attributes atts,
			DictionaryContentHandler handler) {
		TraceData traceData = new TraceData(
				Integer.parseInt(atts.getValue(ID)), atts.getValue(TYPE));
		handler.catchElementContents(traceData);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.nokia.trace.dictionary.model.handlers.BaseHandler#processEndElement
	 * (java.lang.StringBuffer, java.lang.Object,
	 * com.nokia.trace.dictionary.model.DictionaryContentHandler,
	 * com.nokia.trace.dictionary.model.DecodeObject)
	 */
	@Override
	public void processEndElement(StringBuffer elementContent,
			Object unFinishedObject, DictionaryContentHandler handler,
			DecodeObject parentObject) {

		TraceData traceData = (TraceData) unFinishedObject;

		// Check if there is only one variable in the trace. If
		// split has two parts, there is only one variable indicator
		if (elementContent.toString().split(VARIABLE_INDICATOR).length <= 2) {
			traceData.setContainsOnlyOneVariable(true);
		}

		int startOffset = 0;
		int foundOffset = 0;
		int endOffset = 0;

		// Search all variables from the string
		while ((foundOffset = elementContent.indexOf(VARIABLE_INDICATOR,
				startOffset)) != -1) {
			createConstantParameter(elementContent, traceData, startOffset,
					foundOffset);

			String parameterType;
			StringBuilder digitsSB = new StringBuilder();
			boolean isArray = false;

			int nextCharOffset = foundOffset + 1;

			// First gather all possible digits to variable. e.g. from %02x
			// gather 02
			char c = elementContent.charAt(nextCharOffset);
			while (Character.isDigit(c)) {
				digitsSB.append(c);
				nextCharOffset++;
				c = elementContent.charAt(nextCharOffset);
			}

			// Check if next char is {
			if (c == START_BRACKET) {
				// Find offset of char }
				endOffset = elementContent.indexOf(Character
						.toString(END_BRACKET), foundOffset) + 1;

				// End offset was not found,let's change it to end of whole
				// string to get some reasonable error message
				if (endOffset == 0) {
					endOffset = elementContent.length();
				}

				// Try to find array indicator characters
				int indexOfBrackets = elementContent.indexOf(ARRAY_INDICATOR,
						nextCharOffset);
				// Indicator is found and is inside this parameter -> array
				if (indexOfBrackets != -1
						&& indexOfBrackets + ARRAY_INDICATOR.length() < endOffset) {
					isArray = true;
				}

				// Parse from between
				parameterType = elementContent.substring(nextCharOffset,
						endOffset);

				// Next char is not {, so it's a format char
			} else {

				// If the first char is L, l, or h, format char has 2 or 3 chars
				if (c == FORMATCHAR_INDICATOR_BIG_L
						|| c == FORMATCHAR_INDICATOR_SMALL_L
						|| c == FORMATCHAR_INDICATOR_H) {
					c = elementContent.charAt(nextCharOffset + 1);

					// Next char is also h or l, format char is 3 chars
					if (c == FORMATCHAR_INDICATOR_H
							|| c == FORMATCHAR_INDICATOR_SMALL_L) {
						parameterType = elementContent.substring(
								nextCharOffset, nextCharOffset
										+ LONG_FORMATCHAR_LENGTH + 1);
						endOffset = nextCharOffset + LONG_FORMATCHAR_LENGTH + 1;

						// Format char is 2 chars
					} else {
						parameterType = elementContent.substring(
								nextCharOffset, nextCharOffset
										+ LONG_FORMATCHAR_LENGTH);
						endOffset = nextCharOffset + LONG_FORMATCHAR_LENGTH;
					}

					// Only 1 char
				} else {
					parameterType = elementContent.substring(nextCharOffset,
							nextCharOffset + SHORT_FORMATCHAR_LENGTH);
					endOffset = nextCharOffset + SHORT_FORMATCHAR_LENGTH;
				}
			}

			DecodeParameter parameter;

			// Array parameter
			if (isArray) {
				parameter = handleArray(traceData, parameterType, digitsSB
						.toString());

				// Normal parameter
			} else {
				parameter = getDecodeParameter(parameterType, digitsSB
						.toString());

				if (parameter != null) {
					// Add possible fillers before this new parameter
					addFillers(traceData, parameter.getSize());

					// Add to the parameter list
					traceData.addDecodeParameter(parameter);
				}
			}

			// Parameter couldn't be found or created, inform user
			if (parameter == null) {
				postParameterNotFoundMsg(handler, parameterType);
			}

			// Set start offset to previous end offset
			startOffset = endOffset;
		} // while ends

		// Create constant from the remaining
		createConstantParameter(elementContent, traceData, startOffset,
				elementContent.length());

		// Add trace data to model
		model.addTraceData(traceData);

		// Null bytes in block value afterwards
		bytesInBlock = 0;
	}

	/**
	 * Handles array
	 * 
	 * @param traceData
	 *            trace data
	 * @param parameterType
	 *            parameter type
	 * @param digits
	 * @return created parameter or null if cannot be created
	 */
	private DecodeParameter handleArray(TraceData traceData,
			String parameterType, String digits) {
		DecodeParameter parameter = null;

		// Remove array indicator and try decode parameter again
		String arrayContainsStr = parameterType.replace(ARRAY_INDICATOR, ""); //$NON-NLS-1$
		DecodeParameter arrayContains = getDecodeParameter(arrayContainsStr,
				digits);

		// Basic type is found, create array parameter and add it
		// also to the model and to the trace parameter list
		if (arrayContains != null) {
			parameter = new ArrayParameter(parameterType, false, arrayContains);

			model.addDecodeParameter(parameter);
			traceData.addDecodeParameter(parameter);
		}

		return parameter;
	}

	/**
	 * Gets (either from model or creates new) decode parameter
	 * 
	 * @param parameterType
	 *            parameter type to be get
	 * @param digits
	 *            possible format digits
	 * @return found or new decode parameter or null if not found
	 */
	private DecodeParameter getDecodeParameter(String parameterType,
			String digits) {
		String parameterWithFormat = digits + parameterType;

		// Find from parameter list using the possible formatting (e.g. %02)
		DecodeParameter parameter = model
				.getDecodeParameter(parameterWithFormat);

		// Not found, try to find without the formatting
		if (parameter == null) {
			parameter = model.getDecodeParameter(parameterType);

			// If found, we need to create new decode parameter with the
			// formatting included
			if (parameter != null) {
				parameter = createNewFormatDecodeParameter(parameter,
						parameterWithFormat, digits);
			}
		}

		return parameter;
	}

	/**
	 * Create new decode parameter with formatting
	 * 
	 * @param oldParameter
	 *            old parameter
	 * @param parameterWithFormat
	 *            new parameter name
	 * @param digits
	 *            how should the parameter be formatted
	 * @return new decode parameter
	 */
	private DecodeParameter createNewFormatDecodeParameter(
			DecodeParameter oldParameter, String parameterWithFormat,
			String digits) {
		DecodeParameter newParameter = null;

		// This is already checked with "isDigit()" so doesn't need try catch
		int digit = Integer.parseInt(digits);

		// Integer parameter
		if (oldParameter instanceof IntegerParameter) {
			newParameter = new IntegerParameter(parameterWithFormat, false,
					oldParameter.getSize(), true);
			((IntegerParameter) newParameter).setFormatToChars(digit);
		}

		// Hex parameter
		else if (oldParameter instanceof HexParameter) {
			newParameter = new HexParameter(parameterWithFormat, false,
					oldParameter.getSize());
			((HexParameter) newParameter)
					.setPrintInUpperCase(((HexParameter) oldParameter)
							.getPrintInUpperCase());
			((HexParameter) newParameter).setFormatToChars(digit);
		}

		// Add to the parameter list
		if (newParameter != null) {
			model.addDecodeParameter(newParameter);
		}

		return newParameter;
	}

	/**
	 * Posts parameter not found message to user
	 * 
	 * @param handler
	 *            Dictionary handler
	 * @param parameterType
	 *            parameter type that is not found
	 */
	private void postParameterNotFoundMsg(DictionaryContentHandler handler,
			String parameterType) {
		String parameterNotFound = Messages
				.getString("DefHandler.ParameterNotFoundMsg"); //$NON-NLS-1$
		TraceEvent event = new TraceEvent(TraceEvent.ERROR, parameterNotFound
				+ parameterType);
		event.setCategory(EVENT_CATEGORY);
		event.setSource(Integer.valueOf(handler.getLocator().getLineNumber()));
		TraceDictionaryEngine.postEvent(event);
	}

	/**
	 * Adds possible filler parameters to traceData
	 * 
	 * @param traceData
	 *            traceData
	 * @param paramSize
	 *            size of the new item
	 */
	private void addFillers(TraceData traceData, int paramSize) {
		// Parameters are aligned to 32 bits. Parameter after
		// end-of-string is aligned dynamically and thus no filler is
		// created for it
		if (paramSize == 0 || paramSize == 4 || paramSize == 8) {
			if (bytesInBlock > 0) {
				int fillerCount = 4 - bytesInBlock;
				for (int i = 0; i < fillerCount; i++) {
					traceData.addDecodeParameter(model.getFillerParameter());
				}
				bytesInBlock = 0;
			}
		} else if (paramSize == 2) {
			if (bytesInBlock == 1 || bytesInBlock == 3) {
				traceData.addDecodeParameter(model.getFillerParameter());
				// If there was 1 existing byte and filler was added,
				// the number of bytes in the block is now 4 including
				// the 2-byte parameter. If there was 3 bytes, the
				// filler brings it to 4 and the 16-bit parameter
				// changes it to 2
				bytesInBlock += 3;
			} else {
				bytesInBlock += 2;
			}
			if (bytesInBlock >= 4) {
				bytesInBlock -= 4;
			}
		} else {
			bytesInBlock++;
			if (bytesInBlock == 4) {
				bytesInBlock = 0;
			}
		}
	}

	/**
	 * Create constant parameter
	 * 
	 * @param elementContent
	 *            buffer where data is
	 * @param traceData
	 *            TraceData where to insert this parameter
	 * @param startOffset
	 *            start offset from buffer
	 * @param endOffset
	 *            end offset from buffer
	 */
	private void createConstantParameter(StringBuffer elementContent,
			TraceData traceData, int startOffset, int endOffset) {

		// Remove line breaks from the buffer
		int len = elementContent.length();
		for (int i = 0; i < len; i++) {
			char c = elementContent.charAt(i);
			if (c == '\n' || c == '\r') {
				elementContent.setCharAt(i, ' ');
			}
		}

		// First create constant parameter
		String constantPar = elementContent.substring(startOffset, endOffset);
		if (constantPar.length() > 0) {
			// Try to find from the list
			ConstantParameter parameter = model
					.getConstantParameter(constantPar);

			// Couldn't be found
			if (parameter == null) {
				parameter = new ConstantParameter(constantPar, false);
			}

			// Add to lists
			traceData.addDecodeParameter(parameter);
			model.addConstantParameter(parameter);
		}
	}

}