process_pfb(FILE *ifp, const char *ifp_filename, struct font_reader *fr)
{
  int blocktyp = 0;
  unsigned block_len = 0;
  int c = 0;
  unsigned filepos = 0;
  int linepos = 0;
  char line[LINESIZE];

  while (1) {
    while (block_len == 0) {
      c = getc(ifp);
      blocktyp = getc(ifp);
      if (c != PFB_MARKER
	  || (blocktyp != PFB_ASCII && blocktyp != PFB_BINARY
	      && blocktyp != PFB_DONE)) {
	if (c == EOF || blocktyp == EOF)
	  error("%s corrupted: no end-of-file marker", ifp_filename);
	else
	  error("%s corrupted: bad block marker at position %u",
		ifp_filename, filepos);
	blocktyp = PFB_DONE;
      }
      if (blocktyp == PFB_DONE)
	goto done;

      block_len = getc(ifp) & 0xFF;
      block_len |= (getc(ifp) & 0xFF) << 8;
      block_len |= (getc(ifp) & 0xFF) << 16;
      block_len |= (unsigned) (getc(ifp) & 0xFF) << 24;
      if (feof(ifp)) {
	error("%s corrupted: bad block length at position %u",
	      ifp_filename, filepos);
	blocktyp = PFB_DONE;
	goto done;
      }
      filepos += 6;
    }

    /* read the block in its entirety, in LINESIZE chunks */
    while (block_len > 0) {
      unsigned rest = LINESIZE - 1 - linepos; /* leave space for '\0' */
      unsigned n = (block_len > rest ? rest : block_len);
      int actual = fread(line + linepos, 1, n, ifp);
      if (actual != (int) n) {
	error("%s corrupted: block short by %u bytes at position %u",
	      ifp_filename, block_len - actual, filepos);
	block_len = actual;
      }

      if (blocktyp == PFB_BINARY)
	fr->output_binary((unsigned char *)line, actual);
      else
	linepos = handle_pfb_ascii(fr, line, linepos + actual);

      block_len -= actual;
      filepos += actual;
    }

    /* handle any leftover line */
    if (linepos > 0) {
      line[linepos] = 0;
      fr->output_ascii(line, linepos);
      linepos = 0;
    }
  }

 done:
  c = getc(ifp);
  if (c != EOF)
    error("%s corrupted: data after PFB end marker at position %u",
	  ifp_filename, filepos - 2);
  fr->output_end();
}
process_pfb(FILE *ifp, const char *ifp_filename, struct font_reader *fr)
{
  int blocktyp = 0;
  unsigned block_len = 0;
  int c = 0;
  unsigned filepos = 0;
  int linepos = 0;
  char line[LINESIZE];

  while (1) {
    while (block_len == 0) {
      c = getc(ifp);
      blocktyp = getc(ifp);
      if (c != PFB_MARKER
	  || (blocktyp != PFB_ASCII && blocktyp != PFB_BINARY
	      && blocktyp != PFB_DONE)) {
	if (c == EOF || blocktyp == EOF)
	  error("%s corrupted: no end-of-file marker", ifp_filename);
	else
	  error("%s corrupted: bad block marker at position %u",
		ifp_filename, filepos);
	blocktyp = PFB_DONE;
      }
      if (blocktyp == PFB_DONE)
	goto done;

      block_len = getc(ifp) & 0xFF;
      block_len |= (getc(ifp) & 0xFF) << 8;
      block_len |= (getc(ifp) & 0xFF) << 16;
      block_len |= (unsigned) (getc(ifp) & 0xFF) << 24;
      if (feof(ifp)) {
	error("%s corrupted: bad block length at position %u",
	      ifp_filename, filepos);
	blocktyp = PFB_DONE;
	goto done;
      }
      filepos += 6;
    }

     
    while (block_len > 0) {
      unsigned rest = LINESIZE - 1 - linepos;  
      unsigned n = (block_len > rest ? rest : block_len);
      int actual = fread(line + linepos, 1, n, ifp);
      if (actual != (int) n) {
	error("%s corrupted: block short by %u bytes at position %u",
	      ifp_filename, block_len - actual, filepos);
	block_len = actual;
      }

      if (blocktyp == PFB_BINARY)
	fr->output_binary((unsigned char *)line, actual);
      else
	linepos = handle_pfb_ascii(fr, line, linepos + actual);

      block_len -= actual;
      filepos += actual;
    }

     
    if (linepos > 0) {
      line[linepos] = 0;
      fr->output_ascii(line, linepos);
      linepos = 0;
    }
  }

 done:
  c = getc(ifp);
  if (c != EOF)
    error("%s corrupted: data after PFB end marker at position %u",
	  ifp_filename, filepos - 2);
  fr->output_end();
}