|
1 /* |
|
2 * Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 * Writer for dictionary file |
|
17 * |
|
18 */ |
|
19 package com.nokia.tracecompiler.decodeplugins.dictionary; |
|
20 |
|
21 import java.io.File; |
|
22 import java.util.ArrayList; |
|
23 import java.util.Collections; |
|
24 import java.util.Comparator; |
|
25 import java.util.Iterator; |
|
26 |
|
27 import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.DataType; |
|
28 import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.Dictionary; |
|
29 import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.LocationStore; |
|
30 import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TraceComponent; |
|
31 import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TraceDataStore; |
|
32 import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TraceDictionaryEncoder; |
|
33 import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TypeDef; |
|
34 import com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TypeDefStore; |
|
35 import com.nokia.tracecompiler.engine.LocationListBase; |
|
36 import com.nokia.tracecompiler.engine.LocationProperties; |
|
37 import com.nokia.tracecompiler.file.FileUtils; |
|
38 import com.nokia.tracecompiler.model.Trace; |
|
39 import com.nokia.tracecompiler.model.TraceConstantTable; |
|
40 import com.nokia.tracecompiler.model.TraceConstantTableEntry; |
|
41 import com.nokia.tracecompiler.model.TraceGroup; |
|
42 import com.nokia.tracecompiler.model.TraceModel; |
|
43 import com.nokia.tracecompiler.model.TraceObjectUtils; |
|
44 import com.nokia.tracecompiler.model.TraceParameter; |
|
45 import com.nokia.tracecompiler.project.FormattingUtils; |
|
46 import com.nokia.tracecompiler.project.PropertyNames; |
|
47 import com.nokia.tracecompiler.project.TraceProjectAPI; |
|
48 import com.nokia.tracecompiler.project.TraceProjectAPI.TraceFormatFlags; |
|
49 import com.nokia.tracecompiler.rules.FillerParameterRule; |
|
50 import com.nokia.tracecompiler.rules.HiddenTraceObjectRule; |
|
51 import com.nokia.tracecompiler.source.SourceConstants; |
|
52 import com.nokia.tracecompiler.source.SourceUtils; |
|
53 |
|
54 /** |
|
55 * Writer for dictionary file |
|
56 * |
|
57 */ |
|
58 final class DictionaryFileWriter { |
|
59 |
|
60 /** |
|
61 * Comparator for file references |
|
62 */ |
|
63 private final class FileRefComparator implements |
|
64 Comparator<DictionaryFileRef> { |
|
65 public int compare(DictionaryFileRef o1, DictionaryFileRef o2) { |
|
66 int val = o1.path.compareTo(o2.path); |
|
67 if (val == 0) { |
|
68 val = o1.file.compareTo(o2.file); |
|
69 } |
|
70 return val; |
|
71 } |
|
72 } |
|
73 |
|
74 /** |
|
75 * Dictionary file |
|
76 */ |
|
77 private DictionaryFile dictionaryFile; |
|
78 |
|
79 /** |
|
80 * Sequential number for trace definitions |
|
81 */ |
|
82 private int defref; |
|
83 |
|
84 /** |
|
85 * Sequential number for file definitions |
|
86 */ |
|
87 private int fileref; |
|
88 |
|
89 /** |
|
90 * Constructor |
|
91 * |
|
92 * @param dictionaryFile |
|
93 * the dictionary file |
|
94 */ |
|
95 DictionaryFileWriter(DictionaryFile dictionaryFile) { |
|
96 this.dictionaryFile = dictionaryFile; |
|
97 } |
|
98 |
|
99 /** |
|
100 * Writes the dictionary file |
|
101 */ |
|
102 void write() { |
|
103 defref = 0; |
|
104 fileref = 0; |
|
105 File file = new File(dictionaryFile.getAbsolutePathWithID()); |
|
106 // Delete removes possible read-only flags |
|
107 if (file.exists()) { |
|
108 file.delete(); |
|
109 } |
|
110 |
|
111 TraceDictionaryEncoder encoder = new TraceDictionaryEncoder(); |
|
112 File path = file.getParentFile(); |
|
113 if (!path.exists()) { |
|
114 FileUtils.createDirectories(path); |
|
115 } |
|
116 encoder.createNewDictionary(file.getAbsolutePath()); |
|
117 Dictionary.startDictionary(); |
|
118 createTypedefs(); |
|
119 createDefs(); |
|
120 createLocations(); |
|
121 createComponent(); |
|
122 Dictionary.endDictionary(); |
|
123 } |
|
124 |
|
125 /** |
|
126 * Creates the type definitions |
|
127 */ |
|
128 private void createTypedefs() { |
|
129 TypeDefStore.startTypeDefs(); |
|
130 ArrayList<String> typeList = buildTypeList(); |
|
131 writeTypeDefinitions(typeList); |
|
132 TypeDefStore.endTypeDefs(); |
|
133 } |
|
134 |
|
135 /** |
|
136 * Builds the list of parameter types |
|
137 * |
|
138 * @return the list of types found from the model |
|
139 */ |
|
140 private ArrayList<String> buildTypeList() { |
|
141 TraceModel model = dictionaryFile.getOwner().getModel(); |
|
142 ArrayList<String> typeList = new ArrayList<String>(); |
|
143 for (TraceGroup group : model) { |
|
144 for (Trace trace : group) { |
|
145 for (TraceParameter parameter : trace) { |
|
146 if ((parameter.getExtension(HiddenTraceObjectRule.class) == null) |
|
147 || (parameter |
|
148 .getExtension(FillerParameterRule.class) != null)) { |
|
149 String type = parameter.getType(); |
|
150 if (!typeList.contains(type)) { |
|
151 typeList.add(type); |
|
152 } |
|
153 } |
|
154 } |
|
155 } |
|
156 } |
|
157 return typeList; |
|
158 } |
|
159 |
|
160 /** |
|
161 * Writes the data type definitions |
|
162 * |
|
163 * @param typeList |
|
164 * the list of data types |
|
165 */ |
|
166 private void writeTypeDefinitions(ArrayList<String> typeList) { |
|
167 for (String type : typeList) { |
|
168 DataType dt = mapTypeToDataType(type); |
|
169 if (dt != null) { |
|
170 // Normal parameters |
|
171 int size = mapParameterTypeToSize(type); |
|
172 String formatChar = SourceUtils.mapNormalTypeToFormat(type); |
|
173 if (formatChar != null && formatChar.length() > 1 |
|
174 && formatChar.charAt(0) == '%') { |
|
175 formatChar = formatChar.substring(1); |
|
176 TypeDefStore.writeTypeDef(type, size, formatChar, dt); |
|
177 |
|
178 // Write alternative format characters |
|
179 writeAlternativeFormatChars(formatChar, type, size, dt); |
|
180 |
|
181 } else { |
|
182 TypeDefStore.writeTypeDef(type, size, null, dt); |
|
183 } |
|
184 } else { |
|
185 // Enum parameters |
|
186 TraceModel model = dictionaryFile.getOwner().getModel(); |
|
187 TraceConstantTable table = model.findConstantTableByName(type); |
|
188 if (table != null) { |
|
189 TypeDefStore.startTypeDef(table.getName(), |
|
190 mapParameterTypeToSize(table.getType()), null, |
|
191 DataType.ENUM); |
|
192 for (TraceConstantTableEntry entry : table) { |
|
193 TypeDef.writeTypeMember(entry.getID(), entry.getName(), |
|
194 null); |
|
195 } |
|
196 TypeDefStore.endTypeDef(); |
|
197 } |
|
198 } |
|
199 } |
|
200 } |
|
201 |
|
202 /** |
|
203 * Writes alternative format characters to the Dictionary |
|
204 * |
|
205 * @param formatChar |
|
206 * formatchar |
|
207 * @param type |
|
208 * parameter type |
|
209 * @param size |
|
210 * parameter size |
|
211 * @param dt |
|
212 * data type |
|
213 */ |
|
214 private void writeAlternativeFormatChars(String formatChar, String type, |
|
215 int size, DataType dt) { |
|
216 |
|
217 // If there's big L, write also 'll' type |
|
218 if (formatChar.indexOf('L') != -1) { |
|
219 |
|
220 // Double small l |
|
221 String newFormatChar = formatChar.replace("L", "ll"); //$NON-NLS-1$ //$NON-NLS-2$ |
|
222 TypeDefStore.writeTypeDef(type, size, newFormatChar, dt); |
|
223 writeCapitalHexType(newFormatChar, type, size, dt); |
|
224 |
|
225 } |
|
226 |
|
227 // Write alternative option to float types |
|
228 else if (formatChar.equals("f") || formatChar.equals("e") //$NON-NLS-1$//$NON-NLS-2$ |
|
229 || formatChar.equals("g")) { //$NON-NLS-1$ |
|
230 |
|
231 String newFormatChar = 'L' + formatChar; |
|
232 TypeDefStore.writeTypeDef(type, size, newFormatChar, dt); |
|
233 } |
|
234 |
|
235 else { |
|
236 // If length is one, add also formatchar with "l" |
|
237 if (formatChar.length() == 1) { |
|
238 String newFormatChar = "l" + formatChar; //$NON-NLS-1$ |
|
239 TypeDefStore.writeTypeDef(type, size, newFormatChar, dt); |
|
240 writeCapitalHexType(newFormatChar, type, size, dt); |
|
241 } |
|
242 |
|
243 // Check capital hex need |
|
244 writeCapitalHexType(formatChar, type, size, dt); |
|
245 } |
|
246 } |
|
247 |
|
248 /** |
|
249 * Writes capital hex type |
|
250 * |
|
251 * @param formatChar |
|
252 * formatchar |
|
253 * @param type |
|
254 * parameter type |
|
255 * @param size |
|
256 * parameter size |
|
257 * @param dt |
|
258 * data type |
|
259 */ |
|
260 private void writeCapitalHexType(String formatChar, String type, int size, |
|
261 DataType dt) { |
|
262 |
|
263 // Write also capital X if there are hex values |
|
264 if (formatChar.indexOf('x') != -1) { |
|
265 type = type.toUpperCase(); |
|
266 TypeDefStore.writeTypeDef(type, size, formatChar.replace('x', 'X'), |
|
267 dt); |
|
268 } |
|
269 } |
|
270 |
|
271 /** |
|
272 * Gets the parameter size from type |
|
273 * |
|
274 * @param type |
|
275 * the type |
|
276 * @return the size in bytes |
|
277 */ |
|
278 private int mapParameterTypeToSize(String type) { |
|
279 int size = SourceUtils.mapParameterTypeToSize(type); |
|
280 if (size == 0) { |
|
281 if (type.equals(TraceParameter.ASCII)) { |
|
282 size = 1; |
|
283 } else if (type.equals(TraceParameter.UNICODE)) { |
|
284 size = 2; // CodForChk_Dis_Magic |
|
285 } |
|
286 } |
|
287 return size; |
|
288 } |
|
289 |
|
290 /** |
|
291 * Creates the trace definitions |
|
292 */ |
|
293 private void createDefs() { |
|
294 // This should check for duplicates |
|
295 TraceDataStore.startDataStore(); |
|
296 TraceModel model = dictionaryFile.getOwner().getModel(); |
|
297 TraceProjectAPI api = model.getExtension(TraceProjectAPI.class); |
|
298 for (TraceGroup group : model) { |
|
299 for (Trace trace : group) { |
|
300 trace.addExtension(new DictionaryDefRef(++defref)); |
|
301 TraceFormatFlags flags = new TraceFormatFlags(); |
|
302 flags.isFormattingSupported = true; |
|
303 String data = api.formatTraceForExport(trace, flags); |
|
304 data = replaceUnescapeQuotes(data); |
|
305 TraceDataStore.writeData(defref, DataType.STRING, data); |
|
306 } |
|
307 } |
|
308 TraceDataStore.endDataStore(); |
|
309 } |
|
310 |
|
311 /** |
|
312 * Replaces unescape quates |
|
313 * |
|
314 * @param data |
|
315 * the data |
|
316 * @return the new string |
|
317 */ |
|
318 private String replaceUnescapeQuotes(String data) { |
|
319 data = data.replace("\\\"", "\""); //$NON-NLS-1$ //$NON-NLS-2$ |
|
320 return data; |
|
321 } |
|
322 |
|
323 /** |
|
324 * Maps a basic type to a Dictionary data type |
|
325 * |
|
326 * @param type |
|
327 * the type |
|
328 * @return the data type |
|
329 */ |
|
330 private DataType mapTypeToDataType(String type) { // CodForChk_Dis_ComplexFunc |
|
331 DataType retval; |
|
332 // Unsigned is not supported in Dictionary |
|
333 if (type.equals(TraceParameter.SDEC32)) { |
|
334 retval = DataType.INTEGER; |
|
335 } else if (type.equals(TraceParameter.HEX32)) { |
|
336 retval = DataType.HEX; |
|
337 } else if (type.equals(TraceParameter.UDEC32)) { |
|
338 retval = DataType.INTEGER; |
|
339 } else if (type.equals(TraceParameter.OCT32)) { |
|
340 retval = DataType.OCTAL; |
|
341 } else if (type.equals(TraceParameter.SDEC16)) { |
|
342 retval = DataType.INTEGER; |
|
343 } else if (type.equals(TraceParameter.HEX16)) { |
|
344 retval = DataType.HEX; |
|
345 } else if (type.equals(TraceParameter.UDEC16)) { |
|
346 retval = DataType.INTEGER; |
|
347 } else if (type.equals(TraceParameter.OCT16)) { |
|
348 retval = DataType.OCTAL; |
|
349 } else if (type.equals(TraceParameter.SDEC8)) { |
|
350 retval = DataType.INTEGER; |
|
351 } else if (type.equals(TraceParameter.HEX8)) { |
|
352 retval = DataType.HEX; |
|
353 } else if (type.equals(TraceParameter.UDEC8)) { |
|
354 retval = DataType.INTEGER; |
|
355 } else if (type.equals(TraceParameter.OCT8)) { |
|
356 retval = DataType.OCTAL; |
|
357 } else if (type.equals(TraceParameter.SDEC64)) { |
|
358 retval = DataType.INTEGER; |
|
359 } else if (type.equals(TraceParameter.HEX64)) { |
|
360 retval = DataType.HEX; |
|
361 } else if (type.equals(TraceParameter.UDEC64)) { |
|
362 retval = DataType.INTEGER; |
|
363 } else if (type.equals(TraceParameter.OCT64)) { |
|
364 retval = DataType.OCTAL; |
|
365 } else if (type.equals(TraceParameter.ASCII)) { |
|
366 retval = DataType.STRING; |
|
367 } else if (type.equals(TraceParameter.UNICODE)) { |
|
368 retval = DataType.STRING; |
|
369 } else if (type.equals(TraceParameter.FLOAT_FIX)) { |
|
370 retval = DataType.FLOAT; |
|
371 } else if (type.equals(TraceParameter.FLOAT_EXP)) { |
|
372 retval = DataType.FLOAT; |
|
373 } else if (type.equals(TraceParameter.FLOAT_OPT)) { |
|
374 retval = DataType.FLOAT; |
|
375 } else if (type.equals(TraceParameter.POINTER)) { |
|
376 retval = DataType.HEX; |
|
377 } else { |
|
378 retval = null; |
|
379 } |
|
380 return retval; |
|
381 } |
|
382 |
|
383 /** |
|
384 * Creates the location definitions |
|
385 */ |
|
386 private void createLocations() { |
|
387 ArrayList<DictionaryFileRef> files = new ArrayList<DictionaryFileRef>(); |
|
388 LocationStore.startLocations(); |
|
389 for (TraceGroup group : dictionaryFile.getOwner().getModel()) { |
|
390 for (Trace trace : group) { |
|
391 writeLocation(files, trace); |
|
392 } |
|
393 } |
|
394 // Build XML and assign ID's to refs |
|
395 Collections.sort(files, new FileRefComparator()); |
|
396 String lastpath = null; |
|
397 for (DictionaryFileRef ref : files) { |
|
398 if (!ref.path.equals(lastpath)) { |
|
399 if (lastpath != null) { |
|
400 LocationStore.endPath(); |
|
401 } |
|
402 LocationStore.startPath(ref.path); |
|
403 lastpath = ref.path; |
|
404 } |
|
405 LocationStore.writeFile(++fileref, ref.file); |
|
406 ref.refid = fileref; |
|
407 } |
|
408 if (lastpath != null) { |
|
409 LocationStore.endPath(); |
|
410 } |
|
411 LocationStore.endLocations(); |
|
412 } |
|
413 |
|
414 /** |
|
415 * Writes the location of a trace |
|
416 * |
|
417 * @param files |
|
418 * file references |
|
419 * @param trace |
|
420 * trace to be written |
|
421 */ |
|
422 private void writeLocation(ArrayList<DictionaryFileRef> files, Trace trace) { |
|
423 LocationProperties loc = findFirstLocation(trace); |
|
424 if (loc != null) { |
|
425 String path = loc.getFilePath(); |
|
426 String file = loc.getFileName(); |
|
427 if (path != null) { |
|
428 path = FileUtils.convertSeparators( |
|
429 SourceConstants.FORWARD_SLASH_CHAR, path, true); |
|
430 // TODO: Remove drive letter. Actually cannot remove drive |
|
431 // letter because EPOCROOT might not be in the root of the drive |
|
432 } |
|
433 DictionaryFileRef ref = getRef(files, file, path); |
|
434 if (ref == null) { |
|
435 ref = new DictionaryFileRef(file, path, trace); |
|
436 files.add(ref); |
|
437 trace.addExtension(ref); |
|
438 } else { |
|
439 trace.addExtension(ref); |
|
440 } |
|
441 } |
|
442 } |
|
443 |
|
444 /** |
|
445 * Finds the first location from trace |
|
446 * |
|
447 * @param trace |
|
448 * the trace |
|
449 * @return the location |
|
450 */ |
|
451 private LocationProperties findFirstLocation(Trace trace) { |
|
452 Iterator<LocationListBase> itr = trace |
|
453 .getExtensions(LocationListBase.class); |
|
454 LocationProperties loc = null; |
|
455 while (itr.hasNext() && loc == null) { |
|
456 Iterator<LocationProperties> locs = itr.next().iterator(); |
|
457 if (locs.hasNext()) { |
|
458 loc = locs.next(); |
|
459 } |
|
460 } |
|
461 return loc; |
|
462 } |
|
463 |
|
464 /** |
|
465 * Gets a file reference |
|
466 * |
|
467 * @param files |
|
468 * the list of file references |
|
469 * @param file |
|
470 * file name |
|
471 * @param path |
|
472 * file path |
|
473 * @return the file reference |
|
474 */ |
|
475 private DictionaryFileRef getRef(ArrayList<DictionaryFileRef> files, |
|
476 String file, String path) { |
|
477 DictionaryFileRef retval = null; |
|
478 for (int i = 0; i < files.size() && retval == null; i++) { |
|
479 DictionaryFileRef ref = files.get(i); |
|
480 if (ref.file.equals(file) && ref.path.equals(path)) { |
|
481 retval = ref; |
|
482 } |
|
483 } |
|
484 return retval; |
|
485 } |
|
486 |
|
487 /** |
|
488 * Creates the component definition |
|
489 */ |
|
490 private void createComponent() { |
|
491 TraceModel model = dictionaryFile.getOwner().getModel(); |
|
492 int compid = model.getID(); |
|
493 // Component prefix and suffix are in property file. |
|
494 // If not there, the default values are used |
|
495 String prefix = TraceObjectUtils.findProperty(model, |
|
496 PropertyNames.PREFIX); |
|
497 if (prefix == null || prefix.length() == 0) { |
|
498 prefix = FormattingUtils.getDefaultComponentPrefix(model); |
|
499 } |
|
500 String suffix = TraceObjectUtils.findProperty(model, |
|
501 PropertyNames.SUFFIX); |
|
502 if (suffix == null || suffix.length() == 0) { |
|
503 suffix = FormattingUtils.getDefaultComponentSuffix(model); |
|
504 } |
|
505 Dictionary.startComponent(compid, dictionaryFile.getProjectName(), |
|
506 prefix, suffix); |
|
507 for (TraceGroup group : model) { |
|
508 createGroup(group); |
|
509 } |
|
510 Dictionary.endComponent(); |
|
511 } |
|
512 |
|
513 /** |
|
514 * Creates a group definition |
|
515 * |
|
516 * @param group |
|
517 * the group |
|
518 */ |
|
519 private void createGroup(TraceGroup group) { |
|
520 String prefix = TraceObjectUtils.findProperty(group, |
|
521 PropertyNames.PREFIX); |
|
522 if (prefix == null || prefix.length() == 0) { |
|
523 prefix = FormattingUtils.getDefaultGroupPrefix(group); |
|
524 } |
|
525 String suffix = TraceObjectUtils.findProperty(group, |
|
526 PropertyNames.SUFFIX); |
|
527 if (suffix == null || suffix.length() == 0) { |
|
528 suffix = FormattingUtils.getDefaultGroupSuffix(group); |
|
529 } |
|
530 TraceComponent.startGroup(group.getID(), group.getName(), prefix, |
|
531 suffix); |
|
532 for (Trace trace : group) { |
|
533 createTrace(trace); |
|
534 } |
|
535 TraceComponent.endGroup(); |
|
536 } |
|
537 |
|
538 /** |
|
539 * Creates a trace definition |
|
540 * |
|
541 * @param trace |
|
542 * the trace |
|
543 */ |
|
544 private void createTrace(Trace trace) { |
|
545 DictionaryDefRef defref = trace.getExtension(DictionaryDefRef.class); |
|
546 if (defref != null) { |
|
547 DictionaryFileRef fileref = trace |
|
548 .getExtension(DictionaryFileRef.class); |
|
549 com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TraceGroup.startTrace(defref |
|
550 .getRefId(), trace.getName()); |
|
551 if (fileref != null) { |
|
552 writeTraceWithLocation(fileref.getRefId(), trace); |
|
553 } else { |
|
554 com.nokia.tracecompiler.decodeplugins.dictionary.encoder.Trace.writeInstance(trace |
|
555 .getID(), 0, 0, "", //$NON-NLS-1$ |
|
556 ""); //$NON-NLS-1$ |
|
557 } |
|
558 com.nokia.tracecompiler.decodeplugins.dictionary.encoder.TraceGroup.endTrace(); |
|
559 } |
|
560 trace.removeExtensions(DictionaryRef.class); |
|
561 |
|
562 } |
|
563 |
|
564 /** |
|
565 * Writes a trace which has a source location |
|
566 * |
|
567 * @param refId |
|
568 * file reference number |
|
569 * @param trace |
|
570 * the trace |
|
571 */ |
|
572 private void writeTraceWithLocation(int refId, Trace trace) { |
|
573 LocationProperties loc = findFirstLocation(trace); |
|
574 int line = 0; |
|
575 String className = ""; //$NON-NLS-1$ |
|
576 String functionName = ""; //$NON-NLS-1$ |
|
577 if (loc != null) { |
|
578 line = loc.getLineNumber(); |
|
579 className = loc.getClassName(); |
|
580 functionName = loc.getFunctionName(); |
|
581 } |
|
582 com.nokia.tracecompiler.decodeplugins.dictionary.encoder.Trace.writeInstance(trace.getID(), |
|
583 refId, line, functionName, className); |
|
584 } |
|
585 |
|
586 } |