/*
*                               compact.c
*
* message compaction / encryption
*/
#include "ctdl.h"
/*
*                               history
*
* 89Jun05 HAW  Created.
*/
/*
*                               Contents
*
*       StartEncode()           Start baudot-v encoding.
*       StopEncode()            Stop same.
*       Encode()                Does actual encoding of a byte.
*       Combine()               Work function for encoding.
*       StartDecode()           Start Decoding.
*       StopDecode()            Stop Decoding.
*       Decode()                Actual decoding function.
*       Decode2()               Work function.
*/
/* #define DEBUG */
void StopEncode(void);
static int Combine(int val);
static int Decode2(int val);
#define NO_SET          4       /* no such set */
#define CAPS            0
#define SPEC_CHARS      3
#define COMP_SPACE      26      /* universal */
#define ZERO_COMP       16
#define RET_COMP        17
static struct
  {
  char Set,                /* code set */
  CompValue;     /* position in code set */

  }
compress[] =
  {
    {
    0, 0

    }
  ,
    {
    2, 10

    }
  ,
    {
    2, 11

    }
  ,
    {
    2, 12

    }
  ,
    {
    2, 13

    }
  , /* ' ' - '$' */
    {
    2, 14

    }
  ,
    {
    2, 15

    }
  ,
    {
    2, 16

    }
  ,
    {
    2, 17

    }
  ,
    {
    2, 18

    }
  , /* '%' - ')' */
    {
    2, 19

    }
  ,
    {
    2, 20

    }
  ,
    {
    2, 21

    }
  ,
    {
    2, 22

    }
  ,
    {
    2, 23

    }
  , /* '*' - '.' */
    {
    2, 24

    }
  ,
    {
    2, 0

    }
  ,
    {
    2, 1

    }
  ,
    {
    2, 2

    }
  ,
    {
    2, 3

    }
  ,  /* '/' - '3' */
    {
    2, 4

    }
  ,
    {
    2, 5

    }
  ,
    {
    2, 6

    }
  ,
    {
    2, 7

    }
  ,
    {
    2, 8

    }
  ,  /* '4' - '8' */
    {
    2, 9

    }
  ,
    {
    2, 25

    }
  ,
    {
    3, 0

    }
  ,
    {
    3, 1

    }
  ,
    {
    3, 2

    }
  ,  /* '9' - '=' */
    {
    3, 3

    }
  ,
    {
    3, 4

    }
  ,
    {
    3, 5

    }
  ,
    {
    0, 0

    }
  ,
    {
    0, 1

    }
  ,  /* '>' - 'B' */
    {
    0, 2

    }
  ,
    {
    0, 3

    }
  ,
    {
    0, 4

    }
  ,
    {
    0, 5

    }
  ,
    {
    0, 6

    }
  ,  /* 'C' - 'G' */
    {
    0, 7

    }
  ,
    {
    0, 8

    }
  ,
    {
    0, 9

    }
  ,
    {
    0, 10

    }
  ,
    {
    0, 11

    }
  , /* 'H' - 'L' */
    {
    0, 12

    }
  ,
    {
    0, 13

    }
  ,
    {
    0, 14

    }
  ,
    {
    0, 15

    }
  ,
    {
    0, 16

    }
  , /* 'M' - 'Q' */
    {
    0, 17

    }
  ,
    {
    0, 18

    }
  ,
    {
    0, 19

    }
  ,
    {
    0, 20

    }
  ,
    {
    0, 21

    }
  , /* 'R' - 'V' */
    {
    0, 22

    }
  ,
    {
    0, 23

    }
  ,
    {
    0, 24

    }
  ,
    {
    0, 25

    }
  ,
    {
    3, 6

    }
  ,  /* 'W' - '[' */
    {
    3, 7

    }
  ,
    {
    3, 8

    }
  ,
    {
    3, 9

    }
  ,
    {
    3, 10

    }
  ,
    {
    3, 11

    }
  , /* '\' - '`' */
    {
    1, 0

    }
  ,
    {
    1, 1

    }
  ,
    {
    1, 2

    }
  ,
    {
    1, 3

    }
  ,
    {
    1, 4

    }
  ,  /* 'a' - 'e' */
    {
    1, 5

    }
  ,
    {
    1, 6

    }
  ,
    {
    1, 7

    }
  ,
    {
    1, 8

    }
  ,
    {
    1, 9

    }
  ,  /* 'f' - 'i' */
    {
    1, 10

    }
  ,
    {
    1, 11

    }
  ,
    {
    1, 12

    }
  ,
    {
    1, 13

    }
  ,
    {
    1, 14

    }
  , /* 'j' - 'o' */
    {
    1, 15

    }
  ,
    {
    1, 16

    }
  ,
    {
    1, 17

    }
  ,
    {
    1, 18

    }
  ,
    {
    1, 19

    }
  , /* 'p' - 't' */
    {
    1, 20

    }
  ,
    {
    1, 21

    }
  ,
    {
    1, 22

    }
  ,
    {
    1, 23

    }
  ,
    {
    1, 24

    }
  , /* 'u' - 'y' */
    {
    1, 25

    }
  ,
    {
    3, 12

    }
  ,
    {
    3, 13

    }
  ,
    {
    3, 14

    }
  ,
    {
    3, 15

    }
  /* 'z' - '~' */

  };
