tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/decodeplugins/dictionary/DictionaryFileWriter.java
changeset 56 aa2539c91954
parent 41 838cdffd57ce
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/decodeplugins/dictionary/DictionaryFileWriter.java	Fri Oct 08 14:56:39 2010 +0300
@@ -0,0 +1,586 @@
+/*
+* Copyright (c) 2008-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:
+*
+* Writer for dictionary file
+*
+*/
+package com.nokia.tracecompiler.decodeplugins.dictionary;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+
+import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.DataType;
+import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.Dictionary;
+import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.LocationStore;
+import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TraceComponent;
+import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TraceDataStore;
+import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TraceDictionaryEncoder;
+import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TypeDef;
+import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TypeDefStore;
+import com.nokia.tracecompiler.engine.LocationListBase;
+import com.nokia.tracecompiler.engine.LocationProperties;
+import com.nokia.tracecompiler.file.FileUtils;
+import com.nokia.tracecompiler.model.Trace;
+import com.nokia.tracecompiler.model.TraceConstantTable;
+import com.nokia.tracecompiler.model.TraceConstantTableEntry;
+import com.nokia.tracecompiler.model.TraceGroup;
+import com.nokia.tracecompiler.model.TraceModel;
+import com.nokia.tracecompiler.model.TraceObjectUtils;
+import com.nokia.tracecompiler.model.TraceParameter;
+import com.nokia.tracecompiler.project.FormattingUtils;
+import com.nokia.tracecompiler.project.PropertyNames;
+import com.nokia.tracecompiler.project.TraceProjectAPI;
+import com.nokia.tracecompiler.project.TraceProjectAPI.TraceFormatFlags;
+import com.nokia.tracecompiler.rules.FillerParameterRule;
+import com.nokia.tracecompiler.rules.HiddenTraceObjectRule;
+import com.nokia.tracecompiler.source.SourceConstants;
+import com.nokia.tracecompiler.source.SourceUtils;
+
+/**
+ * Writer for dictionary file
+ * 
+ */
+final class DictionaryFileWriter {
+
+	/**
+	 * Comparator for file references
+	 */
+	private final class FileRefComparator implements
+			Comparator<DictionaryFileRef> {
+		public int compare(DictionaryFileRef o1, DictionaryFileRef o2) {
+			int val = o1.path.compareTo(o2.path);
+			if (val == 0) {
+				val = o1.file.compareTo(o2.file);
+			}
+			return val;
+		}
+	}
+
+	/**
+	 * Dictionary file
+	 */
+	private DictionaryFile dictionaryFile;
+
+	/**
+	 * Sequential number for trace definitions
+	 */
+	private int defref;
+
+	/**
+	 * Sequential number for file definitions
+	 */
+	private int fileref;
+
+	/**
+	 * Constructor
+	 * 
+	 * @param dictionaryFile
+	 *            the dictionary file
+	 */
+	DictionaryFileWriter(DictionaryFile dictionaryFile) {
+		this.dictionaryFile = dictionaryFile;
+	}
+
+	/**
+	 * Writes the dictionary file
+	 */
+	void write() {
+		defref = 0;
+		fileref = 0;
+		File file = new File(dictionaryFile.getAbsolutePathWithID());
+		// Delete removes possible read-only flags
+		if (file.exists()) {
+			file.delete();
+		}
+
+		TraceDictionaryEncoder encoder = new TraceDictionaryEncoder();
+		File path = file.getParentFile();
+		if (!path.exists()) {
+			FileUtils.createDirectories(path);
+		}
+		encoder.createNewDictionary(file.getAbsolutePath());
+		Dictionary.startDictionary();
+		createTypedefs();
+		createDefs();
+		createLocations();
+		createComponent();
+		Dictionary.endDictionary();
+	}
+
+	/**
+	 * Creates the type definitions
+	 */
+	private void createTypedefs() {
+		TypeDefStore.startTypeDefs();
+		ArrayList<String> typeList = buildTypeList();
+		writeTypeDefinitions(typeList);
+		TypeDefStore.endTypeDefs();
+	}
+
+	/**
+	 * Builds the list of parameter types
+	 * 
+	 * @return the list of types found from the model
+	 */
+	private ArrayList<String> buildTypeList() {
+		TraceModel model = dictionaryFile.getOwner().getModel();
+		ArrayList<String> typeList = new ArrayList<String>();
+		for (TraceGroup group : model) {
+			for (Trace trace : group) {
+				for (TraceParameter parameter : trace) {
+					if ((parameter.getExtension(HiddenTraceObjectRule.class) == null)
+							|| (parameter
+									.getExtension(FillerParameterRule.class) != null)) {
+						String type = parameter.getType();
+						if (!typeList.contains(type)) {
+							typeList.add(type);
+						}
+					}
+				}
+			}
+		}
+		return typeList;
+	}
+
+	/**
+	 * Writes the data type definitions
+	 * 
+	 * @param typeList
+	 *            the list of data types
+	 */
+	private void writeTypeDefinitions(ArrayList<String> typeList) {
+		for (String type : typeList) {
+			DataType dt = mapTypeToDataType(type);
+			if (dt != null) {
+				// Normal parameters
+				int size = mapParameterTypeToSize(type);
+				String formatChar = SourceUtils.mapNormalTypeToFormat(type);
+				if (formatChar != null && formatChar.length() > 1
+						&& formatChar.charAt(0) == '%') {
+					formatChar = formatChar.substring(1);
+					TypeDefStore.writeTypeDef(type, size, formatChar, dt);
+
+					// Write alternative format characters
+					writeAlternativeFormatChars(formatChar, type, size, dt);
+
+				} else {
+					TypeDefStore.writeTypeDef(type, size, null, dt);
+				}
+			} else {
+				// Enum parameters
+				TraceModel model = dictionaryFile.getOwner().getModel();
+				TraceConstantTable table = model.findConstantTableByName(type);
+				if (table != null) {
+					TypeDefStore.startTypeDef(table.getName(),
+							mapParameterTypeToSize(table.getType()), null,
+							DataType.ENUM);
+					for (TraceConstantTableEntry entry : table) {
+						TypeDef.writeTypeMember(entry.getID(), entry.getName(),
+								null);
+					}
+					TypeDefStore.endTypeDef();
+				}
+			}
+		}
+	}
+
+	/**
+	 * Writes alternative format characters to the Dictionary
+	 * 
+	 * @param formatChar
+	 *            formatchar
+	 * @param type
+	 *            parameter type
+	 * @param size
+	 *            parameter size
+	 * @param dt
+	 *            data type
+	 */
+	private void writeAlternativeFormatChars(String formatChar, String type,
+			int size, DataType dt) {
+
+		// If there's big L, write also 'll' type
+		if (formatChar.indexOf('L') != -1) {
+
+			// Double small l
+			String newFormatChar = formatChar.replace("L", "ll"); //$NON-NLS-1$ //$NON-NLS-2$
+			TypeDefStore.writeTypeDef(type, size, newFormatChar, dt);
+			writeCapitalHexType(newFormatChar, type, size, dt);
+
+		}
+
+		// Write alternative option to float types
+		else if (formatChar.equals("f") || formatChar.equals("e") //$NON-NLS-1$//$NON-NLS-2$
+				|| formatChar.equals("g")) { //$NON-NLS-1$
+
+			String newFormatChar = 'L' + formatChar;
+			TypeDefStore.writeTypeDef(type, size, newFormatChar, dt);
+		}
+
+		else {
+			// If length is one, add also formatchar with "l"
+			if (formatChar.length() == 1) {
+				String newFormatChar = "l" + formatChar; //$NON-NLS-1$
+				TypeDefStore.writeTypeDef(type, size, newFormatChar, dt);
+				writeCapitalHexType(newFormatChar, type, size, dt);
+			}
+
+			// Check capital hex need
+			writeCapitalHexType(formatChar, type, size, dt);
+		}
+	}
+
+	/**
+	 * Writes capital hex type
+	 * 
+	 * @param formatChar
+	 *            formatchar
+	 * @param type
+	 *            parameter type
+	 * @param size
+	 *            parameter size
+	 * @param dt
+	 *            data type
+	 */
+	private void writeCapitalHexType(String formatChar, String type, int size,
+			DataType dt) {
+
+		// Write also capital X if there are hex values
+		if (formatChar.indexOf('x') != -1) {
+			type = type.toUpperCase();
+			TypeDefStore.writeTypeDef(type, size, formatChar.replace('x', 'X'),
+					dt);
+		}
+	}
+
+	/**
+	 * Gets the parameter size from type
+	 * 
+	 * @param type
+	 *            the type
+	 * @return the size in bytes
+	 */
+	private int mapParameterTypeToSize(String type) {
+		int size = SourceUtils.mapParameterTypeToSize(type);
+		if (size == 0) {
+			if (type.equals(TraceParameter.ASCII)) {
+				size = 1;
+			} else if (type.equals(TraceParameter.UNICODE)) {
+				size = 2; // CodForChk_Dis_Magic
+			}
+		}
+		return size;
+	}
+
+	/**
+	 * Creates the trace definitions
+	 */
+	private void createDefs() {
+		// This should check for duplicates
+		TraceDataStore.startDataStore();
+		TraceModel model = dictionaryFile.getOwner().getModel();
+		TraceProjectAPI api = model.getExtension(TraceProjectAPI.class);
+		for (TraceGroup group : model) {
+			for (Trace trace : group) {
+				trace.addExtension(new DictionaryDefRef(++defref));
+				TraceFormatFlags flags = new TraceFormatFlags();
+				flags.isFormattingSupported = true;
+				String data = api.formatTraceForExport(trace, flags);
+				data = replaceUnescapeQuotes(data);
+				TraceDataStore.writeData(defref, DataType.STRING, data);
+			}
+		}
+		TraceDataStore.endDataStore();
+	}
+
+	/**
+	 * Replaces unescape quates
+	 * 
+	 * @param data
+	 *            the data
+	 * @return the new string
+	 */
+	private String replaceUnescapeQuotes(String data) {
+		data = data.replace("\\\"", "\""); //$NON-NLS-1$ //$NON-NLS-2$
+		return data;
+	}
+
+	/**
+	 * Maps a basic type to a Dictionary data type
+	 * 
+	 * @param type
+	 *            the type
+	 * @return the data type
+	 */
+	private DataType mapTypeToDataType(String type) { // CodForChk_Dis_ComplexFunc
+		DataType retval;
+		// Unsigned is not supported in Dictionary
+		if (type.equals(TraceParameter.SDEC32)) {
+			retval = DataType.INTEGER;
+		} else if (type.equals(TraceParameter.HEX32)) {
+			retval = DataType.HEX;
+		} else if (type.equals(TraceParameter.UDEC32)) {
+			retval = DataType.INTEGER;
+		} else if (type.equals(TraceParameter.OCT32)) {
+			retval = DataType.OCTAL;
+		} else if (type.equals(TraceParameter.SDEC16)) {
+			retval = DataType.INTEGER;
+		} else if (type.equals(TraceParameter.HEX16)) {
+			retval = DataType.HEX;
+		} else if (type.equals(TraceParameter.UDEC16)) {
+			retval = DataType.INTEGER;
+		} else if (type.equals(TraceParameter.OCT16)) {
+			retval = DataType.OCTAL;
+		} else if (type.equals(TraceParameter.SDEC8)) {
+			retval = DataType.INTEGER;
+		} else if (type.equals(TraceParameter.HEX8)) {
+			retval = DataType.HEX;
+		} else if (type.equals(TraceParameter.UDEC8)) {
+			retval = DataType.INTEGER;
+		} else if (type.equals(TraceParameter.OCT8)) {
+			retval = DataType.OCTAL;
+		} else if (type.equals(TraceParameter.SDEC64)) {
+			retval = DataType.INTEGER;
+		} else if (type.equals(TraceParameter.HEX64)) {
+			retval = DataType.HEX;
+		} else if (type.equals(TraceParameter.UDEC64)) {
+			retval = DataType.INTEGER;
+		} else if (type.equals(TraceParameter.OCT64)) {
+			retval = DataType.OCTAL;
+		} else if (type.equals(TraceParameter.ASCII)) {
+			retval = DataType.STRING;
+		} else if (type.equals(TraceParameter.UNICODE)) {
+			retval = DataType.STRING;
+		} else if (type.equals(TraceParameter.FLOAT_FIX)) {
+			retval = DataType.FLOAT;
+		} else if (type.equals(TraceParameter.FLOAT_EXP)) {
+			retval = DataType.FLOAT;
+		} else if (type.equals(TraceParameter.FLOAT_OPT)) {
+			retval = DataType.FLOAT;
+		} else if (type.equals(TraceParameter.POINTER)) {
+			retval = DataType.HEX;
+		} else {
+			retval = null;
+		}
+		return retval;
+	}
+
+	/**
+	 * Creates the location definitions
+	 */
+	private void createLocations() {
+		ArrayList<DictionaryFileRef> files = new ArrayList<DictionaryFileRef>();
+		LocationStore.startLocations();
+		for (TraceGroup group : dictionaryFile.getOwner().getModel()) {
+			for (Trace trace : group) {
+				writeLocation(files, trace);
+			}
+		}
+		// Build XML and assign ID's to refs
+		Collections.sort(files, new FileRefComparator());
+		String lastpath = null;
+		for (DictionaryFileRef ref : files) {
+			if (!ref.path.equals(lastpath)) {
+				if (lastpath != null) {
+					LocationStore.endPath();
+				}
+				LocationStore.startPath(ref.path);
+				lastpath = ref.path;
+			}
+			LocationStore.writeFile(++fileref, ref.file);
+			ref.refid = fileref;
+		}
+		if (lastpath != null) {
+			LocationStore.endPath();
+		}
+		LocationStore.endLocations();
+	}
+
+	/**
+	 * Writes the location of a trace
+	 * 
+	 * @param files
+	 *            file references
+	 * @param trace
+	 *            trace to be written
+	 */
+	private void writeLocation(ArrayList<DictionaryFileRef> files, Trace trace) {
+		LocationProperties loc = findFirstLocation(trace);
+		if (loc != null) {
+			String path = loc.getFilePath();
+			String file = loc.getFileName();
+			if (path != null) {
+				path = FileUtils.convertSeparators(
+						SourceConstants.FORWARD_SLASH_CHAR, path, true);
+				// TODO: Remove drive letter. Actually cannot remove drive
+				// letter because EPOCROOT might not be in the root of the drive
+			}
+			DictionaryFileRef ref = getRef(files, file, path);
+			if (ref == null) {
+				ref = new DictionaryFileRef(file, path, trace);
+				files.add(ref);
+				trace.addExtension(ref);
+			} else {
+				trace.addExtension(ref);
+			}
+		}
+	}
+
+	/**
+	 * Finds the first location from trace
+	 * 
+	 * @param trace
+	 *            the trace
+	 * @return the location
+	 */
+	private LocationProperties findFirstLocation(Trace trace) {
+		Iterator<LocationListBase> itr = trace
+				.getExtensions(LocationListBase.class);
+		LocationProperties loc = null;
+		while (itr.hasNext() && loc == null) {
+			Iterator<LocationProperties> locs = itr.next().iterator();
+			if (locs.hasNext()) {
+				loc = locs.next();
+			}
+		}
+		return loc;
+	}
+
+	/**
+	 * Gets a file reference
+	 * 
+	 * @param files
+	 *            the list of file references
+	 * @param file
+	 *            file name
+	 * @param path
+	 *            file path
+	 * @return the file reference
+	 */
+	private DictionaryFileRef getRef(ArrayList<DictionaryFileRef> files,
+			String file, String path) {
+		DictionaryFileRef retval = null;
+		for (int i = 0; i < files.size() && retval == null; i++) {
+			DictionaryFileRef ref = files.get(i);
+			if (ref.file.equals(file) && ref.path.equals(path)) {
+				retval = ref;
+			}
+		}
+		return retval;
+	}
+
+	/**
+	 * Creates the component definition
+	 */
+	private void createComponent() {
+		TraceModel model = dictionaryFile.getOwner().getModel();
+		int compid = model.getID();
+		// Component prefix and suffix are in property file.
+		// If not there, the default values are used
+		String prefix = TraceObjectUtils.findProperty(model,
+				PropertyNames.PREFIX);
+		if (prefix == null || prefix.length() == 0) {
+			prefix = FormattingUtils.getDefaultComponentPrefix(model);
+		}
+		String suffix = TraceObjectUtils.findProperty(model,
+				PropertyNames.SUFFIX);
+		if (suffix == null || suffix.length() == 0) {
+			suffix = FormattingUtils.getDefaultComponentSuffix(model);
+		}
+		Dictionary.startComponent(compid, dictionaryFile.getProjectName(),
+				prefix, suffix);
+		for (TraceGroup group : model) {
+			createGroup(group);
+		}
+		Dictionary.endComponent();
+	}
+
+	/**
+	 * Creates a group definition
+	 * 
+	 * @param group
+	 *            the group
+	 */
+	private void createGroup(TraceGroup group) {
+		String prefix = TraceObjectUtils.findProperty(group,
+				PropertyNames.PREFIX);
+		if (prefix == null || prefix.length() == 0) {
+			prefix = FormattingUtils.getDefaultGroupPrefix(group);
+		}
+		String suffix = TraceObjectUtils.findProperty(group,
+				PropertyNames.SUFFIX);
+		if (suffix == null || suffix.length() == 0) {
+			suffix = FormattingUtils.getDefaultGroupSuffix(group);
+		}
+		TraceComponent.startGroup(group.getID(), group.getName(), prefix,
+				suffix);
+		for (Trace trace : group) {
+			createTrace(trace);
+		}
+		TraceComponent.endGroup();
+	}
+
+	/**
+	 * Creates a trace definition
+	 * 
+	 * @param trace
+	 *            the trace
+	 */
+	private void createTrace(Trace trace) {
+		DictionaryDefRef defref = trace.getExtension(DictionaryDefRef.class);
+		if (defref != null) {
+			DictionaryFileRef fileref = trace
+					.getExtension(DictionaryFileRef.class);
+			com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TraceGroup.startTrace(defref
+					.getRefId(), trace.getName());
+			if (fileref != null) {
+				writeTraceWithLocation(fileref.getRefId(), trace);
+			} else {
+				com.nokia.tracecompiler.decodeplugins.dictionary.encoder.Trace.writeInstance(trace
+						.getID(), 0, 0, "", //$NON-NLS-1$
+						""); //$NON-NLS-1$
+			}
+			com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TraceGroup.endTrace();
+		}
+		trace.removeExtensions(DictionaryRef.class);
+
+	}
+
+	/**
+	 * Writes a trace which has a source location
+	 * 
+	 * @param refId
+	 *            file reference number
+	 * @param trace
+	 *            the trace
+	 */
+	private void writeTraceWithLocation(int refId, Trace trace) {
+		LocationProperties loc = findFirstLocation(trace);
+		int line = 0;
+		String className = ""; //$NON-NLS-1$
+		String functionName = ""; //$NON-NLS-1$
+		if (loc != null) {
+			line = loc.getLineNumber();
+			className = loc.getClassName();
+			functionName = loc.getFunctionName();
+		}
+		com.nokia.tracecompiler.decodeplugins.dictionary.encoder.Trace.writeInstance(trace.getID(),
+				refId, line, functionName, className);
+	}
+
+}