summaryrefslogtreecommitdiffstats
path: root/src/file_emf.c
blob: 5bae67d849e675e4a422854108bc19b0473128d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
/*

    File: file_emf.c

    Copyright (C) 2008 Christophe GRENIER <grenier@cgsecurity.org>
  
    This software is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
  
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
  
    You should have received a copy of the GNU General Public License along
    with this program; if not, write the Free Software Foundation, Inc., 51
    Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

 */
#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_emf)
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <stdio.h>
#include "types.h"
#include "filegen.h"
#include "log.h"
#include "common.h"
#if defined(__FRAMAC__)
#include "__fc_builtin.h"
#endif

/*@ requires valid_register_header_check(file_stat); */
static void register_header_check_emf(file_stat_t *file_stat);

const file_hint_t file_hint_emf= {
  .extension="emf",
  .description="Windows Enhanced MetaFile",
  .max_filesize=PHOTOREC_MAX_FILE_SIZE,
  .recover=1,
  .enable_by_default=1,
  .register_header_check=&register_header_check_emf
};

typedef struct {
  uint32_t iType;
  uint32_t nSize;
} U_EMR;

typedef struct {
  int32_t left;
  int32_t top;
  int32_t right;
  int32_t bottom;
} U_RECTL;

typedef struct {
  int32_t cx;
  int32_t cy;
} U_SIZEL;

struct EMF_HDR
{
  U_EMR emr;
  U_RECTL rclBounds;
  U_RECTL rclFrame;
  uint32_t dSignature;
  uint32_t nVersion;
  uint32_t nBytes;
  uint32_t nRecords;
  uint16_t nHandles;
  uint16_t sReserved;
  uint32_t nDescription;
  uint32_t offDescription;
  uint32_t nPalEntries;
  U_SIZEL szlDevice;
  U_SIZEL szlMillimeters;
} __attribute__ ((gcc_struct, __packed__));

