Logo Search packages:      
Sourcecode: ksh version File versions  Download package

code-uu.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 2003-2007 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Phong Vo <kpv@research.att.com>                    *
*                                                                      *
***********************************************************************/
#pragma prototyped

/*
 * quoted printable coder
 */

#include <codex.h>
#include <ctype.h>

#define UUIN            3
#define UUOUT           4
#define UUCHUNK         15

#define UU_END          (UCHAR_MAX)
#define UU_IGN          (UCHAR_MAX-1)
#define UU_PAD          (UCHAR_MAX-2)

typedef struct
{
      int         pad;
      int         fill;
      int         length;
      const char  map[65];
} Data_t;

typedef struct State_s
{
      Codex_t*    codex;

      const Data_t*     data;

      unsigned char*    bb;
      unsigned char*    bp;
      unsigned char*    bl;
      unsigned char*    be;
      unsigned char*    map;
      unsigned char*    pb;
      unsigned char*    pp;

      int         c1;
      int         c2;
      int         nl;
      int         text;

      unsigned char     mapbuf[UCHAR_MAX + 2];
      unsigned char     buf[SF_BUFSIZE];
      unsigned char     peek[UUIN];
} State_t;

static const Data_t     uu_base64 =
{
      '=',
      0,
      0,
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
};

static const Data_t     uu_bsd =
{
      0,
      0156,
      1,
      "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
};

static const Data_t     uu_posix =
{
      0,
      0,
      1,
      " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
};

#define GETCHAR(p)            ((p)->bp < (p)->be ? (int)*(p)->bp++ : fill(p))
#define PUTCHAR(p,s,e,c)      ((s<e) ? (*s++=(c)) : (*p->pp++=(c)))

static int
fill(State_t* state)
{
      ssize_t     r;

      state->bp = state->buf;
      if ((r = sfrd(state->codex->sp, state->bp, sizeof(state->buf), &state->codex->sfdisc)) <= 0)
      {
            state->be = state->bp;
            return EOF;
      }
      state->be = state->bp + r;
      return *state->bp++;
}

static int
flush(register State_t* state)
{
      uint32_t    b;
      int         c3;
      int         x;

      x = 1;
      if (state->c1 >= 0)
      {
            c3 = state->data->fill;
            x++;
            if (state->c2 < 0)
            {
                  state->c2 = c3;
                  x++;
            }
            b = (state->c1 << 16) | (state->c2 << 8) | c3;
            *state->bp++ = state->data->map[b >> 18];
            *state->bp++ = state->data->map[(b >> 12) & 077];
            *state->bp++ = x == 3 && state->data->pad ? state->data->pad : state->data->map[(b >> 6) & 077];
            *state->bp++ = state->data->pad ? state->data->pad : state->data->map[b & 077];
            state->c1 = state->c2 = -1;
      }
      if ((state->bl - state->bp) < UUOUT * UUCHUNK || state->bp > state->buf + !!state->bb)
      {
            if (state->bb)
                  *state->bb = state->data->map[((state->bp - state->bb - x) / UUOUT) * UUIN + 1];
            if (*(state->bp - 1) != '\n')
                  *state->bp++ = '\n';
            x = state->bp - state->buf;
            state->bp = state->buf;
            state->bl = state->bp + UUOUT * UUCHUNK;
            if (sfwr(state->codex->sp, state->buf, x, &state->codex->sfdisc) != x)
                  return EOF;
      }
      return 0;
}

static int
uu_open(Codex_t* p, char* const args[], Codexnum_t flags)
{
      register State_t* state;
      register char*          s;
      register char**         a;
      unsigned char*          m;
      unsigned char*          q;
      const Data_t*           data;
      int               c;
      int               n;
      int               text;

      data = &uu_posix;
      text = 0;
      a = (char**)args + 1;
      while (s = *++a)
            if (streq(s, "base64") || streq(s, "mime"))
                  data = &uu_base64;
            else if (streq(s, "bsd") || streq(s, "ucb"))
                  data = &uu_bsd;
            else if (streq(s, "posix"))
                  data = &uu_posix;
            else if (streq(s, "text"))
                  text = 1;
            else
            {
                  if (p->disc->errorf)
                        (*p->disc->errorf)(NiL, p->disc, 2, "%s: %s: unknown option", p->meth->name, s);
                  return -1;
            }
      if (!(state = newof(0, State_t, 1, 0)))
      {
            if (p->disc->errorf)
                  (*p->disc->errorf)(NiL, p->disc, 2, "out of space");
            return -1;
      }
      state->data = data;
      state->text = text;
      if (p->flags & CODEX_DECODE)
      {
            n = data->length ? 0 : UU_IGN;
            q = state->mapbuf;
            memset(q, n, sizeof(state->mapbuf));
            state->map = ++q;
            q[EOF] = UU_END;
            if (n)
                  q[data->pad] = UU_PAD;
            for (m = (unsigned char*)data->map; c = *m; m++)
                  q[c] =  m - (unsigned char*)data->map;
      }
      p->data = state;
      state->codex = p;
      return 0;
}

