home *** CD-ROM | disk | FTP | other *** search
/ DTP Toolbox / DTPToolbox.iso / utilities / archiveutils / wmf.lha / src / wmf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-04  |  14.2 KB  |  546 lines

  1. /*
  2. *  Windows Metafile Reader
  3. * $Log: wmf.c,v $
  4. *  Revision 1.16  1995/12/04  19:23:10  fuscoj
  5. *  Added debug code.
  6. *
  7. *  Revision 1.15  1995/02/20  21:21:03  JFusco
  8. *  Pre-release.
  9. *
  10. *  Revision 1.14  1994/11/08  22:10:52  JFusco
  11. *  Added iff save.
  12. *
  13. *  Revision 1.13  1994/06/27  22:40:55  JFusco
  14. *  Removed color printf()'s.
  15. *
  16. *  Revision 1.12  1994/06/26  18:03:53  JFusco
  17. *  Better support for colors and brushes, still no fill patterns.
  18. *
  19. *  Revision 1.11  1994/06/25  02:28:03  JFusco
  20. *  Better fills (?).  Tries to match luminance of color values.
  21. *
  22. *  Revision 1.10  1994/06/22  22:22:09  JFusco
  23. *  Checking to determine if Handles are being handled properly.
  24. *
  25. *  Revision 1.9  1994/06/20  23:23:06  JFusco
  26. *  Added polygon fill routines
  27. *
  28. *  Revision 1.8  1994/06/19  22:59:29  JFusco
  29. *  Removed printfs.  Uses stderr for really important info.
  30. *
  31. *  Revision 1.7  1994/06/18  03:10:00  JFusco
  32. *  Lots of changes, too numerous to mention.
  33. *  Added amiga.c and window.c so it now draws to the screen.
  34. *  
  35. */
  36.  
  37. #include <sys/types.h> /* ULONG, UWORD, etc. */
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <assert.h>
  42.  
  43. #include "dformat.h"
  44. #include "wmf.h"
  45. #include "window.h"
  46.  
  47. /* Unconditional pointer test or DIE!!!. */
  48. #define ASSERT(a)   if (!(a)) { perror("no memory!\n"); CleanExit(1); }
  49. #ifndef TRUE
  50. #define TRUE 1
  51. #endif
  52. #ifdef DEBUG
  53. int AbortFlag=0;
  54. int RecCtr=0;
  55. #define DBGREC printf("RecCtr=%d\n",RecCtr);
  56. #else
  57. #define DBGREC
  58. #endif
  59.  
  60. /* Local Prototypes. */
  61. void FunctionHandler( struct rec_tmpl * );
  62. char *wmf_func_name( unsigned short, unsigned char );
  63. unsigned CreateHandle( wmf_objects, struct rec_tmpl * );
  64.  
  65. char            *filename=NULL, *savename=NULL;
  66. wmf_hdr_t       FileHdr;
  67. static wmf_handle_t    *Handle;
  68. static wmf_place_hdr_t PlaceHdr;
  69.  
  70. unsigned     window_okay = 0;
  71.  
  72. main(int argc, char **argv)
  73. {
  74.    FILE *fin;
  75.    unsigned short hbuf[2];
  76.    struct rec_tmpl *Rec;
  77.  
  78.    if ((argc<2) || (! (fin = fopen( argv[1], "rb" )))) {
  79.       fprintf(stderr,"WMF viewer version 1.0 by John Fusco, 1994\n");
  80.       fprintf(stderr,"usage: wmf {wmf_filename} [{save_as_iff}]\n");
  81.       exit(1);
  82.    }
  83.    filename = argv[1];
  84.    if (argc==3) savename = argv[2];
  85.  
  86.    /* Read 4 bytes to determine if this is a normal or placeable metafile. */
  87.    fread( (char *) hbuf, 1, 4, fin );
  88.    reformat_short( hbuf, sizeof(hbuf) );
  89.  
  90.    /* Most files should have the place header. */
  91.    if (hbuf[0] == 0xcdd7 && hbuf[1]==0x9ac6) {
  92.       memcpy( &PlaceHdr, &hbuf[0], 4);
  93.       fread((char *)&PlaceHdr.unused0, 1,sizeof(PlaceHdr)-4,fin);
  94.       reformat_short(&PlaceHdr.unused0, sizeof(PlaceHdr)-4);
  95.  
  96.       /* Set the window extent to maximum until we're told otherwise. */
  97.       WindowExt.X = abs( PlaceHdr.Left - PlaceHdr.Right );
  98.       WindowExt.Y = abs( PlaceHdr.Top - PlaceHdr.Bottom );
  99.  
  100.       /* We can use what we have if necessary. */
  101.       window_okay = TRUE;
  102.  
  103.       /* Read the file header, which immediately follows. */
  104.       fread((char *)&FileHdr, 1,sizeof(FileHdr),fin);
  105.       reformat_short( (unsigned short *)&FileHdr, 4);
  106.    }
  107.    else {
  108.       /* No place header, just a file header. */
  109.       memcpy( &FileHdr, &hbuf[0], sizeof(hbuf));
  110.       fread((char *)&FileHdr.Ver, 1,sizeof(FileHdr)-4,fin);
  111.    }
  112.  
  113.    /* Finish little endian to big endian conversion. */
  114.    reformat_short(&FileHdr.Ver, 14);
  115.    fix_mixed_longs( &FileHdr.Fsize, sizeof(FileHdr.Fsize));
  116.    fix_mixed_longs( &FileHdr.Largest, sizeof(FileHdr.Largest));
  117.  
  118.    /* Sanity checks. */
  119.    if ( FileHdr.Type != 1  || 
  120.         FileHdr.Hsize != 9 || 
  121.         FileHdr.Largest > FileHdr.Fsize ) {
  122.       fprintf(stderr,"Not a Windows Metafile!\n");
  123.       exit(1);
  124.    }
  125.  
  126.    /* All wmf sizes are in 16-bit words. */
  127.    FileHdr.Largest <<= 1;
  128.    Rec = (struct rec_tmpl *) malloc(FileHdr.Largest);
  129.    Handle = (wmf_handle_t *)calloc(sizeof(wmf_handle_t),FileHdr.numHandles);
  130.    if (Rec==NULL || Handle==NULL) {
  131.       perror("allocating initial space.");
  132.       exit(1);
  133.    }
  134.  
  135. #ifdef DEBUG
  136.    fprintf(stderr,"Top Left     x=%6d y=%6d\n",PlaceHdr.Left,PlaceHdr.Top);
  137.    fprintf(stderr,"Bottom Right x=%6d y=%6d\n",PlaceHdr.Right,PlaceHdr.Bottom);
  138.    fprintf(stderr,"%d pixels per inch\n",PlaceHdr.pixelsPerInch);
  139.    fprintf(stderr,"%d Handles used.\n\n",FileHdr.numHandles);
  140. #endif
  141.  
  142.    while ( fread((char *)Rec, 1, 6, fin ) == 6 ) {
  143.  
  144. #ifdef DEBUG
  145.       RecCtr++;
  146. #endif
  147.       /* Little endian to big endian conversion. */
  148.       reformat_long( &Rec->Size, 4);
  149.       reformat_short(&Rec->Func, 2);
  150.  
  151.       Rec->Size <<= 1;
  152.       if (Rec->Size>FileHdr.Largest) {
  153.          fprintf(stderr,"Record too large: %ld bytes; expected %ld\n",
  154.          Rec->Size, FileHdr.Largest);
  155.          break;
  156.       }
  157.  
  158.       /* Read the rest of the record. */
  159.       Rec->Size -= 6;
  160.       if (fread((char *)Rec->Data, 1, Rec->Size, fin ) != Rec->Size ) break;
  161.  
  162.       /* Convert data, any embedded longs will have to be corrected. */
  163.       reformat_short( Rec->Data, Rec->Size );
  164.  
  165.       FunctionHandler( Rec );
  166.  
  167. #ifdef DEBUG
  168.       if (AbortFlag) break;
  169. #endif
  170.    };
  171.  
  172.    fclose(fin);
  173.    if (savename) {
  174.       AmigaSave( savename );
  175.    }
  176.    else {
  177.       AmigaWait();
  178.    }
  179.    CleanExit(0);
  180. }
  181.  
  182. void FunctionHandler( struct rec_tmpl *Rec )
  183. {
  184.    switch( Rec->Func ) {
  185. #ifdef DEBUG
  186.    case WMF_AnimatePalette:
  187.    case WMF_Arc:
  188.    case WMF_BitBlt:
  189.    case WMF_BitBlt3:
  190.    case WMF_Chord:
  191.    case WMF_DrawText:
  192.    case WMF_Ellipse:
  193.    case WMF_Escape:
  194.    case WMF_ExcludeClipRect:
  195.    case WMF_ExtTextOut:
  196.    case WMF_FloodFill:
  197.    case WMF_InsertClipRect:
  198.    case WMF_LineTo:
  199.    case WMF_MoveTo:
  200.    case WMF_OffsetClipRgn:
  201.    case WMF_OffsetViewportOrg:
  202.    case WMF_OffsetWindowOrg:
  203.    case WMF_PatBlt:
  204.    case WMF_Pie:
  205.    case WMF_PolyPolygon:
  206.    case WMF_RealizePalette:
  207.    case WMF_Rectangle:
  208.    case WMF_ResizePalette:
  209.    case WMF_RestoreDC:
  210.    case WMF_RoundRect:
  211.    case WMF_SaveDC:
  212.    case WMF_ScaleViewportExt:
  213.    case WMF_ScaleWindowExt:
  214.    case WMF_SelectClipRgn:
  215.    case WMF_SelectPalette:
  216.    case WMF_SetBkColor:
  217.    case WMF_SetBkMode:
  218.    case WMF_SetDIBitsToDevice:
  219.    case WMF_SetMapMode:
  220.    case WMF_SetMapperFlags:
  221.    case WMF_SetPaletteEntries:
  222.    case WMF_SetPixel:
  223.    case WMF_SetStretchBltMode:
  224.    case WMF_SetTextAlign:
  225.    case WMF_SetTextCharExtra:
  226.    case WMF_SetTextColor:
  227.    case WMF_SetTextJustification:
  228.    case WMF_SetViewportExt:
  229.    case WMF_SetViewportOrg:
  230.    case WMF_StretchBlt:
  231.    case WMF_StretchBlt3:
  232.    case WMF_StretchDIBits:
  233.    case WMF_TextOut:
  234.         MyDeepestApologies( Rec->Func );
  235.         break;
  236. #endif
  237.    /* Got to keep track of these even if I don't implement them. */
  238.    case WMF_CreateFontIndirect:
  239.         CreateHandle( FONT, Rec );
  240.         break;
  241.  
  242.    case WMF_CreatePalette:
  243.         CreateHandle( PALETTE, Rec );
  244.         break;
  245.  
  246.    case WMF_CreatePatternBrush:
  247.         CreateHandle( PATTERNBRUSH, Rec );
  248.         break;
  249.  
  250.    case WMF_CreatePatternBrush3:
  251.         CreateHandle( PATTERNBRUSH3, Rec );
  252.         break;
  253.  
  254.    case WMF_CreateRegion:
  255.         MyDeepestApologies( Rec->Func );
  256.         fprintf(stderr,"Did you know this function is undocumented!\n");
  257.         CleanExit(1);
  258.         break;
  259.  
  260.    /* Stuff I've actually implemented!!! (or plan to).*/
  261.    case WMF_CreatePenIndirect:
  262.         {
  263.           static WarnPenColor=1;
  264.           pen_t *Pen = (pen_t *) Rec->Data;
  265.           fix_mixed_longs( &Pen->Color, 4 );
  266.           if (Pen->Color.IDX.Type==1 && WarnPenColor) {
  267.              WarnPenColor=0;
  268.              fprintf(stderr,"Color index not implemented: %08lx\n",
  269.                                                            Pen->Color);
  270.           }
  271.         }
  272.         CreateHandle( PEN, Rec );
  273.         break;
  274.  
  275.    case WMF_CreateBrushIndirect:
  276.         {
  277.           static WarnBrushColor=1;
  278.           brush_t *Brush = (brush_t *) Rec->Data;
  279.           fix_mixed_longs( &Brush->Color, 4 );
  280.           if (Brush->Color.IDX.Type==1 && WarnBrushColor) {
  281.              DBGREC;
  282.              WarnBrushColor=0;
  283.              fprintf(stderr,"Color index not implemented: %08lx\n",
  284.                                                            Brush->Color);
  285.           }
  286.         }
  287.         CreateHandle( BRUSH, Rec );
  288.         break;
  289.  
  290.    case WMF_SelectObject:
  291.         assert( Rec->Data[0]<FileHdr.numHandles && Rec->Data[0] >= 0 );
  292.     SelectObject( Rec->Data[0] );
  293.         break;
  294.  
  295.    case WMF_DeleteObject:
  296.         assert( Rec->Data[0]<FileHdr.numHandles && Rec->Data[0] >= 0 );
  297.         {
  298.            unsigned idx = Rec->Data[0];
  299.            Handle[idx].Type = NOTANOBJ;
  300.            free( Handle[idx].Data );
  301.            Handle[idx].Data = NULL;
  302.         }
  303.         break;
  304.  
  305.  
  306.    case WMF_Polygon:
  307.         {
  308.           unsigned i;
  309.           poly_point_tmpl_t *Poly= (poly_point_tmpl_t *) Rec->Data;
  310.  
  311.           PolygonMoveWC( Poly->Point[0].X, Poly->Point[0].Y );
  312.           for (i=1; i<Poly->numPoints; i++) {
  313.             PolygonDrawWC( Poly->Point[i].X, Poly->Point[i].Y );
  314.           }
  315.           PolygonEndWC();
  316.         }
  317.         break;
  318.  
  319.    case WMF_Polyline:
  320.         {
  321.           unsigned i;
  322.           poly_point_tmpl_t *Poly= (poly_point_tmpl_t *) Rec->Data;
  323.  
  324.           MoveWC( Poly->Point[0].X, Poly->Point[0].Y );
  325.           for (i=1; i<Poly->numPoints; i++) {
  326.             DrawWC( Poly->Point[i].X, Poly->Point[i].Y );
  327.           }
  328.         }
  329.         break;
  330.  
  331.    case WMF_SetPolyFillMode:
  332.         {
  333.            static warn=0;
  334.            if (warn==0) {
  335.               DBGREC;
  336.               warn = 1;
  337.               fprintf(stderr,"Using default fill mode\n");
  338.            }
  339.         }
  340.         break;
  341.  
  342.    case WMF_SetWindowExt:
  343.         memcpy( &WindowExt, &Rec->Data[0], sizeof(WindowExt));
  344.         InitVirtualWindow( &PlaceHdr );
  345.         OpenAmigaWindow();
  346.         break;
  347.  
  348.    case WMF_SetWindowOrg:
  349.         memcpy( &WindowOrg, &Rec->Data[0], sizeof(WindowOrg));
  350.         break;
  351.  
  352.    case WMF_SetROP2:
  353.         SetDrawingMode( Rec->Data[0] ); 
  354.         break;
  355.  
  356.    case WMF_Null:
  357.         break;
  358.  
  359.    default:
  360.         DBGREC;
  361.         fprintf(stderr,"%s: Unknown function (%x)\n", filename, Rec->Func);
  362.         break;
  363.    }
  364.    return;
  365. }
  366.  
  367. MyDeepestApologies( USHORT Func )
  368. {
  369.    DBGREC;
  370.    fprintf(stderr,"WARNING: %s unimplemented and is being ignored!\n",
  371.                    wmf_func_name( Func, 0 ));
  372. }
  373.  
  374. CleanExit(int x)
  375. {
  376.    CleanAmiga();
  377.    exit(x);
  378. }
  379.  
  380. /* Lookup values for metafile functions. */
  381. struct function_code {
  382.    unsigned short opcode;
  383.    char *name, found; 
  384. } wmf_function[] = {
  385.       {0x000,"Null",0},
  386.       {0x01e,"SaveDC",0},
  387.       {0x035,"RealizePalette",0},
  388.       {0x037,"SetPaletteEntries",0},
  389.       {0x0f7,"CreatePalette",0},
  390.       {0x102,"SetBkMode",0},
  391.       {0x103,"SetMapMode",0},
  392.       {0x104,"SetROP2",0},
  393.       {0x106,"SetPolyFillMode",0},
  394.       {0x107,"SetStretchBltMode",0},
  395.       {0x108,"SetTextCharExtra",0},
  396.       {0x127,"RestoreDC",0},
  397.       {0x12c,"SelectClipRgn",0},
  398.       {0x12d,"SelectObject",0},
  399.       {0x12e,"SetTextAlign",0},
  400.       {0x139,"ResizePalette",0},
  401.       {0x142,"CreatePatternBrush3",0},
  402.       {0x1f0,"DeleteObject",0},
  403.       {0x1f9,"CreatePatternBrush",0},
  404.       {0x201,"SetBkColor",0},
  405.       {0x209,"SetTextColor",0},
  406.       {0x20a,"SetTextJustification",0},
  407.       {0x20b,"SetWindowOrg",0},
  408.       {0x20c,"SetWindowExt",0},
  409.       {0x20d,"SetViewportOrg",0},
  410.       {0x20e,"SetViewportExt",0},
  411.       {0x20f,"OffsetWindowOrg",0},
  412.       {0x211,"OffsetViewportOrg",0},
  413.       {0x213,"LineTo",0},
  414.       {0x214,"MoveTo",0},
  415.       {0x220,"OffsetClipRgn",0},
  416.       {0x231,"SetMapperFlags",0},
  417.       {0x234,"SelectPalette",0},
  418.       {0x2fa,"CreatePenIndirect",0},
  419.       {0x2fb,"CreateFontIndirect",0},
  420.       {0x2fc,"CreateBrushIndirect",0},
  421.       {0x324,"Polygon",0},
  422.       {0x325,"Polyline",0},
  423.       {0x400,"ScaleWindowExt",0},
  424.       {0x412,"ScaleViewportExt",0},
  425.       {0x415,"ExcludeClipRect",0},
  426.       {0x416,"InsertClipRect",0},
  427.       {0x418,"Ellipse",0},
  428.       {0x419,"FloodFill",0},
  429.       {0x41b,"Rectangle",0},
  430.       {0x41f,"SetPixel",0},
  431.       {0x436,"AnimatePalette",0},
  432.       {0x521,"TextOut",0},
  433.       {0x538,"PolyPolygon",0},
  434.       {0x61c,"RoundRect",0},
  435.       {0x61d,"PatBlt",0},
  436.       {0x626,"Escape",0},
  437.       {0x62f,"DrawText",0},
  438.       {0x6ff,"CreateRegion",0},
  439.       {0x817,"Arc",0},
  440.       {0x81a,"Pie",0},
  441.       {0x830,"Chord",0},
  442.       {0x922,"BitBlt",0},
  443.       {0x940,"BitBlt3",0},
  444.       {0xa32,"ExtTextOut",0},
  445.       {0xb23,"StretchBlt",0},
  446.       {0xb41,"StretchBlt3",0},
  447.       {0xd33,"SetDIBitsToDevice",0},
  448.       {0xf43,"StretchDIBits",0},
  449.       {0xffff,"Unknown Function",0} /* This must be last */
  450. };
  451.  
  452. char *wmf_func_name( unsigned short func, unsigned char dup )
  453. {
  454.    unsigned i;
  455.  
  456.    /* Last function will be "Unknown" if we got through the loop
  457.    /* without a find. */
  458.    for(i=0; i<sizeof(wmf_function)/sizeof(wmf_function[0]); i++) {
  459.       if (wmf_function[i].opcode >= func) break;
  460.    }
  461.    if ((wmf_function[i].opcode == func) && ! (wmf_function[i].found) ) {
  462.       if (dup) wmf_function[i].found = 1;
  463.       return( wmf_function[i].name );
  464.    }
  465.    else if (wmf_function[i].found)
  466.      return( NULL );
  467.    else
  468.      return( wmf_function[i].name ); /* Unknown function. */
  469. }
  470.  
  471. SelectObject( unsigned short idx )
  472. {
  473.    /* NOTANOBJ, BRUSH, FONT, PALETTE, PATTERNBRUSH, PATTERNBRUSH3, PEN */
  474.    switch ( Handle[idx].Type ) {
  475.  
  476.    case PEN:
  477.       SetPenStyleAmiga( Handle[idx].Data );
  478.       break;
  479.  
  480.    case BRUSH:
  481.       SetBrushStyleAmiga( Handle[idx].Data );
  482.       break;
  483.  
  484.    case FONT:
  485.       {
  486.          static warn=0;
  487.          if (!(warn)) {
  488.             warn=1;
  489.             DBGREC;
  490.             fprintf(stderr,"Font objects not selectable\n"); 
  491.          }
  492.       }
  493.       break;
  494.  
  495.    case PALETTE:
  496.       {
  497.          static warn=0;
  498.          if (!(warn)) {
  499.             warn=1;
  500.             DBGREC;
  501.             fprintf(stderr,"Palette objects not selectable\n"); 
  502.          }
  503.       }
  504.       break;
  505.  
  506.    case PATTERNBRUSH:
  507.    case PATTERNBRUSH3:
  508.       {
  509.          static warn=0;
  510.          if (!(warn)) {
  511.             warn=1;
  512.             DBGREC;
  513.             fprintf(stderr,"Pattern brush objects not selectable\n"); 
  514.          }
  515.       }
  516.       break;
  517.  
  518.    default:
  519.       DBGREC;
  520.       fprintf(stderr,"Unimplemented object selected %ld\n",Handle[idx].Type); 
  521.       break;
  522.    };
  523. }
  524.  
  525. unsigned CreateHandle( wmf_objects Type, struct rec_tmpl *Rec )
  526. {
  527.    unsigned i;
  528.  
  529.    /* Find free slot. */
  530.    for (i=0; i<FileHdr.numHandles; i++) {
  531.       if (Handle[i].Type == NOTANOBJ) break;
  532.    };
  533.  
  534.    if (i>=FileHdr.numHandles) {
  535.       fprintf(stderr,"Corrupt WMF file!  Bad handle.\n");
  536.       CleanExit(1);
  537.    };
  538.       
  539.    Handle[i].Type = Type;
  540.    Handle[i].Data = (USHORT *) malloc( Rec->Size );
  541.    ASSERT(Handle[i].Data);
  542.    memcpy( &Handle[i].Data[0], &Rec->Data[0], Rec->Size );
  543.    return i;
  544. }
  545.