#define EMR_HEADER	1
#define EMR_POLYBEZIER	2
#define EMR_POLYGON	3
#define EMR_POLYLINE	4
#define EMR_POLYBEZIERTO	5
#define EMR_POLYLINETO	6
#define EMR_POLYPOLYLINE	7
#define EMR_POLYPOLYGON	8
#define EMR_SETWINDOWEXTEX	9
#define EMR_SETWINDOWORGEX	10
#define EMR_SETVIEWPORTEXTEX	11
#define EMR_SETVIEWPORTORGEX	12
#define EMR_SETBRUSHORGEX	13
#define EMR_EOF	14
#define EMR_SETPIXELV	15
#define EMR_SETMAPPERFLAGS	16
#define EMR_SETMAPMODE	17
#define EMR_SETBKMODE	18
#define EMR_SETPOLYFILLMODE	19
#define EMR_SETROP2	20
#define EMR_SETSTRETCHBLTMODE	21
#define EMR_SETTEXTALIGN	22
#define EMR_SETCOLORADJUSTMENT	23
#define EMR_SETTEXTCOLOR	24
#define EMR_SETBKCOLOR	25
#define EMR_OFFSETCLIPRGN	26
#define EMR_MOVETOEX	27
#define EMR_SETMETARGN	28
#define EMR_EXCLUDECLIPRECT	29
#define EMR_INTERSECTCLIPRECT	30
#define EMR_SCALEVIEWPORTEXTEX	31
#define EMR_SCALEWINDOWEXTEX	32
#define EMR_SAVEDC	33
#define EMR_RESTOREDC	34
#define EMR_SETWORLDTRANSFORM	35
#define EMR_MODIFYWORLDTRANSFORM	36
#define EMR_SELECTOBJECT	37
#define EMR_CREATEPEN	38
#define EMR_CREATEBRUSHINDIRECT	39
#define EMR_DELETEOBJECT	40
#define EMR_ANGLEARC	41
#define EMR_ELLIPSE	42
#define EMR_RECTANGLE	43
#define EMR_ROUNDRECT	44
#define EMR_ARC	45
#define EMR_CHORD	46
#define EMR_PIE	47
#define EMR_SELECTPALETTE	48
#define EMR_CREATEPALETTE	49
#define EMR_SETPALETTEENTRIES	50
#define EMR_RESIZEPALETTE	51
#define EMR_REALIZEPALETTE	52
#define EMR_EXTFLOODFILL	53
#define EMR_LINETO	54
#define EMR_ARCTO	55
#define EMR_POLYDRAW	56
#define EMR_SETARCDIRECTION	57
#define EMR_SETMITERLIMIT	58
#define EMR_BEGINPATH	59
#define EMR_ENDPATH	60
#define EMR_CLOSEFIGURE	61
#define EMR_FILLPATH	62
#define EMR_STROKEANDFILLPATH	63
#define EMR_STROKEPATH	64
#define EMR_FLATTENPATH	65
#define EMR_WIDENPATH	66
#define EMR_SELECTCLIPPATH	67
#define EMR_ABORTPATH	68
#define EMR_GDICOMMENT	70
#define EMR_FILLRGN	71
#define EMR_FRAMERGN	72
#define EMR_INVERTRGN	73
#define EMR_PAINTRGN	74
#define EMR_EXTSELECTCLIPRGN	75
#define EMR_BITBLT	76
#define EMR_STRETCHBLT	77
#define EMR_MASKBLT	78
#define EMR_PLGBLT	79
#define EMR_SETDIBITSTODEVICE	80
#define EMR_STRETCHDIBITS	81
#define EMR_EXTCREATEFONTINDIRECTW	82
#define EMR_EXTTEXTOUTA	83
#define EMR_EXTTEXTOUTW	84
#define EMR_POLYBEZIER16	85
#define EMR_POLYGON16	86
#define EMR_POLYLINE16	87
#define EMR_POLYBEZIERTO16	88
#define EMR_POLYLINETO16	89
#define EMR_POLYPOLYLINE16	90
#define EMR_POLYPOLYGON16	91
#define EMR_POLYDRAW16	92
#define EMR_CREATEMONOBRUSH	93
#define EMR_CREATEDIBPATTERNBRUSHPT	94
#define EMR_EXTCREATEPEN	95
#define EMR_POLYTEXTOUTA	96
#define EMR_POLYTEXTOUTW	97
#define EMR_SETICMMODE	98
#define EMR_CREATECOLORSPACE	99
#define EMR_SETCOLORSPACE	100
#define EMR_DELETECOLORSPACE	101
#define EMR_GLSRECORD	102
#define EMR_GLSBOUNDEDRECORD	103
#define EMR_PIXELFORMAT 104
#define EMR_DRAWESCAPE 	105
#define EMR_EXTESCAPE	106
#define EMR_STARTDOC	107
#define EMR_SMALLTEXTOUT	108
#define EMR_FORCEUFIMAPPING	109
#define EMR_NAMEDESCAPE	110
#define EMR_COLORCORRECTPALETTE	111
#define EMR_SETICMPROFILEA	112
#define EMR_SETICMPROFILEW	113
#define EMR_ALPHABLEND	114
#define EMR_SETLAYOUT	115
#define EMR_TRANSPARENTBLT	116
#define EMR_RESERVED_117	117
#define EMR_GRADIENTFILL	118
#define EMR_SETLINKEDUFI	119
#define EMR_SETTEXTJUSTIFICATION	120
#define EMR_COLORMATCHTOTARGETW	121
#define EMR_CREATECOLORSPACEW	122

/*@
  @ requires file_recovery->data_check==&data_check_emf;
  @ requires buffer_size >= 2;
  @ requires valid_data_check_param(buffer, buffer_size, file_recovery);
  @ terminates \true;
  @ ensures  valid_data_check_result(\result, file_recovery);
  @ assigns file_recovery->calculated_file_size;
  @*/