static int
uu_init(Codex_t* p)
{
      register State_t* state = (State_t*)p->data;
      int               n;

      state->bp = state->buf;
      if (p->flags & CODEX_ENCODE)
      {
            n = UUOUT * UUCHUNK + state->data->length + 1;
            state->be = state->bp + (sizeof(state->buf) / n) * n;
            if (state->data->length)
            {
                  state->bb = state->bp;
                  *state->bp++ = state->data->map[UUIN * UUCHUNK];
            }
            state->bl = state->bp + UUOUT * UUCHUNK;
            state->c1 = state->c2 = -1;
      }
      else
      {
            state->be = state->bp;
            state->pb = state->pp = state->peek;
            if (state->data->length)
                  state->nl = -1;
            state->c1 = state->c2 = -1;
      }
      return 0;
}

static ssize_t
uu_read(Sfio_t* sp, void* buf, size_t n, Sfdisc_t* disc)
{
      register State_t* state = (State_t*)CODEX(disc)->data;
      register char*          s = (char*)buf;
      register char*          e = s + n;
      register uint32_t b;
      register int            c;
      register int            x;

      if (state->pb < state->pp)
      {
            while (s < e && state->pb < state->pp)
                  *s++ = *state->pb++;
            if (state->pb == state->pp)
                  state->pb = state->pp = state->peek;
      }
      if (state->data->length)
            while (s < e)
            {
                  switch (c = GETCHAR(state))
                  {
                  case EOF:
                        goto done;
                  case '\n':
                        state->nl = -1;
                        continue;
                  }
                  if (state->nl < 0)
                        state->nl = state->map[c];
                  else if (state->nl > 0)
                  {
                        b = state->map[c];
                        if ((c = GETCHAR(state)) == EOF)
                              c = 0;
                        else
                              c = state->map[c];
                        b = (b << 6) | c;
                        if ((c = GETCHAR(state)) == EOF)
                              c = 0;
                        else
                              c = state->map[c];
                        b = (b << 6) | c;
                        if ((c = GETCHAR(state)) == EOF)
                              c = 0;
                        else
                              c = state->map[c];
                        b = (b << 6) | c;
                        if (state->text)
                        {
                              if ((c = (b >> 16) & 0xFF) != '\r')
                                    PUTCHAR(state, s, e, c);
                              if ((c = (b >> 8) & 0xFF) != '\r')
                                    PUTCHAR(state, s, e, c);
                              if ((c = b & 0xFF) != '\r')
                                    PUTCHAR(state, s, e, c);
                        }
                        else
                        {
                              PUTCHAR(state, s, e, (b >> 16));
                              PUTCHAR(state, s, e, (b >> 8));
                              PUTCHAR(state, s, e, b);
                        }
                        if ((state->nl -= 3) < 0)
                              while (state->nl++ < 0)
                                    s--;
                  }
            }
      else
            while (s < e)
            {
                  while ((c = state->map[GETCHAR(state)]) >= 64)
                        if (c != UU_IGN)
                              goto done;
                  b = c;
                  while ((c = state->map[GETCHAR(state)]) >= 64)
                        if (c != UU_IGN)
                        {
                              if (state->codex->disc->errorf)
                                    (*state->codex->disc->errorf)(NiL, state->codex->disc, 1, "%c: extra input character ignored", c);
                              goto done;
                        }
                  b = (b << 6) | c;
                  while ((c = state->map[GETCHAR(state)]) >= 64)
                        if (c != UU_IGN)
                        {
                              if (state->text)
                              {
                                    if ((x = (b >> 4) & 0xFF) != '\r')
                                          PUTCHAR(state, s, e, x);
                              }
                              else
                                    PUTCHAR(state, s, e, (b >> 4));
                              goto done;
                        }
                  b = (b << 6) | c;
                  while ((c = state->map[GETCHAR(state)]) >= 64)
                        if (c != UU_IGN)
                        {
                              if (state->text)
                              {
                                    if ((x = (b >> 10) & 0xFF) != '\r')
                                          PUTCHAR(state, s, e, x);
                                    if ((x = (b >> 2) & 0xFF) != '\r')
                                          PUTCHAR(state, s, e, x);
                              }
                              else
                              {
                                    PUTCHAR(state, s, e, (b >> 10));
                                    PUTCHAR(state, s, e, (b >> 2));
                              }
                              goto done;
                        }
                  b = (b << 6) | c;
                  if (state->text)
                  {
                        if ((x = (b >> 16) & 0xFF) != '\r')
                              PUTCHAR(state, s, e, x);
                        if ((x = (b >> 8) & 0xFF) != '\r')
                              PUTCHAR(state, s, e, x);
                        if ((x = b & 0xFF) != '\r')
                              PUTCHAR(state, s, e, x);
                  }
                  else
                  {
                        PUTCHAR(state, s, e, (b >> 16));
                        PUTCHAR(state, s, e, (b >> 8));
                        PUTCHAR(state, s, e, b);
                  }
            }
 done:
      return s - (char*)buf;
}