static char EncCurSet;
static int  BitsUsed, SendVal, Next, EncodeByteCount;
int (*EncOF)(int c);
int StartEncode(int (*func)(int c))
  {
  BitsUsed = 0;
  EncCurSet   = NO_SET;
  EncOF = func;
  SendVal  = 0;
  EncodeByteCount = 0;
  return 1;

  }
void StopEncode()
  {
  if (EncodeByteCount == 0) return;     /* don't bother */
  Combine(31);
  Combine(0);
  Combine(0);
  Combine(0);

  }
int Encode(int c)
  {
  int toReturn = TRUE;
  EncodeByteCount++;
  switch (c)
    {
    case ' ':   /* space exists in all code sets */
    if (EncCurSet == NO_SET)
      {
      Combine(CAPS + 27);
      EncCurSet = CAPS;

      }
    toReturn = Combine(COMP_SPACE); break;
    case 0:
    case '\r':
    if (EncCurSet != SPEC_CHARS)
      {
      Combine(SPEC_CHARS + 27);
      EncCurSet = SPEC_CHARS;

      }
    toReturn = Combine((c == 0) ? ZERO_COMP : RET_COMP);
    break;
    default:
    /* discard if not printable, C/R, or 0 byte */
    if (c >= ' ' && c < '~')
      {
      if (compress[c - 32].Set != EncCurSet)
        {
        Combine(compress[c - 32].Set + 27);
        EncCurSet = compress[c - 32].Set;

        }
      toReturn = Combine(compress[c - 32].CompValue);

      }

    }
  return toReturn;

  }
static int Combine(int val)
  {
  int           toReturn;
  SendVal |= (val << BitsUsed);
  SendVal &= 0xff;
  Next = (val >> BitsUsed);
  BitsUsed += 5;
  if (BitsUsed >= 8)
    {
    toReturn = (*EncOF)(SendVal);
    SendVal = val >> (13 - BitsUsed);
    BitsUsed %= 8;

    }
  else toReturn = TRUE;
  return toReturn;

  }
void StopDecode(void);
#define NO_CAPS         1
#define NUMERICS        2
#define FINISHED        4       /* finished with encoded data */
#define INIT_SET        5       /* an initial value */
static char Numerics[] =
  {
  '0', '1', '2', '3', '4',
  '5', '6', '7', '8', '9',
  '!', '\"', '#', '$', '%',
  '&', '\'', '(', ')', '*',
  '+', ',', '-', '.', '/',
  ':'

  };
static char SpecChars[] =
  {
  ';', '<' , '=', '>', '?', '@', '[', '\\',
  ']', 0x5e, '_', '`', '{', '|', '}', '~', 0,'\r'

  };
static char DecCurSet;
static int  ThisVal, NB;
int (*DecOF)(int val);
int StartDecode(int (*func)())
  {
  ThisVal = 0;
  DecCurSet  = INIT_SET;
  DecOF   = func;
  NB      = 5;
  return 1;

  }
void StopDecode()
  {

  }
int Decode(int c)
  {
  static int mask[] =
    {
    0, 1, 3, 7, 0xf, 0x1f

    };
  int AB;
  if (DecCurSet == FINISHED) return TRUE;
  if (!Decode2(c & mask[NB])) return FALSE;
  c  >>= NB;
  AB = 8 - NB;
  if (AB >= 5)
    {
    ThisVal = 0;
    AB -= 5;
    NB  = 5;
    if (!Decode2(c & mask[NB])) return FALSE;
    c >>= 5;

    }
  NB = 5 - AB;
  ThisVal = c;
  return TRUE;

  }
static int Decode2(int val)
  {
  int toReturn = FALSE;
  char Used;
  if (DecCurSet == FINISHED) return TRUE;
  ThisVal += (val << (5 - NB));
  switch (ThisVal - 27)
    {
    case CAPS:
    case NO_CAPS:
    case NUMERICS:
    case SPEC_CHARS:
    case FINISHED:
    DecCurSet = ThisVal - 27;
    Used      = TRUE;
    toReturn  = TRUE;
    break;
    default: Used = FALSE;

    }
  /* Discard if no set defined. */
  if (!Used)
    {
    if (DecCurSet == INIT_SET)
       toReturn = TRUE;   /* True for any valid code set */
    else if (ThisVal == COMP_SPACE) toReturn = (*DecOF)(' ');
    else switch (DecCurSet)
      {
      case CAPS:       toReturn = (*DecOF)('A' + ThisVal); break;
      case NO_CAPS:    toReturn = (*DecOF)('a' + ThisVal); break;
      case NUMERICS:   toReturn = (*DecOF)(Numerics[ThisVal]); break;
      case SPEC_CHARS: toReturn = (*DecOF)(SpecChars[ThisVal]); break;
      }
    }
  return toReturn;

  }