static data_check_t data_check_emf(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
  /*@ assert file_recovery->calculated_file_size <= PHOTOREC_MAX_FILE_SIZE; */
  /*@ assert file_recovery->file_size <= PHOTOREC_MAX_FILE_SIZE; */
  /*@
    @ loop assigns file_recovery->calculated_file_size;
    @ loop variant file_recovery->file_size + buffer_size/2 - (file_recovery->calculated_file_size + 8);
    @*/
  while(file_recovery->calculated_file_size + buffer_size/2  >= file_recovery->file_size &&
      file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2)
  {
    const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size;
    /*@ assert 0 <= i < buffer_size - 8 ; */
    const U_EMR *hdr=(const U_EMR *)&buffer[i];
    const unsigned int itype=le32(hdr->iType);
    const unsigned int atom_size=le32(hdr->nSize);
#ifdef DEBUG_EMF
    log_trace("0x%llx ", (long long unsigned)file_recovery->calculated_file_size);
    switch(itype)
    {
      case EMR_HEADER:			log_trace("EMR_HEADER"); break;
      case EMR_POLYBEZIER:		log_trace("EMR_POLYBEZIER"); break;
      case EMR_POLYGON:			log_trace("EMR_POLYGON"); break;
      case EMR_POLYLINE:		log_trace("EMR_POLYLINE"); break;
      case EMR_POLYBEZIERTO:		log_trace("EMR_POLYBEZIERTO"); break;
      case EMR_POLYLINETO:		log_trace("EMR_POLYLINETO"); break;
      case EMR_POLYPOLYLINE:		log_trace("EMR_POLYPOLYLINE"); break;
      case EMR_POLYPOLYGON:		log_trace("EMR_POLYPOLYGON"); break;
      case EMR_SETWINDOWEXTEX:		log_trace("EMR_SETWINDOWEXTEX"); break;
      case EMR_SETWINDOWORGEX:		log_trace("EMR_SETWINDOWORGEX"); break;
      case EMR_SETVIEWPORTEXTEX:	log_trace("EMR_SETVIEWPORTEXTEX"); break;
      case EMR_SETVIEWPORTORGEX:	log_trace("EMR_SETVIEWPORTORGEX"); break;
      case EMR_SETBRUSHORGEX:		log_trace("EMR_SETBRUSHORGEX"); break;
      case EMR_EOF:			log_trace("EMR_EOF"); break;
      case EMR_SETPIXELV:		log_trace("EMR_SETPIXELV"); break;
      case EMR_SETMAPPERFLAGS:		log_trace("EMR_SETMAPPERFLAGS"); break;
      case EMR_SETMAPMODE:		log_trace("EMR_SETMAPMODE"); break;
      case EMR_SETBKMODE:		log_trace("EMR_SETBKMODE"); break;
      case EMR_SETPOLYFILLMODE:		log_trace("EMR_SETPOLYFILLMODE"); break;
      case EMR_SETROP2:			log_trace("EMR_SETROP2"); break;
      case EMR_SETSTRETCHBLTMODE:	log_trace("EMR_SETSTRETCHBLTMODE"); break;
      case EMR_SETTEXTALIGN:		log_trace("EMR_SETTEXTALIGN"); break;
      case EMR_SETCOLORADJUSTMENT:	log_trace("EMR_SETCOLORADJUSTMENT"); break;
      case EMR_SETTEXTCOLOR:		log_trace("EMR_SETTEXTCOLOR"); break;
      case EMR_SETBKCOLOR:		log_trace("EMR_SETBKCOLOR"); break;
      case EMR_OFFSETCLIPRGN:		log_trace("EMR_OFFSETCLIPRGN"); break;
      case EMR_MOVETOEX:		log_trace("EMR_MOVETOEX"); break;
      case EMR_SETMETARGN:		log_trace("EMR_SETMETARGN"); break;
      case EMR_EXCLUDECLIPRECT:		log_trace("EMR_EXCLUDECLIPRECT"); break;
      case EMR_INTERSECTCLIPRECT:	log_trace("EMR_INTERSECTCLIPRECT"); break;
      case EMR_SCALEVIEWPORTEXTEX:	log_trace("EMR_SCALEVIEWPORTEXTEX"); break;
      case EMR_SCALEWINDOWEXTEX:	log_trace("EMR_SCALEWINDOWEXTEX"); break;
      case EMR_SAVEDC:			log_trace("EMR_SAVEDC"); break;
      case EMR_RESTOREDC:		log_trace("EMR_RESTOREDC"); break;
      case EMR_SETWORLDTRANSFORM:	log_trace("EMR_SETWORLDTRANSFORM"); break;
      case EMR_MODIFYWORLDTRANSFORM:	log_trace("EMR_MODIFYWORLDTRANSFORM"); break;
      case EMR_SELECTOBJECT:		log_trace("EMR_SELECTOBJECT"); break;
      case EMR_CREATEPEN:		log_trace("EMR_CREATEPEN"); break;
      case EMR_CREATEBRUSHINDIRECT:	log_trace("EMR_CREATEBRUSHINDIRECT"); break;
      case EMR_DELETEOBJECT:		log_trace("EMR_DELETEOBJECT"); break;
      case EMR_ANGLEARC:		log_trace("EMR_ANGLEARC"); break;
      case EMR_ELLIPSE:			log_trace("EMR_ELLIPSE"); break;
      case EMR_RECTANGLE:		log_trace("EMR_RECTANGLE"); break;
      case EMR_ROUNDRECT:		log_trace("EMR_ROUNDRECT"); break;
      case EMR_ARC:			log_trace("EMR_ARC"); break;
      case EMR_CHORD:			log_trace("EMR_CHORD"); break;
      case EMR_PIE:			log_trace("EMR_PIE"); break;
      case EMR_SELECTPALETTE:		log_trace("EMR_SELECTPALETTE"); break;
      case EMR_CREATEPALETTE:		log_trace("EMR_CREATEPALETTE"); break;
      case EMR_SETPALETTEENTRIES:	log_trace("EMR_SETPALETTEENTRIES"); break;
      case EMR_RESIZEPALETTE:		log_trace("EMR_RESIZEPALETTE"); break;
      case EMR_REALIZEPALETTE:		log_trace("EMR_REALIZEPALETTE"); break;
      case EMR_EXTFLOODFILL:		log_trace("EMR_EXTFLOODFILL"); break;
      case EMR_LINETO:			log_trace("EMR_LINETO"); break;
      case EMR_ARCTO:			log_trace("EMR_ARCTO"); break;
      case EMR_POLYDRAW:		log_trace("EMR_POLYDRAW"); break;
      case EMR_SETARCDIRECTION:		log_trace("EMR_SETARCDIRECTION"); break;
      case EMR_SETMITERLIMIT:		log_trace("EMR_SETMITERLIMIT"); break;
      case EMR_BEGINPATH:		log_trace("EMR_BEGINPATH"); break;
      case EMR_ENDPATH:			log_trace("EMR_ENDPATH"); break;
      case EMR_CLOSEFIGURE:		log_trace("EMR_CLOSEFIGURE"); break;
      case EMR_FILLPATH:		log_trace("EMR_FILLPATH"); break;
      case EMR_STROKEANDFILLPATH:	log_trace("EMR_STROKEANDFILLPATH"); break;
      case EMR_STROKEPATH:		log_trace("EMR_STROKEPATH"); break;
      case EMR_FLATTENPATH:		log_trace("EMR_FLATTENPATH"); break;
      case EMR_WIDENPATH:		log_trace("EMR_WIDENPATH"); break;
      case EMR_SELECTCLIPPATH:		log_trace("EMR_SELECTCLIPPATH"); break;
      case EMR_ABORTPATH:		log_trace("EMR_ABORTPATH"); break;
      case EMR_GDICOMMENT:		log_trace("EMR_GDICOMMENT"); break;
      case EMR_FILLRGN:			log_trace("EMR_FILLRGN"); break;
      case EMR_FRAMERGN:		log_trace("EMR_FRAMERGN"); break;
      case EMR_INVERTRGN:		log_trace("EMR_INVERTRGN"); break;
      case EMR_PAINTRGN:		log_trace("EMR_PAINTRGN"); break;
      case EMR_EXTSELECTCLIPRGN:	log_trace("EMR_EXTSELECTCLIPRGN"); break;
      case EMR_BITBLT:			log_trace("EMR_BITBLT"); break;
      case EMR_STRETCHBLT:		log_trace("EMR_STRETCHBLT"); break;
      case EMR_MASKBLT:			log_trace("EMR_MASKBLT"); break;
      case EMR_PLGBLT:			log_trace("EMR_PLGBLT"); break;
      case EMR_SETDIBITSTODEVICE:	log_trace("EMR_SETDIBITSTODEVICE"); break;
      case EMR_STRETCHDIBITS:		log_trace("EMR_STRETCHDIBITS"); break;
      case EMR_EXTCREATEFONTINDIRECTW:	log_trace("EMR_EXTCREATEFONTINDIRECTW"); break;
      case EMR_EXTTEXTOUTA:		log_trace("EMR_EXTTEXTOUTA"); break;
      case EMR_EXTTEXTOUTW:		log_trace("EMR_EXTTEXTOUTW"); break;
      case EMR_POLYBEZIER16:		log_trace("EMR_POLYBEZIER16"); break;
      case EMR_POLYGON16:		log_trace("EMR_POLYGON16"); break;
      case EMR_POLYLINE16:		log_trace("EMR_POLYLINE16"); break;
      case EMR_POLYBEZIERTO16:		log_trace("EMR_POLYBEZIERTO16"); break;
      case EMR_POLYLINETO16:		log_trace("EMR_POLYLINETO16"); break;
      case EMR_POLYPOLYLINE16:		log_trace("EMR_POLYPOLYLINE16"); break;
      case EMR_POLYPOLYGON16:		log_trace("EMR_POLYPOLYGON16"); break;
      case EMR_POLYDRAW16:		log_trace("EMR_POLYDRAW16"); break;
      case EMR_CREATEMONOBRUSH:		log_trace("EMR_CREATEMONOBRUSH"); break;
      case EMR_CREATEDIBPATTERNBRUSHPT:	log_trace("EMR_CREATEDIBPATTERNBRUSHPT"); break;
      case EMR_EXTCREATEPEN:		log_trace("EMR_EXTCREATEPEN"); break;
      case EMR_POLYTEXTOUTA:		log_trace("EMR_POLYTEXTOUTA"); break;
      case EMR_POLYTEXTOUTW:		log_trace("EMR_POLYTEXTOUTW"); break;
      case EMR_SETICMMODE:		log_trace("EMR_SETICMMODE"); break;
      case EMR_CREATECOLORSPACE:	log_trace("EMR_CREATECOLORSPACE"); break;
      case EMR_SETCOLORSPACE:		log_trace("EMR_SETCOLORSPACE"); break;
      case EMR_DELETECOLORSPACE:	log_trace("EMR_DELETECOLORSPACE"); break;
      case EMR_GLSRECORD:		log_trace("EMR_GLSRECORD"); break;
      case EMR_GLSBOUNDEDRECORD:	log_trace("EMR_GLSBOUNDEDRECORD"); break;
      case EMR_PIXELFORMAT:		log_trace("EMR_PIXELFORMAT"); break;
      case EMR_DRAWESCAPE :		log_trace("EMR_DRAWESCAPE "); break;
      case EMR_EXTESCAPE:		log_trace("EMR_EXTESCAPE"); break;
      case EMR_STARTDOC:		log_trace("EMR_STARTDOC"); break;
      case EMR_SMALLTEXTOUT:		log_trace("EMR_SMALLTEXTOUT"); break;
      case EMR_FORCEUFIMAPPING:		log_trace("EMR_FORCEUFIMAPPING"); break;
      case EMR_NAMEDESCAPE:		log_trace("EMR_NAMEDESCAPE"); break;
      case EMR_COLORCORRECTPALETTE:	log_trace("EMR_COLORCORRECTPALETTE"); break;
      case EMR_SETICMPROFILEA:		log_trace("EMR_SETICMPROFILEA"); break;
      case EMR_SETICMPROFILEW:		log_trace("EMR_SETICMPROFILEW"); break;
      case EMR_ALPHABLEND:		log_trace("EMR_ALPHABLEND"); break;
      case EMR_SETLAYOUT:		log_trace("EMR_SETLAYOUT"); break;
      case EMR_TRANSPARENTBLT:		log_trace("EMR_TRANSPARENTBLT"); break;
      case EMR_RESERVED_117:		log_trace("EMR_RESERVED_117"); break;
      case EMR_GRADIENTFILL:		log_trace("EMR_GRADIENTFILL"); break;
      case EMR_SETLINKEDUFI:		log_trace("EMR_SETLINKEDUFI"); break;
      case EMR_SETTEXTJUSTIFICATION:	log_trace("EMR_SETTEXTJUSTIFICATION"); break;
      case EMR_COLORMATCHTOTARGETW:	log_trace("EMR_COLORMATCHTOTARGETW"); break;
      case EMR_CREATECOLORSPACEW:	log_trace("EMR_CREATECOLORSPACEW"); break;
    }
    log_trace(" (%08x) \t%08x\n", itype, atom_size);
#endif
      if(atom_size<8 || atom_size%4!=0 || atom_size>1024*1024)
	return DC_ERROR;
      /*@ assert 8 <= atom_size <= 1024*1024; */
      file_recovery->calculated_file_size+=(uint64_t)atom_size;
      if(itype==EMR_EOF)
	return DC_STOP;
      /*@ assert file_recovery->calculated_file_size < file_recovery->file_size + buffer_size/2 - 8 + 1024*1024; */
  }
  return DC_CONTINUE;
}

