00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <stdio.h>
00014 #include <stdlib.h>
00015 #include <stdint.h>
00016 #include <string.h>
00017 #include <assert.h>
00018 #include <errno.h>
00019
00020 #include <string>
00021 #include <map>
00022 #include <vector>
00023
00024
00025
00026
00027
00028 #define DWORD uint32_t
00029
00030 #define NAME_LENGTH 32
00031
00032 typedef struct {
00033 DWORD record_type;
00034 DWORD event_id;
00035 DWORD time;
00036 DWORD def_offset;
00037 DWORD data_size;
00038 } HIST_RECORD;
00039
00040 typedef struct {
00041 char name[NAME_LENGTH];
00042 DWORD type;
00043 DWORD n_data;
00044 } TAG;
00045
00046
00047
00048
00049
00050
00051
00052 int tid_size[] = {
00053 0,
00054 1,
00055 1,
00056 1,
00057 2,
00058 2,
00059 4,
00060 4,
00061 4,
00062 4,
00063 8,
00064 1,
00065 0,
00066 0,
00067 0,
00068 0,
00069 0
00070 };
00071
00072
00073 char *tid_name[] = {
00074 "NULL",
00075 "BYTE",
00076 "SBYTE",
00077 "CHAR",
00078 "WORD",
00079 "SHORT",
00080 "DWORD",
00081 "INT",
00082 "BOOL",
00083 "FLOAT",
00084 "DOUBLE",
00085 "BITFIELD",
00086 "STRING",
00087 "ARRAY",
00088 "STRUCT",
00089 "KEY",
00090 "LINK"
00091 };
00092
00093
00094
00095 struct Tag
00096 {
00097 int event_id;
00098 std::string name;
00099 int offset;
00100 int arraySize;
00101 int typeSize;
00102 int typeCode;
00103 };
00104
00105 struct Event
00106 {
00107 bool printAllTags;
00108 int size;
00109 std::map<std::string,Tag*> tags;
00110 std::vector<std::string> tagNames;
00111 std::vector<int> tagIndexes;
00112 };
00113
00114 std::map<int,Event*> gTags;
00115
00116 bool doPrintTags = true;
00117 bool doPrintNames = true;
00118 bool doPrintData = true;
00119 bool doAll = false;
00120
00121 int readHstFile(FILE*f)
00122 {
00123 bool doRead = true;
00124
00125 assert(f!=NULL);
00126
00127 while (1)
00128 {
00129 HIST_RECORD rec;
00130
00131 if (doRead)
00132 {
00133 int rd = fread(&rec, sizeof(rec), 1, f);
00134 if (!rd)
00135 break;
00136 }
00137
00138 doRead = true;
00139 #if 0
00140 printf("HIST_RECORD:\n");
00141 printf(" Record type: 0x%x\n", rec.record_type);
00142 printf(" Event ID: %d\n", rec.event_id);
00143 printf(" Time: %d\n", rec.time);
00144 printf(" Offset: 0x%x\n", rec.def_offset);
00145 printf(" Size: 0x%x\n", rec.data_size);
00146 #endif
00147
00148 switch (rec.record_type)
00149 {
00150 default:
00151 printf("Unexpected record type: 0x%08x, trying to recover by skipping bad data.\n", rec.record_type);
00152 while (1)
00153 {
00154 int c = fgetc(f);
00155
00156 if (c==EOF)
00157 return 0;
00158 if (c!=0x48)
00159 continue;
00160
00161 c = fgetc(f);
00162 if (c==EOF)
00163 return 0;
00164 if (c!=0x53)
00165 continue;
00166
00167 c = fgetc(f);
00168 if (c==EOF)
00169 return 0;
00170 if (c!=0x44)
00171 continue;
00172
00173 printf("Maybe recovered - see what looks like valid history record header.\n");
00174
00175 ((char*)(&rec))[0] = 0x48;
00176 ((char*)(&rec))[1] = 0x53;
00177 ((char*)(&rec))[2] = 0x44;
00178
00179 int rd = fread(((char*)(&rec))+3, sizeof(rec)-3, 1, f);
00180 if (!rd)
00181 return 0;
00182
00183 doRead = false;
00184 break;
00185 }
00186 break;
00187
00188 case 0x46445348:
00189 {
00190 char event_name[NAME_LENGTH];
00191 int rd = fread(event_name, 1, NAME_LENGTH, f);
00192 assert(rd == NAME_LENGTH);
00193
00194 int size = rec.data_size;
00195 int ntags = size/sizeof(TAG);
00196
00197 if (doPrintTags)
00198 printf("Event %d, \"%s\", size %d, %d tags.\n", rec.event_id, event_name, size, ntags);
00199
00200 assert(size > 0);
00201 assert(size < 1*1024*1024);
00202 assert(size == ntags*(int)sizeof(TAG));
00203
00204 TAG *tags = new TAG[ntags];
00205 rd = fread(tags, 1, size, f);
00206 assert(rd == size);
00207
00208 Event* e = gTags[rec.event_id];
00209 if (!e)
00210 {
00211 gTags[rec.event_id] = new Event;
00212 e = gTags[rec.event_id];
00213 e->printAllTags = false;
00214 if (doAll)
00215 e->printAllTags = true;
00216 }
00217 else
00218 {
00219 e->tagNames.clear();
00220 e->tagIndexes.clear();
00221 }
00222
00223 e->size = 0;
00224
00225 int offset = 0;
00226
00227 for (int itag=0; itag<ntags; itag++)
00228 {
00229 int tsize = tid_size[tags[itag].type];
00230
00231 if (tsize == 0)
00232 tsize = 1;
00233
00234 int size = tags[itag].n_data * tsize;
00235
00236 if (offset%tsize != 0)
00237 offset += tsize-offset%tsize;
00238
00239 assert(offset%tsize == 0);
00240
00241 Tag* t = new Tag;
00242 t->event_id = rec.event_id;
00243 t->name = tags[itag].name;
00244 t->offset = offset;
00245 t->arraySize = tags[itag].n_data;
00246 t->typeSize = tid_size[tags[itag].type];
00247 t->typeCode = tags[itag].type;
00248
00249 e->tags[t->name] = t;
00250
00251 if (e->printAllTags)
00252 {
00253 e->tagNames.push_back(t->name);
00254 e->tagIndexes.push_back(-1);
00255 }
00256
00257 if (doPrintTags)
00258 printf(" Tag %d: \"%s\"[%d], type \"%s\" (%d), type size %d, offset %d+%d\n", itag, tags[itag].name, tags[itag].n_data, tid_name[tags[itag].type], tags[itag].type, tid_size[tags[itag].type], offset, size);
00259
00260 offset += size;
00261 }
00262
00263 e->size = offset;
00264
00265 delete tags;
00266 break;
00267 }
00268
00269 case 0x41445348:
00270 {
00271 int size = rec.data_size;
00272
00273 if (0)
00274 printf("Data record, size %d.\n", size);
00275
00276 if (size <= 1 || size > 1*1024*1024)
00277 {
00278 printf("Invalid data record: event %d, size %d is invalid\n", rec.event_id, rec.data_size);
00279 continue;
00280 }
00281
00282 char *buf = new char[size];
00283 int rd = fread(buf, 1, size, f);
00284 assert(rd == size);
00285
00286 time_t t = (time_t)rec.time;
00287
00288 Event* e = gTags[rec.event_id];
00289 if (e && doPrintData)
00290 {
00291 if (size != e->size)
00292 {
00293 printf("event %d, size mismatch should be %d, got %d bytes\n", rec.event_id, e->size, size);
00294 }
00295
00296
00297
00298 int n = e->tagNames.size();
00299
00300 if (n>0)
00301 printf("%d %d ", rec.event_id, rec.time);
00302
00303 for (int i=0; i<n; i++)
00304 {
00305 Tag*t = e->tags[e->tagNames[i]];
00306 int index = e->tagIndexes[i];
00307
00308
00309
00310 if (t)
00311 {
00312 int offset = t->offset;
00313 void* ptr = (void*)(buf+offset);
00314
00315 if (doPrintNames)
00316 {
00317 if (index < 0)
00318 printf(" %s=", t->name.c_str());
00319 else
00320 printf(" %s[%d]=", t->name.c_str(), index);
00321 }
00322
00323 for (int j=0; j<t->arraySize; j++)
00324 {
00325 if (index >= 0)
00326 j = index;
00327
00328 switch (t->typeCode)
00329 {
00330 default:
00331 printf("unknownType%d ",t->typeCode);
00332 break;
00333 case 1:
00334 printf("%u ",((uint8_t*)ptr)[j]);
00335 break;
00336 case 2:
00337 printf("%d ",((int8_t*)ptr)[j]);
00338 break;
00339 case 3:
00340 printf("\'%c\' ",((char*)ptr)[j]);
00341 break;
00342 case 4:
00343 printf("%u ",((uint16_t*)ptr)[j]);
00344 break;
00345 case 5:
00346 printf("%d ",((int16_t*)ptr)[j]);
00347 break;
00348 case 6:
00349 printf("%u ",((uint32_t*)ptr)[j]);
00350 break;
00351 case 7:
00352 printf("%d ",((int32_t*)ptr)[j]);
00353 break;
00354 case 8:
00355 printf("%u ",((uint32_t*)ptr)[j]);
00356 break;
00357 case 9:
00358 printf("%.8g ",((float*)ptr)[j]);
00359 break;
00360 case 10:
00361 printf("%.16g ",((double*)ptr)[j]);
00362 break;
00363 }
00364
00365 if (index >= 0)
00366 break;
00367 }
00368 }
00369 }
00370
00371 if (n>0)
00372 printf(" %s", ctime(&t));
00373 }
00374
00375 delete buf;
00376 break;
00377 }
00378 }
00379 }
00380
00381 return 0;
00382 }
00383
00384 int readHst(const char* name)
00385 {
00386 FILE* f = fopen(name,"r");
00387 if (!f)
00388 {
00389 fprintf(stderr,"Error: Cannot open \'%s\', errno %d (%s)\n", name, errno, strerror(errno));
00390 exit(1);
00391 }
00392
00393 readHstFile(f);
00394 fclose(f);
00395 return 0;
00396 }
00397
00398 void help()
00399 {
00400 fprintf(stderr,"Usage: mhdump [-h] [-L] [-n] [-t] [-E event_id] [-T tag_name] file1.hst file2.hst ...\n");
00401 fprintf(stderr,"\n");
00402 fprintf(stderr,"Switches:\n");
00403 fprintf(stderr," -h --- print this help message\n");
00404 fprintf(stderr," -L --- list tag definitions only\n");
00405 fprintf(stderr," -t --- omit tag definitions\n");
00406 fprintf(stderr," -n --- omit variable names\n");
00407 fprintf(stderr,"\n");
00408 fprintf(stderr,"Examples:\n");
00409 fprintf(stderr," To list all existing tags: mhdump -L file1.hst file2.hst ...\n");
00410 fprintf(stderr," To show data for all events, all tags: mhdump file1.hst file2.hst ...\n");
00411 fprintf(stderr," To show all data for event 0: mhdump -E 0 file1.hst file2.hst ...\n");
00412 fprintf(stderr," To show data for event 0, tag \"State\": mhdump -n -E 0 -T State file1.hst file2.hst ...\n");
00413 fprintf(stderr," To show data for event 3, tag \"MCRT\", array index 5: mhdump -n -E 3 -T MCRT[5] file1.hst file2.hst ...\n");
00414 exit(1);
00415 }
00416
00417 int main(int argc,char*argv[])
00418 {
00419 int event_id = -1;
00420
00421 if (argc <= 1)
00422 help();
00423
00424 for (int iarg=1; iarg<argc; iarg++)
00425 if (strcmp(argv[iarg], "-h")==0)
00426 {
00427 help();
00428 }
00429 else if (strcmp(argv[iarg], "-E")==0)
00430 {
00431 iarg++;
00432 event_id = atoi(argv[iarg]);
00433 if (!gTags[event_id])
00434 gTags[event_id] = new Event;
00435 gTags[event_id]->printAllTags = true;
00436 }
00437 else if (strcmp(argv[iarg], "-T")==0)
00438 {
00439 iarg++;
00440 char *s = strchr(argv[iarg],'[');
00441 int index = -1;
00442 if (s)
00443 {
00444 index = atoi(s+1);
00445 *s = 0;
00446 }
00447
00448 std::string name = argv[iarg];
00449
00450 Event* e = gTags[event_id];
00451
00452 if ((event_id<0) || !e)
00453 {
00454 fprintf(stderr,"Error: expected \"-E event_id\" before \"-T ...\"\n");
00455 exit(1);
00456 }
00457
00458 e->printAllTags = false;
00459 e->tagNames.push_back(name);
00460 e->tagIndexes.push_back(index);
00461 }
00462 else if (strcmp(argv[iarg], "-t")==0)
00463 doPrintTags = false;
00464 else if (strcmp(argv[iarg], "-L")==0)
00465 {
00466 doPrintTags = true;
00467 doPrintData = false;
00468 }
00469 else if (strcmp(argv[iarg], "-A")==0)
00470 doAll = true;
00471 else if (strcmp(argv[iarg], "-n")==0)
00472 doPrintNames = false;
00473 else
00474 {
00475 if (gTags.size() == 0)
00476 doAll = true;
00477 readHst(argv[iarg]);
00478 }
00479
00480 return 0;
00481 }
00482
00483