Mercurial > hg > dmlib
comparison tools/fanalyze.c @ 1682:2cfb4806cf71
Add simple and naively implemented multi-file bindiff type file analyzer utility 'fanalyze'.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 31 May 2018 15:15:50 +0300 |
parents | |
children | 187a9f3c9e88 |
comparison
equal
deleted
inserted
replaced
1681:bd68c9adc7ca | 1682:2cfb4806cf71 |
---|---|
1 /* | |
2 * Fanalyze - Analyze similarities between multiple files | |
3 * Programmed and designed by Matti 'ccr' Hamalainen | |
4 * (C) Copyright 2018 Tecnic Software productions (TNSP) | |
5 * | |
6 * Please read file 'COPYING' for information on license and distribution. | |
7 */ | |
8 #include "dmtool.h" | |
9 #include "dmlib.h" | |
10 #include "dmargs.h" | |
11 #include "dmfile.h" | |
12 | |
13 #define SET_MAX_FILES (8) | |
14 | |
15 | |
16 /* Typedefs | |
17 */ | |
18 typedef struct | |
19 { | |
20 char *filename; | |
21 Uint8 *data; | |
22 size_t size; // offset, crop_start, crop_end, doCrop? | |
23 } DMSourceFile; | |
24 | |
25 | |
26 /* Global variables | |
27 */ | |
28 int nsrcFiles = 0; // Number of source files | |
29 DMSourceFile srcFiles[SET_MAX_FILES]; // Source file names | |
30 | |
31 | |
32 /* Arguments | |
33 */ | |
34 static const DMOptArg optList[] = | |
35 { | |
36 { 0, '?', "help", "Show this help", OPT_NONE }, | |
37 { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, | |
38 }; | |
39 | |
40 static const int optListN = sizeof(optList) / sizeof(optList[0]); | |
41 | |
42 | |
43 void argShowHelp() | |
44 { | |
45 dmPrintBanner(stdout, dmProgName, "[options] <input file #1> <input file #2> [...]"); | |
46 dmArgsPrintHelp(stdout, optList, optListN, 0); | |
47 } | |
48 | |
49 | |
50 BOOL argHandleOpt(const int optN, char *optArg, char *currArg) | |
51 { | |
52 switch (optN) | |
53 { | |
54 case 0: | |
55 argShowHelp(); | |
56 exit(0); | |
57 break; | |
58 | |
59 case 1: | |
60 dmVerbosity++; | |
61 break; | |
62 | |
63 default: | |
64 dmErrorMsg("Unknown argument '%s'.\n", currArg); | |
65 return FALSE; | |
66 } | |
67 | |
68 return TRUE; | |
69 } | |
70 | |
71 | |
72 BOOL argHandleNonOpt(char *currArg) | |
73 { | |
74 if (nsrcFiles < SET_MAX_FILES) | |
75 { | |
76 DMSourceFile *file = &srcFiles[nsrcFiles++]; | |
77 file->filename = currArg; | |
78 return TRUE; | |
79 } | |
80 else | |
81 { | |
82 dmErrorMsg("Maximum number of input files exceeded (%d).\n", | |
83 SET_MAX_FILES); | |
84 return FALSE; | |
85 } | |
86 } | |
87 | |
88 | |
89 #define SET_MAX_ELEMS 256 | |
90 typedef struct | |
91 { | |
92 Uint8 counts[SET_MAX_ELEMS]; | |
93 Uint8 variants, data; | |
94 } DMCompElem; | |
95 | |
96 | |
97 int main(int argc, char *argv[]) | |
98 { | |
99 DMCompElem *compBuf = NULL; | |
100 size_t compBufSize = 0; | |
101 int res; | |
102 | |
103 dmInitProg("fanalyze", "File format analyzer", "0.1", NULL, NULL); | |
104 dmVerbosity = 1; | |
105 | |
106 // Parse arguments | |
107 if (!dmArgsProcess(argc, argv, optList, optListN, | |
108 argHandleOpt, argHandleNonOpt, OPTH_BAILOUT)) | |
109 exit(1); | |
110 | |
111 if (nsrcFiles < 1) | |
112 { | |
113 dmErrorMsg("Nothing to do. (try --help)\n"); | |
114 goto out; | |
115 } | |
116 | |
117 // Read input files | |
118 for (int nfile = 0; nfile < nsrcFiles; nfile++) | |
119 { | |
120 DMSourceFile *file = &srcFiles[nfile]; | |
121 dmPrint(2, "Input #%d: %s\n", nfile + 1, file->filename); | |
122 if ((res = dmReadDataFile(NULL, file->filename, &file->data, &file->size)) != DMERR_OK) | |
123 { | |
124 dmErrorMsg("Could not read '%s': %s\n", | |
125 file->filename, dmErrorStr(res)); | |
126 goto out; | |
127 } | |
128 | |
129 if (file->size > compBufSize) | |
130 compBufSize = file->size; | |
131 } | |
132 | |
133 // Allocate comparision buffer | |
134 // XXX: integer overflow? | |
135 dmPrint(2, "Allocating %d element (%d bytes) comparision buffer.\n", | |
136 compBufSize, compBufSize * sizeof(DMCompElem)); | |
137 | |
138 if ((compBuf = dmCalloc(compBufSize, sizeof(DMCompElem))) == NULL) | |
139 { | |
140 dmErrorMsg("Out of memory. Could not allocate comparision buffer!\n"); | |
141 goto out; | |
142 } | |
143 | |
144 // Begin analyzing .. | |
145 dmPrint(2, "Analyzing ..\n"); | |
146 for (int nfile = 0; nfile < nsrcFiles; nfile++) | |
147 { | |
148 DMSourceFile *file = &srcFiles[nfile]; | |
149 for (size_t offs = 0; offs < compBufSize; offs++) | |
150 if (offs < file->size) | |
151 compBuf[offs].counts[file->data[offs]]++; | |
152 else | |
153 compBuf[offs].counts[0]++; | |
154 } | |
155 | |
156 for (size_t offs = 0; offs < compBufSize; offs++) | |
157 { | |
158 DMCompElem *el = &compBuf[offs]; | |
159 for (int n = 0; n < SET_MAX_ELEMS; n++) | |
160 { | |
161 if (el->counts[n] > 0) | |
162 { | |
163 el->variants++; | |
164 el->data = n; | |
165 } | |
166 } | |
167 } | |
168 | |
169 // Display results | |
170 for (size_t offs = 0, n = 0; offs < compBufSize; offs++) | |
171 { | |
172 DMCompElem *el = &compBuf[offs]; | |
173 BOOL var = el->variants > 1; | |
174 | |
175 if (n == 0) | |
176 printf("%08x | ", offs); | |
177 | |
178 if (var) | |
179 printf("[%2d] ", el->variants); | |
180 else | |
181 printf(" %02x ", el->data); | |
182 | |
183 if (++n >= 16) | |
184 { | |
185 printf("\n"); | |
186 n = 0; | |
187 } | |
188 } | |
189 | |
190 printf("\n"); | |
191 | |
192 out: | |
193 for (int nfile = 0; nfile < nsrcFiles; nfile++) | |
194 { | |
195 DMSourceFile *file = &srcFiles[nfile]; | |
196 dmFree(file->data); | |
197 } | |
198 | |
199 return 0; | |
200 } |