/*@
  @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new);
  @ ensures  valid_header_check_result(\result, file_recovery_new);
  @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_emf.extension);
  @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
  @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= 0x34);
  @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
  @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
  @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_emf);
  @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
  @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null);
  @ assigns *file_recovery_new;
  @*/
static int header_check_emf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
  static const unsigned char emf_header[4]= { 0x01, 0x00, 0x00, 0x00};
  const struct EMF_HDR *hdr=(const struct EMF_HDR *)buffer;
  const unsigned int atom_size=le32(hdr->emr.nSize);
  if(buffer_size < sizeof(struct EMF_HDR))
    return 0;
  if(memcmp(buffer,emf_header,sizeof(emf_header))==0 &&
      le32(hdr->nBytes) >= 88 &&
      le16(hdr->sReserved)==0 &&
      atom_size>=0x34 && atom_size%4==0)
  {
    reset_file_recovery(file_recovery_new);
    file_recovery_new->extension=file_hint_emf.extension;
    if(file_recovery_new->blocksize >= 8)
    {
      file_recovery_new->data_check=&data_check_emf;
      file_recovery_new->file_check=&file_check_size;
      file_recovery_new->calculated_file_size=atom_size;
    }
    return 1;
  }
  return 0;
}

static void register_header_check_emf(file_stat_t *file_stat)
{
  static const unsigned char emf_sign[4]= { ' ','E', 'M','F'};
  register_header_check(0x28, emf_sign,sizeof(emf_sign), &header_check_emf, file_stat);
}
#endif

