Source file: /~heha/hs/dos/dosmisc.zip/SRC/WMF.C

/* WMF decoder/viewer, based on code by a taiwanese programmer */

// compiler: BC3.1, target: DOS, model: small, calling: pascal
// floatpoint: none, alignment: 2
// h#s 11/06
#include <stdio.h>

#define elemof(x) (sizeof(x)/sizeof((x)[0]))
typedef enum {false, true} bool;

const int regular[] = {
 0x001E,0x0035,0x0037,0x004F,0x0050,0x0052,0x005E,0x0102,0x0103,
 0x0104,0x0105,0x0106,0x0107,0x0108,0x0127,0x012A,0x012B,0x012C,
 0x012D,0x012E,0x012E,0x0139,0x014C,0x014D,0x01f0,0x0201,
 0x020A,0x020B,0x020C,0x020D,0x020E,0x020F,0x0211,0x0213,0x0214,
 0x0220,0x0228,0x0231,0x0410,0x0412,0x0415,0x0416,0x0418,
 0x0419,0x041B,0x041F,0x0429,0x0548,0x061C,0x061D,0x0817,0x081A,
 0x0830,0x0d33,0x0000,
};

const char *regtext[] = {
 "SaveDC","RealizePalette","SetPalEntries","StartPage","EndPage",
 "AbortDoc","EndDoc","SetBkMode","SetMapMode","SetROP2","SetRelabs",
 "SetPolyFillMode","SetStretchBltMode","SetTextCharExtra","RestoreDC",
 "InvertRegion","PaintRegion","SelectClipRegion","SelectObject",
 "SetTextAlign","SetTextAlign","ResizePalette","ResetDc","StartDoc",
 "DeleteObject","SetBkColor","SetTextJustification",
 "SetWindowOrg","SetWindowExt","SetViewportOrg","SetViewportExt",
 "OffsetWindowOrg","OffsetViewportOrg","LineTo","MoveTo",
 "OffsetClipRgn","FillRegion","SetMapperFlags","ScaleWindowExt",
 "ScaleViewportExt","ExcludeClipRect","IntersectClipRect","Ellipse",
 "FloodFill","Rectangle","SetPixel","FrameRegion","ExtFloodFill",
 "RoundRect","PatBlt","Arc","Pie","Chord","SetDibToDev","EOF"
};

const int unregular[] = {
 0x00F7,0x00F8,0x0142,0x01F0,0x01F9,0x0234,0x02FA,0x02FB,0x02FC,
 0x02FD,0x0324,0x0325,0x0436,0x0521,0x0538,0x0626,0x062F,
 0x06FE,0x06FF,0x0922,0x0940,0x0A32,0x0B23,0x0B41,0x0F43,0x0209
};

const char *unregtext[] = {
 "CreatePalette","CreateBrush","DibCreatePatternBrush","DeleteObject",
 "CreatePatternBrush","SelectPalatte","CreatePenIndirect",
 "CreateFontIndirect",
 "CreateBrushIndirect","CreateBitmapIndirect","Polygon","Polyline",
 "AnimatePalette","TextOut","PolyPolygon","Escape","DrawText",
 "CreateBitmap","CreateRegion","BitBlt","DibBitblt","ExtTextOut",
 "StretchBlt","DibStretchBlt","StretchDIBits","SetTextColor"
};

int in_regular (int func) {
 int i;
 for (i=0; i<elemof(regular); i++)
   if (regular[i] == func) return i;
 return -1;
}

int in_unreg (int func) {
 int i;
 for (i=0; i<elemof(unregular); i++)
   if (unregular[i] == func) return i;
 return -1;
}

static const long HtmlColors[]={
 0x000000L,0x808080L,0x800000L,0xFF0000L,
 0x008000L,0x00FF00L,0x808000L,0xFFFF00L,
 0x000080L,0x0000FFL,0x800080L,0xFF00FFL,
 0x008080L,0x00FFFFL,0xC0C0C0L,0xFFFFFFL};

static const char *HtmlNames[]={
 "black","gray","maroon","red",
 "green","lime","olive","yellow",
 "navy","blue","purple","fuchsia",
 "teal","aqua","silver","white"};

