text: 
  /***************************************************************************
  
      MDATOPBM: Convert Microdesign area to portable bitmap
      Copyright (C) 1999 John Elliott <jce@seasip.demon.co.uk>
  
      This program 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 to the Free Software
      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  
      See the file mdaspec.txt for a specification of the MDA format.
  ******************************************************************************/
  
  #include <string.h>
  #include <stdio.h>
  #include "pbm.h"
  #include "mallocvar.h"
  
  /* Simple MDA -> portable bitmap converter */
  
  typedef unsigned char mdbyte;   /* Must be exactly one byte */
  
  static FILE *infile;            /* Input file */
  static mdbyte header[128];      /* MDA file header */
  static bit **data;          /* PBM image */
  static mdbyte *mdrow;           /* MDA row after decompression (MD3 only) */
  static int bInvert = 0;     /* Invert image? */
  static int bScale  = 0;     /* Scale image? */
  static int bAscii  = 0;     /* Ouput ASCII PBM? */
  static int nInRows, nInCols;        /* Height, width of input (rows x bytes) */
  static int nOutCols, nOutRows;      /* Height, width of output (rows x bytes) */
  
  static mdbyte 
  getbyte(void) {
      /* Read a byte from the input stream, with error trapping */
      int b;
  
      b = fgetc(infile);
  
      if (b == EOF) pm_error("Unexpected end of MDA file\n");
      
      return (mdbyte)b;
  }
  
  
  
  static void 
  render_byte(int *col, int *xp, int *yp, int b) {
  
  /* Convert a byte to 8 cells in the destination bitmap 
   *
   * *col = source column
   * *xp  = destination column
   * *yp  = destination row
   *  b   = byte to draw
   *
   * Will update *col, *xp and *yp to point to the next bit of the row.
   */
  
      int mask = 0x80;
      int n;
      int y3 = *yp;
  
      if (bScale) y3 *= 2;
  
      if (y3 >= nOutRows) return;
  
      for (n = 0; n < 8; ++n) {
          if (bInvert) data[y3][*xp] = (b & mask) ? PBM_BLACK : PBM_WHITE;
          else         data[y3][*xp] = (b & mask) ? PBM_WHITE : PBM_BLACK;
          mask = mask >> 1;
          if (bScale) data[y3+1][*xp] = data[y3][*xp];
          ++(*xp);
      }
      ++(*col);       /* Next byte */
      if ((*col) >= nInCols) {
          /* Onto next line? */
          *col = 0;
          *xp = 0;
          ++(*yp);
      }
  }
  
  
  static void 
  md2_trans(void) {
      /* Convert a MicroDesign 2 area to PBM */
      /* MD2 has RLE encoding that may go over */
  
      int x1, y1, col;    /* multiple lines. */
      mdbyte b;
      int c;
  
      x1 = y1 = col = 0;
  
      while (y1 < nInRows) {
          b = getbyte();
      
          if (b == 0 || b == 0xFF) {
              /* RLE sequence */
              c = getbyte();
              if (c == 0) c = 256;
              while (c > 0) { 
                  render_byte(&col, &x1, &y1, b); 
                  --c; 
              }
          }
          else 
              render_byte(&col, &x1, &y1, b);    /* Not RLE */
      }
  }
  
  
  
  static void 
  md3_trans(void) {
      /* Convert MD3 file. MD3 are encoded as rows, and 
         there are three types. 
      */
      int x1, y1, col;
      mdbyte b;
      int c, d, n;
  
      for (y1 = 0; y1 < nInRows; ++y1) {
          b = getbyte();   /* Row type */
          switch(b)  {
          case 0: /* All the same byte */
              c = getbyte();
              for (n = 0; n < nInCols; n++) 
                  mdrow[n] = c;
              break;
              
          case 1:      /* Encoded data */
          case 2: col = 0; /* Encoded as XOR with previous row */
              while (col < nInCols) {
                  c = getbyte();
                  if (c >= 129) {
                      /* RLE sequence */
                      c = 257 - c;
                      d = getbyte();
                      for (n = 0; n < c; ++n) {
                          if (b == 1) 
                              mdrow[col++] = d;
                          else 
                              mdrow[col++] ^= d;
                      }   
                  } else {
                      /* not RLE sequence */
                          ++c;
                          for (n = 0; n < c; ++n) {
                              d = getbyte();
                              if (b == 1) 
                                  mdrow[col++] = d;
                              else
                                  mdrow[col++] ^= d;
                          }
                  } 
              }
          }
          /* Row loaded. Convert it. */
          x1 = 0; col = 0; 
          for (n = 0; n < nInCols; ++n) {
              d  = y1;
              render_byte(&col, &x1, &d, mdrow[n]);
          }
      }
  }
  
  
  
  static void 
  usage(char *s) {        
      printf("mdatopbm v1.00, Copyright (C) 1999 "
             "John Elliott <jce@seasip.demon.co.uk>\n"
             "This program is redistributable under the terms of "
             "the GNU General Public\n"
             "License, version 2 or later.\n\n"
             "Usage: %s [ -a ] [ -d ] [ -i ] [ -- ] [ infile ]\n\n"
             "-a: Output an ASCII pbm file\n"
             "-d: Double height (to compensate for the PCW aspect ratio)\n"
             "-i: Invert colours\n"
             "--: No more options (use if filename begins with a dash)\n",
             s);
  
      exit(0);
  }
  
  
  
  int 
  main(int argc, char **argv) {
      int n, optstop = 0;
      char *fname = NULL;
  
      pbm_init(&argc, argv);
  
      /* Parse options */
  
      for (n = 1; n < argc; ++n) {
          if (argv[n][0] == '-' && !optstop) {   
              if (argv[n][1] == 'a' || argv[n][1] == 'A') bAscii = 1;
              if (argv[n][1] == 'd' || argv[n][1] == 'D') bScale = 1;
              if (argv[n][1] == 'i' || argv[n][1] == 'I') bInvert = 1;
              if (argv[n][1] == 'h' || argv[n][1] == 'H') usage(argv[0]);
              if (argv[n][1] == '-' && argv[n][2] == 0 && !fname) {
                  /* "--" */
                  optstop = 1;
              }
              if (argv[n][1] == '-' && (argv[n][2] == 'h' || argv[n][2] == 'H'))
                  usage(argv[0]);
          }
          else if (argv[n][0] && !fname) {
              /* Filename */
              fname = argv[n];
          }
      }
  
      if (fname) 
          infile = pm_openr(fname);
      else
          infile = stdin;
  
      /* Read MDA file header */
  
      if (fread(header, 1, 128, infile) < 128)
          pm_error("Not a .MDA file\n");
  
      if (strncmp((char*) header, ".MDA", 4) && 
          strncmp((char*) header, ".MDP", 4))
          pm_error("Not a .MDA file\n");
  
      {
          short yy;
          pm_readlittleshort(infile, &yy); nInRows = yy;
          pm_readlittleshort(infile, &yy); nInCols = yy;
      }
      
      overflow2(nOutCols, 8);
      nOutCols = 8 * nInCols;
      nOutRows = nInRows;
      if (bScale) {
          overflow2(nOutRows, 2);
          nOutRows *= 2;
      }
  
      data = pbm_allocarray(nOutCols, nOutRows);
      
      MALLOCARRAY_NOFAIL(mdrow, nInCols);
  
      if (header[21] == '0') 
          md2_trans();
      else
          md3_trans();
  
      pbm_writepbm(stdout, data, nInCols*8, nOutRows, bAscii);
  
      if (infile != stdin) 
          pm_close(infile);
      fflush(stdout);
      pbm_freearray(data, nOutRows);
      free(mdrow);
  
      return 0;
  }
  