static ssize_t
uu_write(Sfio_t* sp, const void* buf, size_t n, Sfdisc_t* disc)
{
      register State_t* state = (State_t*)CODEX(disc)->data;
      register unsigned char* s;
      register unsigned char* e;
      register uint32_t b;
      register int            c1;
      register int            c2;
      register int            c3;

      s = (unsigned char*)buf;
      e = s + n;
      if ((c1 = state->c1) >= 0)
      {
            state->c1 = -1;
            if ((c2 = state->c2) >= 0)
            {
                  state->c2 = -1;
                  goto get_3;
            }
            goto get_2;
      }
      while (s < e)
      {
            do
            {
                  if (state->nl)
                  {
                        state->nl = 0;
                        c1 = '\n';
                        goto get_2;
                  }
                  if (s >= e)
                        break;
                  c1 = *s++;
                  if (state->text && c1 == '\n')
                  {
                        c1 = '\r';
                        c2 = '\n';
                        goto get_3;
                  }
 get_2:
                  if (s >= e)
                  {
                        state->c1 = c1;
                        return n;
                  }
                  c2 = *s++;
                  if (state->text && c2 == '\n')
                  {
                        c2 = '\r';
                        c3 = '\n';
                        goto put_123;
                  }
 get_3:
                  if (s >= e)
                  {
                        state->c1 = c1;
                        state->c2 = c2;
                        return n;
                  }
                  c3 = *s++;
                  if (state->text && c3 == '\n')
                  {
                        state->nl = 1;
                        c3 = '\r';
                  }
 put_123:
                  b = (c1 << 16) | (c2 << 8) | c3;
                  *state->bp++ = state->data->map[b >> 18];
                  *state->bp++ = state->data->map[(b >> 12) & 077];
                  *state->bp++ = state->data->map[(b >> 6) & 077];
                  *state->bp++ = state->data->map[b & 077];
            } while (state->bp < state->bl);
            *state->bp++ = '\n';
            if (state->bp >= state->be)
            {
                  if (sfwr(sp, state->buf, state->bp - state->buf, disc) != (state->bp - state->buf))
                        return -1;
                  state->bp = state->buf;
            }
            if (state->bb)
            {
                  state->bb = state->bp;
                  *state->bp++ = state->data->map[UUIN * UUCHUNK];
            }
            state->bl = state->bp + UUOUT * UUCHUNK;
      }
      return n;
}

static int
uu_sync(Codex_t* p)
{
      return (p->flags & CODEX_ENCODE) ? flush((State_t*)p->data) : 0;
}

Codexmeth_t codex_uu =
{
      "uu",
      "uuencode printable encoding.",
      "[+posix?Posix \buuencode\b(1). This is the default.]"
      "[+base64|mime?MIME base64 encoding.]"
      "[+bsd|ucb?BSD \buuencode\b(1).]"
      "[+text?Encode \\n => \\r\\n, decode \\r\\n => \\n.]"
      "[+(version)?codex-uu (AT&T Research) 1998-11-11]"
      "[+(author)?Glenn Fowler <gsf@research.att.com>]",
      CODEX_DECODE|CODEX_ENCODE|CODEX_UU,
      0,
      0,
      uu_open,
      0,
      uu_init,
      0,
      uu_read,
      uu_write,
      uu_sync,
      0,
      0,
      0,
      0,
      CODEXNEXT(codex_uu_next)
};

CODEXLIB(&codex_uu)

Generated by  Doxygen 1.6.0   Back to index