const char* C(long color) {
 static char buf[8];
 int i;
 color=((color&0xFF)<<16)|(color&0xFF00)|((color>>16)&0xFF);
 for (i=0; i<elemof(HtmlColors); i++)
   if (color==HtmlColors[i]) return HtmlNames[i];
 sprintf(buf,"#%06X",color);
 return buf;
}

bool funcprint(FILE *out, FILE *wmf) {
 int a, i, j;
 long l,recstart;
 struct{
  long len;
  short fu;
 }rhdr;

 fprintf(out,"============= Records =================\n");
 recstart=ftell(wmf);
 if (fread(&rhdr,sizeof(rhdr),1,wmf)!=1) return false;
 fprintf(out,"Size:\t\t%ld\n",rhdr.len);
 fprintf(out,"Function:\t%04x\n",rhdr.fu);
 a=in_regular(rhdr.fu);
 if (a>=0) {
  fprintf(out,"Name:\t\t%s(",regtext[a]);
  for (i=3; i<rhdr.len; i++) {
   short val;
   fread(&val,sizeof(val),1,wmf);
   if (i>3) fputc(',',out);
   fprintf(out,"%d",val);
  }
  fprintf(out,")\n");
  if (!rhdr.fu) return false;	// exit on EOF record
 }else{ // not regular function
  a=in_unreg(rhdr.fu);
  if (a>=0) {
   fprintf(out,"Name:\t\t%s\n",unregtext[a]);
   switch (rhdr.fu) {
    case 0x0F7:	{	// CreatePalette
     struct{
      short ver;
      short num;
     }h;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"Version:\t%04x\n",h.ver);
     fprintf(out,"Num of Entry:\t%d\n",h.num);
     for (i=0; i<h.num; i++) {
      fread(&l,4,1,wmf);
      fprintf(out,"Entry %3d:\t%08lx\n",i+1,l);
     }
    }break;

    case 0x142: {	// CreatePatternBrush3
     struct{
      short type;
      short usage;
     }h;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"Type:\t%04x\n",h.type);
     fprintf(out,"Usage:\t%04x\n",h.usage);
			// not over...
    }break;

    case 0x234: {		// SelectPalette
     short h;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"Handle:\t\t%04x\n",h);
    }break;

    case 0x2FA: {		// CreatePenIndirect
     const char *sty[]={
       "solid","dashed","dotted","dot and dash",
       "dash ans two dots","none","inside frame"};
     struct{
      short style;
      short width;
      short height;
      long color;
     }h;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"Style:\t\t%d\t%s\n",h.style,
       (unsigned)h.style<elemof(sty)?sty[h.style]:"?");
     fprintf(out,"Width:\t\t%d\n",h.width);
     fprintf(out,"Color:\t\t%06lX\t%s\n",h.color,C(h.color));
    }break;

    case 0x209: {		// SetTextColor
     long color;
     fread(&color,sizeof(color),1,wmf);
     fprintf(out,"Color:\t\t%06lX\t%s\n",color,C(color));
    }break;

    case 0x2FB: {		// CreateFontIndirect
     struct{
      short height;
      short width;
      short escape;
      short orient;
      short weight;
      char italic;
      char underline;
      char strikeout;
      char charset;
      char oprecis;
      char cprecis;
      char oqual;
      char pitch_fam;
      char facename[32];
     }h;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"Height:\t\t%d\n",h.height);
     fprintf(out,"Width:\t\t%d\n",h.width);
     fprintf(out,"Escapement:\t%d\t%d.%d°\n",h.escape,h.escape/10,h.escape%10);
     fprintf(out,"Orientation:\t%d\t%d.%d°\n",h.orient,h.orient/10,h.orient%10);
     fprintf(out,"Weight:\t\t%d\n",h.weight);
     fprintf(out,"Italic:\t\t%d\t%s\n",h.italic,h.italic?"yes":"no");
     fprintf(out,"UnderLine:\t%d\t%s\n",h.underline,h.underline?"yes":"no");
     fprintf(out,"Strikeout:\t%d\t%s\n",h.strikeout,h.strikeout?"yes":"no");
     fprintf(out,"Character set:\t%d\n",h.charset);
     fprintf(out,"Output Precis:\t%d\n",h.oprecis);
     fprintf(out,"Clip Precis:\t%d\n",h.cprecis);
     fprintf(out,"Output Quality:\t%d\n",h.oqual);
     fprintf(out,"Pitch:\t\t%d\n",h.pitch_fam&3);
     fprintf(out,"Font type:\t%d\n",h.pitch_fam>>4);
     fprintf(out,"Font face Name:\t%.32s\n",h.facename);
    }break;

    case 0x2FC: {		// CreateBrushIndirect
     struct{
      short style;
      long color;
      short hatch;
     }h;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"Style:\t\t%d\n",h.style);
     fprintf(out,"Color:\t\t%06lX\t%s\n",h.color,C(h.color));
     fprintf(out,"Cross-hatch line type:%d\n",h.hatch);
    }break;

    case 0x325:		// Polyline
    case 0x324: {	// Polygon
     short h;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"Num of Points:\t%d\n",h);
     for (i=0; i<h; i++) {
      struct{
       short x;
       short y;
      }p;
      fread(&p,sizeof(p),1,wmf);
      fprintf(out,"Point %4d:\t(%3d,%3d)\n",i,p.x,p.y);
     }
    }break;

    case 0x436: {		// AnimatePalatte
     struct{
      short start;
      short num;
     }h;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"Starting Palette Entry Number:\t%d\n",h.start);
     fprintf(out,"Number of entries to animete:\t%d\n",h.num);
     for (i=0; i<h.num; i++) {
      long l;
      fread(&l,sizeof(l),1,wmf);
      fprintf(out,"New Palette Entry %d:\t%08x\n",i,l);
     }
    }break;

    case 0x521: {		// TextOut
     short h;
     struct {
      short y;
      short x;
     }p;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"String Length:\t%d\n",h);
     fprintf(out,"String:\t\t");
     for (i=0; i<h; i++) {
      char c;
      c=fgetc(wmf);
      fputc(c,out);
     }
     fputc('\n',out);
     if (h&1) fgetc(wmf);	// odd number of characters: align file pointer
     fread(&p,sizeof(p),1,wmf);
     fprintf(out,"X Origin:\t%d\n",p.x);
     fprintf(out,"Y Origin:\t%d\n",p.y);
    }break;

    case 0x538: {		// PolyPolygon
     short npoly;
     fread(&npoly,sizeof(npoly),1,wmf);
     fprintf(out,"Num of Polygons:\t%d\n",npoly);
     for (i=j=0; i<npoly; i++) {
      short npt;
      fread(&npt,sizeof(npt),1,wmf);
      j+=npt;
      fprintf(out,"Polygon %d has %d points\n",i,npt);
     }
     for (i=0; i<j; i++) {
      struct{
       short x;
       short y;
      }p;
      fread(&p,sizeof(p),1,wmf);
      fprintf(out,"Point %d:\t(%3d,%3d)\n",i,p.x,p.y);
     }
    }break;

    case 0x626: {		// Escape
     struct{
      short num;
      short size;
     }h;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"Escape Number:\t%d\n",h.num);
     fprintf(out,"Escape Size:\t%d\n",h.size);
     fprintf(out,"Escape Data:\t");
     for (i=0; i<h.size; i++) {
      char c;
      c=fgetc(wmf);
      fputc(c,out);
     }
     fputc('\n',out);
    }break;

    case 0x940: {		// BitBlt3
     struct{
      short too;
      short y;
      short x;
      short dh;
      short dw;
      short dy;
      short dx;
      short bfType;
      long  bfSize;
      long  u1;
      long  bfOffbits;
      long  biSize;
      long  biWidth;
      long  biHeight;
      short biPlanes;
      short biBitCount;
      long  biCompression;
      long  biSizeImage;
      long  biXPelsPerMeter;
      long  biYPelsPerMeter;
      long  biClrUsed;
      long  biClrImportant;
     }h;
     fread(&h,sizeof(h),1,wmf);
     fprintf(out,"Type of Operation:\t%d\n",h.too);
     fprintf(out,"Bitmap Y Origin:\t\t%d\n",h.y);
     fprintf(out,"Bitmap X Origin:\t\t%d\n",h.x);
     fprintf(out,"Destination area height:\t%d\n",h.dh);
     fprintf(out,"Destination area width:\t%d\n",h.dw);
     fprintf(out,"Destination Y Origin:\t%d\n",h.dy);
     fprintf(out,"Destination X Origin:\t%d\n",h.dx);
     fprintf(out,"------ Bitmap File Header -------\n");
     fprintf(out,"\tbfType:\t%d\n",h.bfType);
     fprintf(out,"\tbfSize:\t%d\n",h.bfSize);
     fprintf(out,"\tbfOffbits:\t%d\n",h.bfOffbits);
     fprintf(out,"------ Windows 3 Bitmap Header --\n");
     fprintf(out,"\tbiSize:\t%d\n",h.biSize);
     fprintf(out,"\tbiWidth:\t%d\n",h.biWidth);
     fprintf(out,"\tbiHeight:\t%d\n",h.biHeight);
     fprintf(out,"\tbiPlanes:\t%d\n",h.biPlanes);
     fprintf(out,"\tbiBitCount:\t%d\n",h.biBitCount);
     fprintf(out,"\tbiCompression:\t%d\n",h.biCompression);
     fprintf(out,"\tbiSizeImage:\t%d\n",h.biSizeImage);
     fprintf(out,"\tbiXPelsPerMeter:\t%d\n",h.biXPelsPerMeter);
     fprintf(out,"\tbiYPelsPerMeter:\t%d\n",h.biYPelsPerMeter);
     fprintf(out,"\tbiClrUsed:\t%d\n",h.biClrUsed);
     fprintf(out,"\tbiClrImportant:\t%d\n",h.biClrImportant);
     for (i=0; i<h.biClrUsed; i++) {
      long l;
      fread(&l,sizeof(l),1,wmf);
      fprintf(out,"\tColor Map:\t06lX\t%s\n",l,C(l));
     }
    }break;

   }
  }else{
   fprintf(out,"Unknown record:\t\t%X\n",rhdr.fu);
  }
 }
 fseek(wmf,recstart+rhdr.len*2,0);	// position file pointer to next
 return true;
}

