source: trunk/third/transcript/src/asc85ec.c @ 9090

Revision 9090, 8.1 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9089, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2   
3  asc85ec.c
4   
5   This module implements an encoding filter from binary to a
6   base-85 ASCII encoding (4 bytes binary -> 5 bytes ASCII).
7   The ASCII encoding is a variation of that used by Rutter
8   and Orost in their public-domain Unix utilities atob and btoa.
9   This encoding maps 0 to the character '!' (== 0x21), and 84 to the
10   character 'u' (== 0x75).  New line ('\n') characters are
11   inserted so that standard ASCII tools (editors, mailers, etc.)
12   can handle the resulting ASCII.  Whitespace characters,
13   including '\n', will be ignored during decoding.
14
15Original version: Ed McCreight: 1 Aug 1989
16Edit History:
17Ed McCreight: 8 Jan 91
18End Edit History.
19*/
20
21/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
22*
23*  This source code is provided to you by Adobe on a non-exclusive,
24*  royalty-free basis to facilitate your development of PostScript
25*  language programs.  You may incorporate it into your software as is
26*  or modified, provided that you include the following copyright
27*  notice with every copy of your software containing any portion of
28*  this source code.
29*
30* Copyright 1990 Adobe Systems Incorporated.  All Rights Reserved.
31*
32* Adobe does not warrant or guarantee that this source code will
33* perform in any manner.  You alone assume any risks and
34* responsibilities associated with implementing, using or
35* incorporating this source code into your software.
36*
37* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
38 
39#ifndef WITHIN_PS
40#define WITHIN_PS 0
41#endif
42
43#if !WITHIN_PS
44
45#include <stdio.h>
46
47#ifdef DOS_OS2 /* Microsoft C */
48#include <io.h>         /* for setmode */
49#include <fcntl.h>      /* for setmode */
50#endif /* DOS_OS2 */
51
52#include "protos.h"
53
54#define FILTERBUFSIZE           64 /* should be a multiple of 4 */
55#define BaseStm                 FILE *
56#define private                 static
57#define boolean                 int
58#define true                    1
59#define os_fputc(x, y)          fputc(x, y)
60#define base_ferror(stm)        ferror(stm)
61
62typedef int             ps_size_t;
63
64typedef struct _t_PData
65{
66  BaseStm baseStm;
67  int charsSinceNewline;
68} PDataRec, *PData;
69
70typedef struct _t_Stm
71{
72  struct {
73    boolean eof;
74    boolean error;
75  } flags;
76  int cnt;
77  char *ptr, base[FILTERBUFSIZE];
78  PDataRec data;
79} StmRec, *Stm;
80
81#define GetPData(stm)           ((PData)&((stm)->data))
82#define GetBaseStm(pd)          ((pd)->baseStm)
83
84#define os_feof(stm)            ((stm)->flags.eof)
85#define os_ferror(stm)          ((stm)->flags.error)
86
87private int SetEOF ARGDEF1(Stm, stm)
88{
89  stm->flags.eof = true;
90  stm->cnt = 0;
91  return EOF;
92}
93
94private int SetError ARGDEF1(Stm, stm)
95{
96  stm->flags.error = true;
97  stm->cnt = 0;
98  return EOF;
99}
100
101#endif /* WITHIN_PS */
102
103/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
104
105#define NEWLINE_EVERY   64 /* characters */
106
107private int Asc85EFlsBuf ARGDEF2(int, ch, register Stm, stm)
108{
109  int leftOver;
110  register unsigned char *base;
111  register PData pd = GetPData(stm);
112  register BaseStm baseStm = GetBaseStm(pd);
113 
114  if ( base_ferror(baseStm) || os_feof(stm) || os_ferror(stm) )
115    return SetError(stm);
116 
117  for (base = (unsigned char *)stm->base;
118    base < (unsigned char *)stm->ptr - 3; base += 4)
119  {
120    /* convert 4 binary bytes to 5 ASCII output characters */
121    register unsigned long val;
122   
123    if (NEWLINE_EVERY <= pd->charsSinceNewline)
124    {
125      if (putc('\n', baseStm) == EOF)
126        return EOF;
127      pd->charsSinceNewline = 0;
128    }
129   
130    val =
131      (((unsigned long) ((((unsigned int) base[0]) << 8) | base[1])) << 16) |
132      ((((unsigned int) base[2]) << 8) | base[3]);
133      /* The casting in this statement is carefully designed to
134        preserve unsignedness and to postpone widening as
135        long as possible.
136      */
137
138    if (val == 0)
139    {
140      putc('z', baseStm);
141      pd->charsSinceNewline++;
142    }
143    else
144    {
145      /* requires 2 semi-long divides (long by short), 2
146        short divides, 4 short subtracts, 5 short adds,
147        4 short multiplies.  It surely would be nice if C
148        had an operator that gave you quotient and remainder
149        in one machine operation.
150      */
151      unsigned char digit[5]; /* 0..84 */
152      register unsigned long q = val/7225;
153      register unsigned r = (unsigned)val-7225*(unsigned)q;
154      register unsigned t;
155      digit[3] = (t = r/85) + '!';
156      digit[4] = r - 85*t + '!';
157      digit[0] = (t = q/7225) + '!';
158      r = (unsigned)q - 7225*t;
159      digit[1] = (t = r/85) + '!';
160      digit[2] = r - 85*t + '!';
161      fwrite(digit, (ps_size_t)1, (ps_size_t)5, baseStm);
162      pd->charsSinceNewline += 5;
163    }
164  }
165 
166  for (leftOver = 0; base < (unsigned char *)stm->ptr; )
167    stm->base[leftOver++] = *base++;
168   
169  stm->ptr = stm->base+leftOver;
170  stm->cnt = FILTERBUFSIZE-leftOver;
171 
172  stm->cnt--;
173  return (unsigned char)(*stm->ptr++ = (unsigned char)ch);
174}
175
176private int Asc85EPutEOF ARGDEF1(register Stm, stm)
177{
178  BaseStm baseStm = GetBaseStm(GetPData(stm));
179
180  if ( os_feof(stm) )
181    return EOF;
182  Asc85EFlsBuf(0, stm);
183  stm->ptr--;
184
185  if (stm->base < stm->ptr)
186  {
187    /*  There is a remainder of from one to three binary
188    bytes.  The idea is to simulate padding with 0's
189    to 4 bytes, converting to 5 bytes of ASCII, and then
190    sending only those high-order ASCII bytes necessary to
191    express unambiguously the high-order unpadded binary.  Thus
192    one byte of binary turns into two bytes of ASCII, two to three,
193    and three to four.  This representation has the charm that
194    it allows arbitrary-length binary files to be reproduced exactly, and
195    yet the ASCII is a prefix of that produced by the Unix utility
196    "btoa" (which rounds binary files upward to a multiple of four
197    bytes).
198   
199    This code isn't optimized for speed because it is only executed at EOF.
200    */
201    unsigned long val = 0, power = 52200625L /* 85^4 */;
202    unsigned long int i;
203    for (i = 0; i < 4; i++)
204      val = val << 8 |
205        ((stm->base+i < stm->ptr)? (unsigned char)stm->base[i] :
206        0 /* low-order padding */);
207    for (i = 0; i <= (stm->ptr - stm->base); i++)
208    {
209      char q = val/power; /* q <= 84 */
210      os_fputc(q+'!', baseStm);
211      val = (val - q*power);
212      power /= 85;
213    }
214  }
215  os_fputc('~', baseStm); /* EOD marker */
216  os_fputc('>', baseStm);
217  SetEOF(stm);
218  return (base_ferror(baseStm) || os_ferror(stm)) ? SetError(stm) : 0;
219}
220
221private int Asc85EReset ARGDEF1(register Stm, stm)
222{
223  stm->cnt = FILTERBUFSIZE;
224  stm->ptr = stm->base;
225  GetPData(stm)->charsSinceNewline = 0;
226  return 0;
227}
228
229/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
230
231#if !WITHIN_PS
232
233StmRec outStm[1];
234
235int encode ARGDEF2(FILE *, in, FILE *, out)
236{
237  int bytesRead;
238  GetPData(outStm)->baseStm = out;
239  Asc85EReset(outStm);
240  while (!feof(in))
241  {
242    int ch;
243    while (!feof(in) & (0 < outStm->cnt))
244    {
245      int bytesRead =
246        fread(outStm->ptr, (ps_size_t)1, (ps_size_t)outStm->cnt, in);
247      outStm->ptr += bytesRead;
248      outStm->cnt -= bytesRead;
249    }
250    ch = getc(in);
251    if (ch != EOF)
252    {
253      if (Asc85EFlsBuf(ch, outStm) == EOF)
254        return(-1);
255    }
256  }
257  if (Asc85EPutEOF(outStm) == EOF)
258    return(-1);
259  return (0);
260}
261
262void main ARGDEF0()
263{
264  FILE *in, *out;
265  int prompt = 0;
266 
267#ifdef SMART_C
268  /* Lightspeed C for Macintosh, where there's no obvious way to
269  force stdin to binary mode.
270  */
271  prompt = 1;
272#endif /* SMART_C */
273
274#ifdef PROMPT
275  prompt = PROMPT;
276#endif /* PROMPT */
277
278  if (prompt)
279  {
280    char inName[100], outName[100];
281    fprintf(stdout, "Input binary file: ");
282    fscanf(stdin, "%s", inName);
283    in = fopen(inName, "rb");
284    if (in == NULL)
285    {
286      fprintf(stderr, "Couldn't open binary input file \"%s\"\n", inName);
287      exit(1);
288    }
289    fprintf(stdout, "Output text file: ");
290    fscanf(stdin, "%s", outName);
291    out = fopen(outName, "w");
292    if (out == NULL)
293    {
294      fprintf(stderr, "Couldn't open ASCII output file \"%s\"\n", outName);
295      exit(1);
296    }
297  }
298  else
299  {
300 
301#ifdef DOS_OS2 /* Microsoft C */
302    setmode(fileno(stdin), O_BINARY);
303    setmode(fileno(stdout), O_TEXT);
304#endif /* ndef DOS_OS2 */
305
306    in = stdin;
307    out = stdout;
308  }
309 
310  if (encode(in, out))
311  {
312    fclose(out);
313    fprintf(stderr, "\nASCII85Encode failed.\n");
314    exit(1);
315  }
316 
317  fclose(in);
318  fclose(out);
319  exit(0);
320}
321
322#endif /* WITHIN_PS */
323
Note: See TracBrowser for help on using the repository browser.