#if defined(MAIN_emf)
#define BLOCKSIZE 65536u
int main()
{
  const char fn[] = "recup_dir.1/f0000000.emf";
  unsigned char buffer[BLOCKSIZE];
  file_recovery_t file_recovery_new;
  file_recovery_t file_recovery;
  file_stat_t file_stats;

  /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
#if defined(__FRAMAC__)
  Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
#endif

  reset_file_recovery(&file_recovery);
  file_recovery.blocksize=BLOCKSIZE;
  file_recovery_new.blocksize=BLOCKSIZE;
  file_recovery_new.data_check=NULL;
  file_recovery_new.file_stat=NULL;
  file_recovery_new.file_check=NULL;
  file_recovery_new.file_rename=NULL;
  file_recovery_new.calculated_file_size=0;
  file_recovery_new.file_size=0;
  file_recovery_new.location.start=0;

  file_stats.file_hint=&file_hint_emf;
  file_stats.not_recovered=0;
  file_stats.recovered=0;
  register_header_check_emf(&file_stats);
  if(header_check_emf(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
    return 0;
  /*@ assert file_recovery_new.file_size == 0;	*/
  /*@ assert file_recovery_new.calculated_file_size > 0;	*/
  /*@ assert file_recovery_new.data_check == &data_check_emf; */
  /*@ assert file_recovery_new.file_check == &file_check_size; */
  /*@ assert file_recovery_new.file_rename == \null; */
  /*@ assert file_recovery_new.extension == file_hint_emf.extension; */
  /*@ assert valid_read_string(file_recovery_new.extension); */
  /*@ assert \separated(&file_recovery_new, file_recovery_new.extension); */
  /*@ assert valid_read_string((char *)&fn); */
  memcpy(file_recovery_new.filename, fn, sizeof(fn));
  /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
  /*@ assert valid_read_string((char *)file_recovery_new.filename); */
  /*X TODO assert valid_read_string(file_recovery_new.extension); */
  file_recovery_new.file_stat=&file_stats;
  {
    unsigned char big_buffer[2*BLOCKSIZE];
    data_check_t res_data_check=DC_CONTINUE;
    memset(big_buffer, 0, BLOCKSIZE);
    memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE);
    /*@ assert file_recovery_new.data_check == &data_check_emf; */
    /*@ assert file_recovery_new.file_size == 0; */;
    /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
    res_data_check=data_check_emf(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
    file_recovery_new.file_size+=BLOCKSIZE;
    if(res_data_check == DC_CONTINUE)
    {
      memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
#if defined(__FRAMAC__)
      Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
#endif
      data_check_emf(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
    }
  }
  {
    file_recovery_t file_recovery_new2;
    /* Test when another file of the same is detected in the next block */
    file_recovery_new2.blocksize=BLOCKSIZE;
    file_recovery_new2.file_stat=NULL;
    file_recovery_new2.file_check=NULL;
    file_recovery_new2.location.start=BLOCKSIZE;
    file_recovery_new.handle=NULL;	/* In theory should be not null */
    header_check_emf(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
    /*@ assert valid_read_string((char *)file_recovery_new.filename); */
  }
  /*@ assert valid_read_string((char *)file_recovery_new.filename); */
  {
    file_recovery_new.handle=fopen(fn, "rb");
    if(file_recovery_new.handle!=NULL)
    {
      file_check_size(&file_recovery_new);
      fclose(file_recovery_new.handle);
    }
  }
  return 0;
}
#endif