home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / mandsteg.zip / gifextr.c < prev    next >
C/C++ Source or Header  |  1999-01-18  |  10KB  |  471 lines

  1. /*
  2.  * Gifextract.c V1.0 
  3.  * (C) Copyright Henry Hastur 1994
  4.  *
  5.  * Extracts an arbitrary bit-plane from a GIF file. 
  6.  *
  7.  * This program is copyright Henry Hastur 1994, but may be freely distributed,
  8.  * modified, incorporated into other programs and used, as long as the
  9.  * copyright stays attached and you obey any relevant import or export
  10.  * restrictions on the code. No warranty is offered, and no responsibility
  11.  * is taken for any damage use of this program may cause. In other words,
  12.  * do what you want with it, but don't expect me to pay up if anything
  13.  * unexpected goes wrong - you're using it at your own risk...
  14.  *
  15.  * Note : This file contains some fairly bizarre uses of casts. These
  16.  * were neccesary to get DOS to work, and once it was going I wasn't
  17.  * brave enough to remove any that appeared to be unneccesary in case
  18.  * I broke everything again !
  19.  *
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <malloc.h>
  25.  
  26. #ifdef DOS
  27. #include <fcntl.h>
  28. #include <io.h>
  29. #endif
  30.  
  31. #ifdef __IBMC__
  32. #include <string.h>
  33. #include <fcntl.h>
  34. #include <io.h>
  35. #endif
  36.  
  37. #include "ext.h"
  38. #include "gif.h"
  39.  
  40. /* The following defines the size of buffer we use. Set it to whatever
  41.    seems reasonable for your machine - the larger the better. */
  42.  
  43. #define IN_SIZE         32000
  44. #define OUT_SIZE        32000
  45.  
  46. static  int32   data_size = 0;
  47. static  int32   data_bit_offset = 0;
  48.  
  49. static  int16   bm_width, bm_height;
  50. static  int16   lzw_code_size, lzw_init_size;
  51.  
  52. static  word    lzw_clear_code, lzw_eof_code, lzw_max_code;
  53. static  word    lzw_code_read, lzw_read_mask;
  54. static  word    lzw_first_free, lzw_next_free;
  55.  
  56. typedef struct {
  57.  
  58.     word    pred;
  59.     word    code;
  60.  
  61. } ENTRY;
  62.  
  63. static  ENTRY   code_table[MAX_CODES];
  64. static  byte    lzw_pix_buffr[OUT_SIZE];
  65.  
  66. static  int16   x_coord = 0, y_coord = 0;
  67.  
  68. static  byte    same_col = TRUE;
  69. static  byte    data_bit = 0x80;
  70. static  byte    analyse = FALSE;
  71.  
  72. static  int32   byte_pad = 0;
  73. static  int32   steg_size = 0l;
  74. static  int32   zero_bits = 0;
  75. static  int32   one_bits = 0;
  76.  
  77. /* Read a word in little-endian form */
  78.  
  79. static word get_w(fp)
  80.  
  81. FILE    *fp;
  82.  
  83. {
  84.     word    c1,c2;
  85.  
  86.     c1 = getc(fp);
  87.     c2 = getc(fp);
  88.  
  89.     return ((c2 << 8) + c1);
  90. }
  91.  
  92. /* Read some data from the file into our buffer */
  93.  
  94. static void read_some_data(fp, compressed, start_byte_pos)
  95.  
  96. FILE    *fp;
  97. byte    *compressed;
  98. long    start_byte_pos;
  99.  
  100. {
  101.     int16   i,c = 0;
  102.     int16   data_block_length;
  103.     long    j;
  104.  
  105.     j = start_byte_pos;
  106.     do {
  107.         data_block_length = getc(fp);
  108.         for (i=0; c != EOF && i < data_block_length; i++) {
  109.             c = getc(fp);
  110.             if (c != EOF)
  111.                 compressed[j++] = c;
  112.         }
  113.  
  114.     } while(data_block_length > 0 && c != EOF && (j < (IN_SIZE - 256)));
  115.  
  116.     data_size = j;
  117. }
  118.  
  119. /* Extract a variable-length code from the compressed data */
  120.  
  121. static int read_a_code(fp,compressed)
  122.  
  123. FILE    *fp;
  124. byte    *compressed;
  125.  
  126. {
  127.     lword   code24;
  128.     long    data_byte_offset;
  129.     word    c1, c2;    /* These are used to keep DOS happy */
  130.  
  131.     data_byte_offset = data_bit_offset/8;
  132.  
  133.     if (data_byte_offset > (data_size-8)) {
  134.         int     i;
  135.  
  136.         for (i=0; i<(data_size - data_byte_offset); i++) {
  137.             compressed[i] = compressed[data_byte_offset+i];
  138.         }
  139.  
  140.         read_some_data (fp, compressed, (long)i);
  141.  
  142.         data_byte_offset=0l;
  143.         data_bit_offset%=8;
  144.  
  145.         if (!data_size)
  146.             return FALSE;
  147.     }
  148.  
  149.     /* Unix worked fine without temporary storage in c1 and c2,
  150.        but DOS was getting casts wrong. This works, and I don't
  151.        want to change it ! */
  152.  
  153.     c1 = compressed[data_byte_offset]
  154.         + (compressed[data_byte_offset + 1] << 8);
  155.  
  156.     if (lzw_code_size >= 8) {
  157.         c2 = (compressed[data_byte_offset + 2]);
  158.         code24 = (lword)c1 + (((lword)c2) << 16);
  159.     }
  160.     else
  161.         code24 = (lword)c1 ;
  162.  
  163.     code24 >>= (data_bit_offset % 8);
  164.     lzw_code_read = (code24 & (lword)lzw_read_mask);
  165.  
  166.     data_bit_offset += lzw_code_size;
  167.  
  168.     return TRUE;
  169. }
  170.  
  171. /* Output a pixel - in our case extract the stegg-ed data */
  172.  
  173. static void     output_pixel (val)
  174.  
  175. byte    val;
  176.  
  177. {
  178.     static  byte    last_startpix = 0;
  179.     static  int     outc = 0;
  180.     static  int     out_count = 0;
  181.     static  byte    opix = 0;
  182.     static  byte    last_missed = FALSE;
  183.     byte    pix;
  184.  
  185.     if (!x_coord) {
  186.         if (y_coord)
  187.             opix = last_startpix;
  188.         last_startpix = val & (~data_bit);
  189.     }
  190.  
  191.     pix = val & (~data_bit); 
  192.  
  193.     if (same_col || (pix != opix && (x_coord || y_coord))) {
  194.         if (last_missed) 
  195.             last_missed = FALSE;
  196.         else {
  197.             outc <<= 1;
  198.             if (val & data_bit)
  199.                 outc |= 1;
  200.  
  201.             if (analyse && !byte_pad) {
  202.                 if (val & data_bit)
  203.                     one_bits ++;
  204.                 else
  205.                     zero_bits ++;
  206.             }
  207.  
  208.             out_count++;
  209.  
  210.             if (out_count == 8) {
  211.  
  212.                 if (!byte_pad) {
  213.                     if (!analyse)
  214.                         putchar(outc);
  215.                 }
  216.                 else
  217.                     byte_pad--;
  218.  
  219.                 out_count = 0;
  220.                 outc = 0;
  221.             }
  222.         }
  223.     }
  224.     else
  225.         last_missed = TRUE;
  226.  
  227.     opix = pix;
  228.  
  229.     x_coord++;
  230.     if (x_coord >= bm_width) {
  231.         x_coord=0;
  232.         y_coord++;
  233.     }
  234. }
  235.  
  236. /* Print a usage message */
  237.  
  238. void    usage ()
  239.  
  240. {
  241.     fprintf(stderr,"Usage: gifextract [-a] [-ns] [-bp padding] [-b bit] [file]\n");
  242. }
  243.  
  244. /* Do everything else */
  245.  
  246. main(argc,argv)
  247.  
  248. int     argc;
  249. char    *argv[];
  250.  
  251. {
  252.     char    header_string[7];
  253.     FILE    *input_file;
  254.     byte    *compressed = NULL;
  255.     char    *file_name = NULL;
  256.     word    lzw_current_code = 0, lzw_old_code = 0, lzw_in_code = 0;
  257.     int     i, buffered_pixels = 0;
  258.     byte    has_colormap = 0, last_pixel = 0, pixel_bit_mask = 0;
  259.     word    num_colors = 0, bits_per_pixel = 0;
  260.  
  261.     i = 1;
  262.  
  263.     while (i < argc) {
  264.         if (!strcmp(argv[i],"-ns")) {
  265.             same_col = FALSE;
  266.         }
  267.         else if (!strcmp(argv[i],"-a")) {
  268.             analyse = TRUE;
  269.         }
  270.         else if (!strcmp(argv[i],"-b")) {
  271.             if (i == (argc - 1)) {
  272.                 usage ();
  273.                 exit (1);
  274.             }
  275.             data_bit = ((1 << atoi(argv[++i])) & 0xFF);
  276.             if (!data_bit) {
  277.                 fprintf(stderr, "Bad bit specified, defaulting to 7!\n");
  278.                 data_bit = 0x80;
  279.             }
  280.         }
  281.         else if (!strcmp(argv[i],"-bp")) {
  282.             if (i == (argc - 1)) {
  283.                 usage ();
  284.                 exit (1);
  285.             }
  286.             byte_pad = atol (argv[++i]);
  287.         }
  288.         else
  289.             file_name = argv[i];
  290.         i++;
  291.     }
  292.            
  293.     /* Following needed for binary stdin/stdout on DOS */
  294.  
  295. #ifdef DOS
  296.     _fmode = O_BINARY;
  297.     setmode (fileno(stdin), O_BINARY);
  298.  
  299.     if (!analyse) {
  300.         setmode (fileno(stdout), O_BINARY);
  301.     }
  302. #endif
  303.  
  304.        /* ...and on OS/2 */
  305.  
  306. #ifdef __IBMC__
  307.         _setmode(fileno(stdin),O_BINARY);
  308.         if (!analyse) {
  309.                 _setmode(fileno(stdout),O_BINARY);
  310.         } 
  311. #endif
  312.  
  313.     steg_size = 0;
  314.      
  315.     if ((compressed=(byte *)malloc(IN_SIZE))==NULL) {
  316.         fprintf(stderr,"Not enough memory !\n");
  317.         exit (1);
  318.     }
  319.  
  320.     if (!file_name)
  321.         input_file = stdin;
  322.     else {
  323.         input_file = fopen(file_name,"rb");
  324.         if (!input_file) {
  325.             fprintf(stderr,"Can't open %s\n",file_name);
  326.             exit (1);
  327.         }
  328.     }
  329.  
  330.     fread (header_string,6,1,input_file);
  331.     if (strncmp(header_string,"GIF",3)) {
  332.         fprintf(stderr,"This is not a GIF file !\n");
  333.         exit (1);
  334.     }
  335.  
  336.     (void) get_w(input_file);
  337.     (void) get_w(input_file);
  338.  
  339.     i = getc(input_file);
  340.      
  341.     has_colormap = (i & COLORMAP_BIT);
  342.     bits_per_pixel = (i & 7) + 1;
  343.  
  344.     num_colors = (1 << bits_per_pixel);
  345.     pixel_bit_mask = num_colors - 1;
  346.  
  347.     (void) getc(input_file);
  348.     (void) getc(input_file);
  349.  
  350.     if (has_colormap) {
  351.         int     n = 0;
  352.  
  353.         n = num_colors * 3;
  354.         for (i = 0; i < n; i++)
  355.             (void) getc(input_file);
  356.     }
  357.  
  358.     (void) getc(input_file);
  359.     (void) get_w(input_file);
  360.     (void) get_w(input_file);
  361.     bm_width = get_w(input_file);
  362.     bm_height = get_w(input_file);
  363.  
  364.     if (analyse)
  365.         printf("Image is %d x %d pixels\n", bm_width, bm_height);
  366.  
  367.     if (getc (input_file) & INTERLACE_BIT)
  368.         fprintf(stderr, "Interlaced images not supported - dubious output !\n");
  369.  
  370.     x_coord = 0;    
  371.     y_coord = 0;
  372.     data_bit_offset = 0l;  
  373.  
  374.     lzw_code_size = getc(input_file);
  375.     lzw_clear_code = (1 << lzw_code_size);
  376.     lzw_eof_code = lzw_clear_code + 1;
  377.     lzw_next_free = lzw_first_free = lzw_clear_code+2;
  378.  
  379.     lzw_code_size++;
  380.     lzw_init_size = lzw_code_size;
  381.     lzw_max_code = (1 << lzw_code_size);
  382.     lzw_read_mask = (lzw_max_code - 1);
  383.  
  384.     read_some_data (input_file, compressed, 0l);
  385.  
  386.     buffered_pixels = 0;
  387.  
  388.     do {
  389.         if (!read_a_code(input_file,compressed)) {
  390.             for (i = (buffered_pixels - 1); i >= 0; i--)
  391.                 output_pixel(lzw_pix_buffr[i]);
  392.             goto gif_exit;
  393.         }
  394.  
  395.         if (lzw_code_read != lzw_eof_code) {
  396.             if (lzw_code_read == lzw_clear_code) {
  397.  
  398.                 lzw_code_size = lzw_init_size;
  399.                 lzw_max_code = (1<<lzw_code_size);
  400.                 lzw_next_free = lzw_first_free;
  401.                 lzw_read_mask = ((1 << lzw_code_size) - 1);
  402.  
  403.                 if (!read_a_code(input_file,compressed)) {
  404.                     goto gif_exit;
  405.                 }
  406.                 lzw_current_code = lzw_code_read;       
  407.                 lzw_old_code = lzw_code_read;
  408.                 last_pixel = lzw_code_read & pixel_bit_mask;
  409.                 output_pixel(last_pixel);
  410.             }
  411.             else {
  412.  
  413.                 lzw_current_code = lzw_in_code = lzw_code_read;
  414.  
  415.                 if (lzw_code_read >= lzw_next_free) {
  416.                     lzw_current_code = lzw_old_code;
  417.                     lzw_pix_buffr[buffered_pixels++]=last_pixel;
  418.                     if (buffered_pixels > OUT_SIZE) {
  419.                         fprintf(stderr,"Oops ! pixels > OUT_SIZE!\n");
  420.                         goto gif_exit;
  421.                     }
  422.                 }
  423.  
  424.                 if (lzw_current_code > pixel_bit_mask) {
  425.                     do {
  426.                         lzw_pix_buffr[buffered_pixels++] =
  427.                             code_table[lzw_current_code].code;
  428.                         lzw_current_code = 
  429.                             code_table[lzw_current_code].pred;
  430.                         if (buffered_pixels > OUT_SIZE) {
  431.                             goto gif_exit;
  432.                         }
  433.                     } while (lzw_current_code > pixel_bit_mask);
  434.                 }
  435.  
  436.             last_pixel = (lzw_current_code & pixel_bit_mask);
  437.             lzw_pix_buffr[buffered_pixels] = last_pixel;
  438.  
  439.             for (i = buffered_pixels ; i >= 0 ; i--)
  440.                 output_pixel (lzw_pix_buffr[i]);
  441.  
  442.             buffered_pixels=0;
  443.  
  444.             code_table[lzw_next_free].code = last_pixel;
  445.             code_table[lzw_next_free].pred = lzw_old_code;
  446.             lzw_old_code = lzw_in_code;
  447.  
  448.             if (++lzw_next_free >= lzw_max_code) { 
  449.                 if (lzw_code_size<12) {
  450.                     lzw_code_size++;
  451.                     lzw_max_code <<= 1;
  452.                     lzw_read_mask = ((1 << lzw_code_size) - 1);
  453.                 }
  454.             }
  455.         }
  456.         }
  457.        } while (lzw_code_read != lzw_eof_code);
  458.  
  459. gif_exit:
  460.     fclose(input_file);
  461.     free(compressed);
  462.  
  463.     if (analyse) {
  464.         printf("Analysed file : %ld zero bits, %ld one bits in plane\n",
  465.             zero_bits, one_bits);
  466.     }
  467.  
  468.     exit(0);
  469. }
  470.  
  471.