#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

/* define DEBUG to get debugging output to stderr
 * 0: no debug output
 * 1: summary line (default)
 * 2: 1 + skipped markers
 * 3: 2 + all markers
 */

#ifndef DEBUG
#define DEBUG 1
#endif

int main(int argc, char **argv) {
  int i, c, keep, scan, marker, bytes, skipped;
  unsigned short len;

  /* read JPEG SOI */
  c = getchar();
  assert(c == 0xff);
  putchar(c);
  c = getchar();
  assert(c == 0xd8);
  putchar(c);
  bytes = 2;
  skipped = 0;
  /* do we have to scan for the next marker? (see page 37) */
  scan = 0;
  /* iterate over all blocks, see:
     http://www.w3.org/Graphics/JPEG/itu-t81.pdf
     pages 31 and 32 */
  while(!feof(stdin)) {
    /* do we keep this marker or toss it out? */
    keep = 0;
    /* if we were scanning, the marker has already been consumed */
    if(!scan) {
      /* markers can be preceded by any number of FF padding bytes, but don't
      *have* to */
      while((c = getchar()) == 0xff) skipped += 1;
      skipped -= 1;
#if DEBUG > 2
      fprintf(stderr, "marker 0xff%02x\n", c);
#endif
    } else {
      scan = 0;
    }
    marker = c;
    switch(c) {
      /* EOI does not have a length */
    case 0xD9:
      {
	fputs("\xFF\xD9", stdout);
	bytes += 2;
#if DEBUG
	fprintf(stderr,
		"in=%d bytes, skipped=%d bytes, out=%d bytes, saved %4.2f%%\n",
		bytes+skipped, skipped, bytes, 100.0*skipped/(bytes+skipped));
#endif
	return 0;
      }

      /* these non-segment markers have no length and should be skipped */
    case 0xD0:
    case 0xD1:
    case 0xD2:
    case 0xD3:
    case 0xD4:
    case 0xD5:
    case 0xD6:
    case 0xD7:
      {
	skipped += 2;
#if DEBUG > 1
	fprintf(stderr, "skipped marker 0xff%02x (2 bytes)\n", marker);
#endif
	break;
      }

      /* SOS means we have to scan */
    case 0xDA:
      scan = 1;
      /* FALLTHROUGH */
      
      /* these segment markers will be let through */
    case 0xC0:
    case 0xC1:
    case 0xC2:
    case 0xC3:
    case 0xC4:
    case 0xC5:
    case 0xC6:
    case 0xC7:
    case 0xC8:
    case 0xC9:
    case 0xCA:
    case 0xCB:
    case 0xCC:
    case 0xCD:
    case 0xCE:
    case 0xCF:
      /* we skip restart markers 0xFFD0-7 */
    case 0xDB:
    case 0xDC:
      /* we skip restart interval 0xFFDD */
    case 0xDE:
    case 0xDF:
      /* this one is defined by JFIF */
    case 0xe0:
      keep = 1;
      /* FALLTHROUGH */

    /* these markers do not have a length associated with them */
    case 0x01:
      {
	putchar('\xff');
	putchar(c);
	bytes += 2;
	/* non-segment markers need not continue */
	if (!keep) break;
	/* segment markers fallthrough */
      }
      
    default:
      {
	c = getchar();
	assert(c != -1);
	if(keep) putchar(c);
	len = c << 8;
	c = getchar();
	assert(c != -1);
	if(keep) putchar(c);
	len += c - 2; /* the marker length includes the 2 bytes
			 for the length itself */
	if(keep) {
	  bytes += 2;
	} else {
	  skipped += 4;
	}
	for(i=0; i<len; i++) {
	  c = getchar();
	  assert(c != -1);
	  if(keep) {
	    putchar(c);
	    bytes += 1;
	  } else {
	    skipped += 1;
	  }
	}
#if DEBUG > 1
	if(!keep) {
	  fprintf(stderr, "skipped marker 0xff%02x (%d bytes)\n",
		  marker, len + 2);
	}
#endif
	if(scan) {
	  while(!feof(stdin)) {
	    c = getchar();
	    assert(c != -1);
	    if(c != 0xff) {
	      putchar(c);
	      bytes += 1;
	    } else {
	      c = getchar();
	      assert(c != -1);
	      if(c == 0) {
		/* "stuffed 0xFF00 is a way of escaping 0xFFs that occur
		   naturally in the Huffman or arithmetic-coded data */
		putchar('\xff');
		putchar('\x00');
		bytes += 2;
	      } else if (c >= 0xd0 && c <= 0xd7) {
		/* 0xFFD0-0xFFD7 are restart markers that can occur within
		   an entropy-coded block - we skip them */
		skipped += 2;
#if DEBUG > 1
		fprintf(stderr, "skipped restart marker 0xff%02x (2 bytes)\n",
			c);
#endif
	      } else break; /* we have found the next marker */
	    }
	  }
	}
      }
    }
  }
  return 1;
}
