2008-01-28 21:37:16 +00:00
|
|
|
/* source: xio-ascii.c */
|
2014-03-22 19:07:20 +00:00
|
|
|
/* Copyright Gerhard Rieger */
|
2008-01-27 12:00:08 +00:00
|
|
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
|
|
|
|
|
|
|
/* this file contains functions for text encoding, decoding, and conversions */
|
|
|
|
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "xio-ascii.h"
|
|
|
|
|
|
|
|
/* for each 6 bit pattern we have an ASCII character in the arry */
|
|
|
|
const static int base64chars[] = {
|
|
|
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
|
|
|
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
|
|
|
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
|
|
|
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
|
|
|
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
|
|
|
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
|
|
|
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
|
|
|
'4', '5', '6', '7', '8', '9', '+', '/',
|
|
|
|
} ;
|
|
|
|
|
|
|
|
#define CHAR64(c) (base64chars[c])
|
|
|
|
|
|
|
|
char *
|
|
|
|
xiob64encodeline(const char *data, /* input data */
|
|
|
|
size_t bytes, /* length of input data, >=0 */
|
|
|
|
char *coded /* output buffer, must be long enough */
|
|
|
|
) {
|
|
|
|
int c1, c2, c3;
|
|
|
|
|
|
|
|
while (bytes > 0) {
|
|
|
|
c1 = *data++;
|
|
|
|
*coded++ = CHAR64(c1>>2);
|
|
|
|
if (--bytes == 0) {
|
|
|
|
*coded++ = CHAR64((c1&0x03)<<4);
|
|
|
|
*coded++ = '=';
|
|
|
|
*coded++ = '=';
|
|
|
|
} else {
|
|
|
|
c2 = *data++;
|
|
|
|
*coded++ = CHAR64(((c1&0x03)<<4)|(c2>>4));
|
|
|
|
if (--bytes == 0) {
|
|
|
|
*coded++ = CHAR64((c2&0x0f)<<2);
|
|
|
|
*coded++ = '=';
|
|
|
|
} else {
|
|
|
|
c3 = *data++; --bytes;
|
|
|
|
*coded++ = CHAR64(((c2&0x0f)<<2)|(c3>>6));
|
|
|
|
*coded++ = CHAR64(c3&0x3f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return coded;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* sanitize "untrusted" text, replacing special control characters with the C
|
|
|
|
string version ("\x"), and replacing unprintable chars with ".".
|
|
|
|
text can grow to double size, so keep output buffer long enough!
|
|
|
|
returns a pointer to the first untouched byte of the output buffer.
|
|
|
|
*/
|
|
|
|
char *xiosanitize(const char *data, /* input data */
|
|
|
|
size_t bytes, /* length of input data, >=0 */
|
|
|
|
char *coded /* output buffer, must be long enough */
|
|
|
|
) {
|
|
|
|
int c;
|
|
|
|
|
|
|
|
while (bytes > 0) {
|
|
|
|
c = *(unsigned char *)data++;
|
|
|
|
switch (c) {
|
|
|
|
case '\0' : *coded++ = '\\'; *coded++ = '0'; break;
|
|
|
|
case '\a' : *coded++ = '\\'; *coded++ = 'a'; break;
|
|
|
|
case '\b' : *coded++ = '\\'; *coded++ = 'b'; break;
|
|
|
|
case '\t' : *coded++ = '\\'; *coded++ = 't'; break;
|
|
|
|
case '\n' : *coded++ = '\\'; *coded++ = 'n'; break;
|
|
|
|
case '\v' : *coded++ = '\\'; *coded++ = 'v'; break;
|
|
|
|
case '\f' : *coded++ = '\\'; *coded++ = 'f'; break;
|
|
|
|
case '\r' : *coded++ = '\\'; *coded++ = 'r'; break;
|
|
|
|
case '\'' : *coded++ = '\\'; *coded++ = '\''; break;
|
|
|
|
case '\"' : *coded++ = '\\'; *coded++ = '"'; break;
|
|
|
|
case '\\' : *coded++ = '\\'; *coded++ = '\\'; break;
|
|
|
|
default:
|
|
|
|
if (!isprint(c))
|
|
|
|
c = '.';
|
|
|
|
*coded++ = c;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
--bytes;
|
|
|
|
}
|
|
|
|
return coded;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* print the bytes in hex */
|
|
|
|
char *
|
|
|
|
xiohexdump(const unsigned char *data, size_t bytes, char *coded) {
|
|
|
|
int space = 0;
|
|
|
|
while (bytes-- > 0) {
|
|
|
|
if (space) { *coded++ = ' '; }
|
|
|
|
coded += sprintf(coded, "%02x", *data++);
|
|
|
|
space = 1;
|
|
|
|
}
|
|
|
|
return coded;
|
|
|
|
}
|
2008-09-22 20:17:55 +00:00
|
|
|
|
|
|
|
/* write the binary data to output buffer codbuff in human readable form.
|
|
|
|
bytes gives the length of the data, codlen the available space in codbuff.
|
|
|
|
coding specifies how the data is to be presented. Not much to select now.
|
|
|
|
returns a pointer to the first char in codbuff that has not been overwritten;
|
|
|
|
it might also point to the first char after the buffer!
|
2014-03-22 19:07:20 +00:00
|
|
|
this function does not write a terminating \0
|
2008-09-22 20:17:55 +00:00
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
_xiodump(const unsigned char *data, size_t bytes, char *codbuff, size_t codlen,
|
|
|
|
int coding) {
|
|
|
|
int start = 1;
|
|
|
|
int space = coding & 0xff;
|
|
|
|
|
2014-03-22 19:07:20 +00:00
|
|
|
if (bytes <= 0) { return codbuff; }
|
|
|
|
if (codlen < 1) { return codbuff; }
|
2008-09-22 20:17:55 +00:00
|
|
|
if (space == 0) space = -1;
|
|
|
|
if (0) {
|
|
|
|
; /* for canonical reasons */
|
|
|
|
} else if (1) {
|
|
|
|
/* simple hexadecimal output */
|
2014-03-22 19:07:20 +00:00
|
|
|
if (3*bytes+1 > codlen) {
|
|
|
|
bytes = (codlen-1)/3; /* "truncate" data so generated text fits */
|
2008-09-22 20:17:55 +00:00
|
|
|
}
|
2014-03-22 19:07:20 +00:00
|
|
|
*codbuff++ = 'x';
|
2008-09-22 20:17:55 +00:00
|
|
|
while (bytes-- > 0) {
|
|
|
|
if (start == 0 && space == 0) {
|
|
|
|
*codbuff++ = ' ';
|
|
|
|
space = (coding & 0xff);
|
|
|
|
}
|
|
|
|
codbuff += sprintf(codbuff, "%02x", *data++);
|
|
|
|
start = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return codbuff;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* write the binary data to codbuff in human readable form.
|
|
|
|
bytes gives the length of the data, codlen the available space in codbuff.
|
|
|
|
coding specifies how the data is to be presented. Not much to select now.
|
|
|
|
null terminates the output. returns a pointer to the output string.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
xiodump(const unsigned char *data, size_t bytes, char *codbuff, size_t codlen,
|
|
|
|
int coding) {
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
result = _xiodump(data, bytes, codbuff, codlen-1, coding);
|
|
|
|
*result = '\0';
|
|
|
|
return codbuff;
|
|
|
|
}
|