1#include <stdio.h>
2#include <string.h>
3
4///////////////////////////////////////////////////////////////
5// global data
6enum EnumMode { enum_Mode_Quiet, enum_Mode_Default, enum_Mode_MDF } g_eMode = enum_Mode_Default;
7
8const char* c_szType[] = {
9  "null",  "chr", "int", "bool",
10  "bin", "node", "", "",
11  "", "test", "", "",
12  "", "", "", ""
13};
14
15const char* c_szAccess[] = {
16  "",     // 0
17  "access:Add",  // 1
18  "access:Delete",  // 2
19  "access:Add,Delete",  // 2 + 1
20  "access:Get",  // 4
21  "access:Get,Add",  // 1+4
22  "access:Get,Delete",  // 2 + 4
23  "access:Get,Add,Delete",  // 1 +2+4
24  "access:Replace",  // 8
25  "access:Add,Replace",  // 1 + 8
26  "access:Delete,Replace",  // 2 + 8
27  "access:Add,Delete,Replace",  // 1 +2+8
28  "access:Get,Replace",  // 4 + 8
29  "access:Add,Get,Replace",  // 1+ 4 +8
30  "access:Delete,Get,Replace",  // 2 + 4 + 8
31  "access:Add,Delete,Get,Replace",  // 1+ 2 + 4 + 8
32
33  "access:Exec",     // 0
34  "access:Exec,Add",  // 1
35  "access:Exec,Delete",  // 2
36  "access:Exec,Add,Delete",  // 2 + 1
37  "access:Exec,Get",  // 4
38  "access:Exec,Get,Add",  // 1+4
39  "access:Exec,Get,Delete",  // 2 + 4
40  "access:Exec,Get,Add,Delete",  // 1 +2+4
41  "access:Exec,Replace",  // 8
42  "access:Exec,Add,Replace",  // 1 + 8
43  "access:Exec,Delete,Replace",  // 2 + 8
44  "access:Exec,Add,Delete,Replace",  // 1 +2+8
45  "access:Exec,Get,Replace",  // 4 + 8
46  "access:Exec,Add,Get,Replace",  // 1+ 4 +8
47  "access:Exec,Delete,Get,Replace",  // 2 + 4 + 8
48  "access:Exec,Add,Delete,Get,Replace",  // 1+ 2 + 4 + 8
49
50};
51
52///////////////////////////////////////////////////////////////
53///////////////////////////////////////////////////////////////
54static int GetInt( const unsigned char* buf, int& nOffset )
55{
56  int value = 0;
57
58  for (int i=0; i < 4; i++)
59  {
60    value |= (*(buf+nOffset)) << (i*8);
61    nOffset++;
62  }
63  return value;
64}
65
66///////////////////////////////////////////////////////////////
67static int GetInt16( const unsigned char* buf, int& nOffset )
68{
69  int value = 0;
70
71  for (int i=0; i < 2; i++)
72  {
73    value |= (*(buf+nOffset)) << (i*8);
74    nOffset++;
75  }
76  return value;
77}
78
79
80///////////////////////////////////////////////////////////////
81static int GetPrintItem( const unsigned char* buf, int& nOffset, long nSize, int nLevel, const char* szParentURI )
82{
83  int nRes = 0;
84  char szIndent[100];
85  int nStartOffset = nOffset;
86  char  szCurrentURI[1024];
87
88  strcpy( szCurrentURI, szParentURI );
89
90  for ( int i = 0; i < nLevel; i++ ){
91	szIndent[i] = '\t';
92  }
93  szIndent[nLevel]=0;
94
95  if ( nOffset + 11 >= nSize ){
96	if ( g_eMode != enum_Mode_Quiet )
97	  printf( "Item does not fit buffer completelly, offset %d, \n", nOffset);
98
99	return 6;
100  }
101
102  int nNameOffset = GetInt( buf, nOffset );
103
104  const unsigned char* szName = buf + nNameOffset;
105
106  if ( nNameOffset >= nSize ){
107	szName = (const unsigned char*)"<<out of the buffer>>";
108	nRes = 7;
109  }
110
111  strcat( szCurrentURI, (const char*)szName );
112
113  int nType = GetInt16( buf, nOffset );
114  int nIDOffset = 0;
115
116  if ( nType & 0x400 )
117    nIDOffset = GetInt( buf, nOffset );
118
119  const unsigned char* szID = nIDOffset ? buf + nIDOffset :(const unsigned char*)"<unset>";
120
121  if ( nIDOffset >= nSize ){
122	szID = (const unsigned char*)"<<out of the buffer>>";
123	nRes = 7;
124  }
125
126  int nAccess = buf[nOffset++];
127  int nMimeType = buf[nOffset++];
128  int nChildren = GetInt16( buf, nOffset );
129
130  int aChildren[500];
131
132  if ( nOffset + nChildren * 4 >= nSize ){
133	if ( g_eMode != enum_Mode_Quiet )
134	  printf( "Item does not fit buffer completelly, offset %d, \n", nOffset);
135
136	return 6;
137  }
138
139  for( int i = 0; i < nChildren; i++ ){
140	aChildren[i] = GetInt(buf, nOffset );
141  }
142
143  int nConst = buf[nOffset++];
144
145  if ( g_eMode == enum_Mode_Default)
146    printf( "%s%04x-%04x: Name (%03x): \"%s\", type %x\tid %s\taccess %x,\tmime %x,\tchildren count %x,\t constr %x\n",
147  		  szIndent, nStartOffset, nOffset-1, nNameOffset,
148  		  szName,
149			/*szIndent,*/ nType, szID,
150			nAccess, nMimeType, nChildren, nConst  );
151  else if ( g_eMode == enum_Mode_MDF) {
152    printf( "[%s]\n"
153    "type:%s\n%s\n",
154  		  szCurrentURI,
155  		  c_szType[nType &0x0f],
156  		  c_szAccess[nAccess &0x1f] );
157
158	if ( nType & 0x400 )
159	  printf( "ID:%s\n", szID );
160
161	if ( nType & 0x200 )
162	  printf( "HandledByPlugin:1\n" );
163
164	if ( nType & 0x100 )
165	  printf( "storesPD:1\n" );
166  }
167
168  if ( strcmp( (const char*)szName, "." ) ==0 )
169    szCurrentURI[0]=0;
170
171  strcat(szCurrentURI, "/" );
172
173
174  // constraints
175  for ( int i = 0; i < nConst; i++ ){
176	int nConstType = buf[nOffset++];
177
178	const char* sz_Const[] = {
179	  "",
180	  "min",
181	  "max",
182	  "values",
183	  "default",
184	  "minLen",
185	  "maxLen",
186	  "regexp",
187	  "nMaxLen",
188	  "nValues",
189	  "nRegexp",
190	  "auto",
191	  "recur-after-segment",
192	  "max-recurrence",
193	  "fk",
194	  "child",
195	  "depend",
196	  "maxChild"
197	};
198
199	if ( nOffset + 4 >= nSize ){
200	  if ( g_eMode != enum_Mode_Quiet )
201		printf( "Item does not fit buffer completelly, offset %d, \n", nOffset);
202
203	  return 6;
204	}
205
206	int nValue = 0;
207    char szStrValue[30] = "";
208	const unsigned char* szValue = (const unsigned char*)szStrValue;
209
210	switch ( nConstType ){
211	default:
212	  if ( g_eMode != enum_Mode_Quiet )
213	    printf( "Invalid constraint type %d, offset %d, \n", nConstType, nOffset);
214	  return 6;
215	case 3: case 7: case 9: case 10: case 11: case 12: case 14:  case 15: case 16:
216	  nValue = GetInt( buf, nOffset );
217
218	  if ( nValue >= nSize ){
219		szValue = (const unsigned char*)"<<out of the buffer>>";
220		nRes = 7;
221	  }
222	  else
223		szValue = buf + nValue;
224	  break;
225
226	case 1: case 2:
227	  nValue = GetInt( buf, nOffset );
228    sprintf(szStrValue, "%d", nValue);
229	  break;
230	case 5: case 6: case 8: case 13: case 17:
231	  nValue = GetInt16( buf, nOffset );
232    sprintf(szStrValue, "%d", nValue);
233	  break;
234	case 4:
235	  if ( (nType & 0x7f) == 3 ) {// bool
236		nValue = buf[nOffset++];
237      sprintf(szStrValue, "%s", nValue ? "true": "false");
238	  }
239	  else {
240		nValue = GetInt( buf, nOffset );
241
242      if( (nType & 0x7f) == 2 ) // int
243        sprintf(szStrValue, "%d", nValue);
244      else {
245      	  if ( nValue >= nSize ){
246      		szValue = (const unsigned char*)"<<out of the buffer>>";
247      		nRes = 7;
248      	  }
249      	  else
250      		szValue = buf + nValue;
251      }
252
253	  }
254
255	  break;
256	}
257
258  if ( g_eMode == enum_Mode_Default)
259    printf("%s  constraint type %s, value %x \"%s\"\n", szIndent, sz_Const[nConstType], nValue, szValue );
260  else if ( g_eMode == enum_Mode_MDF)
261    printf("%s:%s\n", sz_Const[nConstType], szValue );
262
263
264  }
265
266  for ( int i = 0; i < nChildren; i++ ){
267	int n = aChildren[i];
268
269	int nResFromChildren = GetPrintItem( buf, n, nSize, nLevel + 1, szCurrentURI );
270
271	if ( nResFromChildren )
272	  nRes = nResFromChildren;
273  }
274  return nRes;
275}
276
277///////////////////////////////////////////////////////////////
278static int ProcessBuffer( FILE* f, unsigned char* buf, long nSize )
279{
280  if ( fread( buf, 1, nSize, f ) != nSize )
281	return 6;
282
283  if ( g_eMode == enum_Mode_Default )
284	printf("buffer loaded...\n");
285
286  int nOffset = 0;
287
288  int n = GetInt( buf, nOffset );
289  int nVer = GetInt16( buf, nOffset );
290
291  if ( g_eMode == enum_Mode_Default )
292	printf( "%x: fsize %x; ver %x (%s)\n", nOffset - 6, n, nVer, n == nSize ? "valid" : "invalid");
293
294  return GetPrintItem( buf, nOffset, nSize, 0, "" );
295}
296
297///////////////////////////////////////////////////////////////
298static int ProcessFile( FILE* f )
299{
300  fseek( f, 0, SEEK_END );
301  long nSize = ftell( f );
302  fseek( f, 0, SEEK_SET );
303
304  if ( nSize <= 0 )
305	return 3;
306
307  if ( g_eMode == enum_Mode_Default )
308	printf( "File size is %d (dec)\n", nSize );
309
310  unsigned char* buf = new unsigned char[nSize+1];
311  if ( !buf )
312	return 4;
313
314  buf[nSize]=0;
315  int nRet = ProcessBuffer( f, buf, nSize );
316
317  delete buf;
318  return nRet;
319}
320
321///////////////////////////////////////////////////////////////
322static void Usage()
323{
324	printf("Simple reader and verifier for binary MDF files\n"
325		   "always return 0 code for valid file and non zero for corrupted file\n"
326		   "usage: bmdf_reader [-q] [-mdf] <bmdf file name>\n"
327		   "-q -- quiet mode, return only error code (0 valid file, not 0 - invalid file)\n"
328		   "-mdf -- generate text mdf\n"
329		   );
330}
331
332///////////////////////////////////////////////////////////////
333static const char*  ParseCmdLineOptions(int argc, char** argv)
334{
335  const char* szFileName = NULL;
336
337  for ( int i = 1; i < argc; i++ ){
338	if ( strcasecmp( argv[i], "-q") == 0 )
339	  g_eMode = enum_Mode_Quiet;
340	else if ( strcasecmp( argv[i], "-mdf") == 0 )
341	  g_eMode = enum_Mode_MDF;
342	else {
343	  szFileName = argv[i];
344	  break;
345	}
346  }
347
348  return szFileName;
349}
350
351///////////////////////////////////////////////////////////////
352int main(int argc, char** argv)
353{
354  const char* szFileName = ParseCmdLineOptions( argc, argv );
355
356  if ( !szFileName ){
357	Usage();
358	return 1;
359  }
360
361  FILE* f = fopen( szFileName, "r" );
362
363  if ( !f ){
364	printf("unable to open file %s\n", szFileName );
365	return 2;
366  }
367
368  int nRet = ProcessFile( f );
369  fclose( f );
370
371  if ( g_eMode == enum_Mode_Default )
372	printf( "\ndone, file is %s\n", nRet ? "invalid" : "ok");
373
374  return nRet;
375}
376