void pheadprint(FILE *out, FILE*wmf) {
 struct{
  long  id;
  short handle;
  short left;
  short top;
  short right;
  short bottom;
  short inch;
  long  reserved;
  short checksum;
 }h;
 fread(&h,sizeof(h),1,wmf);
 fprintf(out,"=============== Placeable Heads =======\n");
 fprintf(out,"Top Left X:\t%d\n",h.left);
 fprintf(out,"Top Left Y:\t%d\n",h.top);
 fprintf(out,"Bottom Right X:\t%d\n",h.right);
 fprintf(out,"Bottom Right Y:\t%d\n",h.bottom);
 fprintf(out,"Scale:\t\t%d units per inch\n",h.inch);
 fprintf(out,"Checksum:\t%d\n",h.checksum);
}

void headprint(FILE *out, FILE*wmf) {
 long l;
 struct{
  short type;
  short headsize;
  short version;
  long  filesize;	// this struct requires at least pack(2)!!
  short nobj;
  long  maxrecsize;
  short nparams;
 }h;
 fread(&l,sizeof(l),1,wmf);
 fseek(wmf,-4,1);	// seek back
 if (l==0x9AC6CDD7UL)	// placeable metafile
   pheadprint(out,wmf);
 fread(&h,sizeof(h),1,wmf);
 fprintf(out,"=============== Heads =================\n");
 fprintf(out,"Filetype:\t%d\n",h.type);
 fprintf(out,"Head Size:\t%d words\n",h.headsize);
 fprintf(out,"Version:\t%#x\n",h.version);
 fprintf(out,"File Size:\t%ld words\n",h.filesize);
 fprintf(out,"Num of Object:\t%d\n",h.nobj);
 fprintf(out,"Max Record Size:%ld words\n",h.maxrecsize);
 fprintf(out,"Num of Params:\t%d(not use)\n\n",h.nparams);
}

int _cdecl main (int argc, char **argv) {
 FILE *wmf, *out;

 if (argc < 2) {
  printf("Usage:\t%s wmf-file out-file\n",argv[0]);
  return 1;
 }

 wmf=fopen(argv[1],"rb");
 if (argc==3) out=fopen(argv[2],"wt");
 else out=fopen("out.txt","wt");

 headprint(out,wmf);
 while (funcprint(out,wmf));
 return 0;
}
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded