Path: funic!news.funet.fi!sunic!uupsi!rpi!zaphod.mps.ohio-state.edu!wuarchive!uunet!jarthur!nntp-server.caltech.edu!pooh!madler
From: madler@pooh.caltech.edu (Mark Adler)
Newsgroups: comp.sys.handhelds
Subject: Re: Why ASC over UUENCODE?
Message-ID: <1991Feb14.202321.23152@nntp-server.caltech.edu>
Date: 14 Feb 91 20:23:21 GMT
References: <5936D424400019B9@gacvx2.gac.edu> <1991Feb14.194901.4798@portia.Stanford.EDU>
Sender: news@nntp-server.caltech.edu
Organization: California Institute of Technology, Pasadena
Lines: 334
Nntp-Posting-Host: pooh


>> How about a portable version of ASC-> and ->ASC in C

I portabilized Pete Wilson's program that was recently posted and I am
posting it at the end of this message.

>> AND which is distributed in EXECUTABLE form

I leave it to others to compile it for PC's or whatnot and put it on some
ftp site.

>> on the HP software disks included with the cables?

Well, I would prefer a uu-like thing instead.  But until then, this program
should be useful.

>> That way, all that whining about UUENCODE would be bunk

Not in my opinion, but I won't rehash what I've posted already.

Mark Adler
madler@pooh.caltech.edu

--- asc2bin.c ---
/* 
    This programs reads an up to 127K ASCII (RPL) file consisting of a
    string intended for ASC-> and converts it into a binary object file.
 
    This program was compiled with Microsoft C 5.1 and Turbo C. ANSI C
    conventions are mostly followed.

    The original algorithm for CRC computation was extracted from
    Li Sheng's posting to comp.sys.handhelds.
 
    01/19/91 PMW  created
    02/14/91 MAdler	modified for portability
*/

#include <stdio.h>
#include <errno.h>


#ifdef __STDC__
#  define MODERN
#endif

#ifdef __TURBOC__
#  ifndef MODERN
#    define MODERN
#  endif
#endif

#ifdef MODERN
#  include <stdlib.h>
#  include <string.h>
#  include <ctype.h>
#  define FOPR "rb"
#  define FOPW "wb"
#else
#  define void int
#  define size_t unsigned int
   extern char *strcat();
   extern char *strcpy();
#  define FOPR "r"
#  define FOPW "w"
#endif


typedef unsigned char BYTE;
typedef unsigned int WORD;


/* Function prototypes for ANSI C */
#ifdef MODERN
  int FileExists(char *);
  long FileSize(FILE *);
  WORD crcBlock(BYTE *, size_t);
  void CopyLine(BYTE **, char **, WORD *);
  void ReadFile(char *, BYTE **, WORD *);
  void WriteFile(char *, BYTE *, WORD );
  int main(int,  char **);
#endif


#define MAX_READ_SIZE 127

#ifndef FILENAME_MAX
#  define FILENAME_MAX 65
#endif

#ifndef EXIT_FAILURE
#  define EXIT_FAILURE 1
#endif

#ifndef EXIT_SUCCESS
#  define EXIT_SUCCESS 0
#endif

#ifndef SEEK_SET
#  define SEEK_SET 0
#endif

#ifndef SEEK_END
#  define SEEK_END 2
#endif

#ifndef isxdigit
#  define isxdigit(c) (c >= '0' && c <= '9' || c >= 'A' && c <= 'F')
#endif
#define HEX2INT(hc) ((unsigned int) (isdigit(hc) ? (hc)-'0' : (hc)-'A'+10))

int FileExists(f)
char *f;
{
    FILE *tf;

    if ((tf = fopen(f, FOPR)) != NULL) {
        fclose(tf);
        return 1;
    }
    else
        return 0;
}

long FileSize(f)
FILE *f;
{
    long origPos = ftell(f), fileSize = 0;

    fseek(f, 0L, SEEK_END);
    fileSize = ftell(f);
    fseek(f, origPos, SEEK_SET);

    return fileSize;
}


#define CALC_CRC(c, i) (((((c)^(i)) & 0xF) * 0x1081) ^ ((c) >> 4))
WORD crcBlock(mb, len)
BYTE *mb;
size_t len;
{
    WORD crc = 0, bObjSize = len/2;

    while (bObjSize--) {
        crc = CALC_CRC(crc, (WORD) (*mb) & 0xF);
        crc = CALC_CRC(crc, (WORD) ((*mb) >> 4));
        ++mb;
    }
    if (len & 1)
        crc = CALC_CRC(crc, (WORD) (*mb) & 0xF);

    return crc;
}


void CopyLine(mb, s, objSize)
BYTE **mb;
char **s;
WORD *objSize;
{
    char *ts = *s;
    BYTE *tmb = *mb;
    WORD ls = 0;

    while (isxdigit(ts[0]) && isxdigit(ts[1])) {
        *tmb++ = (BYTE) (HEX2INT(ts[0]) + (HEX2INT(ts[1]) << 4));
        ls += 2;
        ts += 2;
    }

    if (isxdigit(ts[0]) && ts[1] == '"') {
        /* we ended on a nibble boundary!! */
        BYTE crc1, crc2;
 
        /* correct crc by nibble shifting end */
        crc2 = (BYTE) ((tmb[-1] >> 4) + (HEX2INT(ts[0]) << 4));
        crc1 = (BYTE) ((tmb[-2] >> 4) + ((tmb[-1] & 0xF) << 4));
 
        /* fix memory buffer */
        tmb[-2] &= 0xf;
        tmb[-1] = crc1;
        *tmb++ = crc2;
        ++ls;
        ++ts;
    }

    *s = ts;
    *mb = tmb;
    *objSize += ls;
}


#define READLN(s, f) fgets((s), sizeof(s), (f))

void ReadFile(filepath, mb, objSize)
char *filepath;
BYTE **mb;
WORD *objSize;
{
    FILE *infile;
    char lineBuf[250], *p;
    WORD bufSize;
    long fileSize;
    BYTE *wmb;

    if (!strchr(filepath, '.'))
        strcat(filepath, ".rpl");

    if (!(infile = fopen(filepath, "r"))) {
        fprintf(stderr, "asc2bin:  can't open %s\n", filepath);
        exit(EXIT_FAILURE);
    }

    fileSize = FileSize(infile);
    if (fileSize > MAX_READ_SIZE*1024L) {
        fprintf(stderr, "asc2bin: File %s is too long\n", filepath);
        exit(EXIT_FAILURE);
    }
    bufSize = 4+(WORD) (fileSize / 2);  /* approximate byte size of object */
    if (!(*mb = (BYTE *) malloc(bufSize))) {
        fprintf(stderr, "asc2bin:  Unable to allocate %u bytes\n", bufSize);
        exit(EXIT_FAILURE);
    }
    wmb = *mb;

    /* find string */
    while (!feof(infile)) {
        if (!READLN(lineBuf, infile)) {
            if (feof(infile))
                fputs("asc2bin:  Unable to locate string\n", stderr);
            else
		perror("asc2bin:  Read error");

            fclose(infile);
            exit(EXIT_FAILURE);
        }

        if (*lineBuf == '"')
            break;
    }

    *objSize = 0;

    /* put string into buffer */
    p = &lineBuf[1];  /* skip opening quote */
    CopyLine(&wmb, &p, objSize);

    /* copy remainder into buffer */
    while (*p != '"' && !feof(infile)) {
        if (!READLN(lineBuf, infile)) {
            if (feof(infile))
                fputs("asc2bin:  Unable to locate closing quote\n", stderr);
            else
                perror("asc2bin:  Read error");

            fclose(infile);
            exit(EXIT_FAILURE);
        }

        p = lineBuf;
        CopyLine(&wmb, &p, objSize);
    }

    fclose(infile);
}

void WriteFile(filepath, mb, objSize)
char *filepath;
BYTE *mb;
WORD objSize;
{
    FILE *outfile;
    char *extpos = strchr(filepath, '.');

    strcpy(extpos+1, "bin");

    if (FileExists(filepath)) {
        fprintf(stderr, "asc2bin:  file already exists: %s\n", filepath);
        exit(EXIT_FAILURE);
    }

    if (!(outfile = fopen(filepath, FOPW))) {
        fprintf(stderr, "asc2bin:  unable to create %s\n", filepath);
        exit(EXIT_FAILURE);
    }

    fputs("HPHP48-C", outfile);  /* my own version */
    while (objSize--)
        fputc(*mb++, outfile);

    fclose(outfile);
}


int main(argc, argv)
int argc;
char **argv;
{
    char filepath[FILENAME_MAX];
    BYTE *mb;
    WORD objSize, rcrc, crc,bObjSize;  /*  NOTE: objSize is in nibbles! */

    if (argc < 2) {
        fputs("usage:  asc2bin infile[.ext]\n", stderr);
        fputs("\treads infile.ext and creates infile.bin\n", stderr);
        fputs("\tif omitted, .ext is assumed to be .rpl\n", stderr);
        exit(EXIT_FAILURE);
    }

    strcpy(filepath, argv[1]);

    ReadFile(filepath, &mb, &objSize);
    if (objSize < 2) {
        fputs("asc2bin: String too short to include crc\n", stderr);
        exit(EXIT_FAILURE);
    }

    objSize -= 4;  /* nibbles */
    bObjSize = objSize / 2 + (objSize & 1);
    rcrc = (WORD) mb[bObjSize] + ((WORD) mb[bObjSize+1] << 8);

    crc = crcBlock(mb, objSize);
    if (crc != rcrc) {
        fprintf(stderr,
	"asc2bin: Calculated CRC # %Xh does not match read CRC # %Xh\n",
            crc, rcrc);
        exit(EXIT_FAILURE);
    }

    WriteFile(filepath, mb, bObjSize);

    return EXIT_SUCCESS;
}
