Compare commits

..

19 commits
v0.1 ... main

Author SHA1 Message Date
Eric
aacf2324c7 improve decode time
atob() has been replaced with a lookup table, removing previous
conditionals and function calls necessary to decode.
2025-05-29 16:02:45 +02:00
Eric
debab62506 remove getsxts for better function readb
Decoding input is read faster now.
With this, all options have been tuned to a reasonable degree.
2025-05-29 13:48:49 +02:00
Eric
0a4a98390d improve printw to write faster
Now all encoding options are faster.
2025-05-29 00:51:00 +02:00
Eric
f0577d8ea0 decrease encode time
The functions encode and decode are now capable of processing larger
buffers with less conditional logic. Input and output functions need to
follow suit to make better use of this next. Encode without line
wrapping already makes use of these improvements, because input and
output are now entirely handled by <stdio.h> functions.
2025-05-28 23:24:05 +02:00
Eric
3194981825 repair Makefile to include -g in CFLAGS again 2025-05-28 20:33:16 +02:00
Eric
4e8bb86ddd change Makefile to be stricter
-Og enables better detection of bugs that would only occur in optimized
compilations and allows for slightly lesser than -O1 optimization that
does not interfere with debugging.
2025-05-28 17:55:13 +02:00
Eric
733a013ee7 remove bugs related to uninitialized variables
These bugs became visible when using optimization options. They were
either not present unoptimized or very unlikely to occur. However, given
the options, the resulting program would behave incorrectly and reliably
break under all circumstances.

The makefile will see the intended changes accordingly in the following
commit to ensure compatibility.
2025-05-28 17:31:07 +02:00
Eric
fa5095133a remove buffer size dependency from input functions
This should've been part of 848c37, when buffers were unwired from input
functions. Now buffer size is also no longer supplied in function calls
but assumed. It is up to the caller to provide appropriately sized
buffers.
2025-05-27 18:37:48 +02:00
Eric
b76c50a91b change header macro names to be more idiomatic 2025-05-27 15:14:55 +02:00
Eric
196c54cffa change newline termination behaviour when encoding
Before, encoded text would be newline terminated by default.
This was supposed to make short encoded strings easier to read when
using an interactive shell.
Now this only happens with the explicit line wrap option.
2025-05-27 02:09:21 +02:00
Eric
cd091b6a0c change help message to reflect new options -uw 2025-05-27 01:36:27 +02:00
Eric
0dba01d98e add linewrap option when encoding (76 columns) 2025-05-27 01:32:09 +02:00
Eric
6c7d699f1a add newline to end of file when encoding 2025-05-27 00:27:25 +02:00
Eric
623d0a5c3b add newline recognition for encoded input 2025-05-27 00:14:33 +02:00
Eric
a91be306b1 add base64url encoding option 2025-05-26 23:59:47 +02:00
Eric
8991fe1a69 correct Makefile recipe for encode.o
Since 848c37 encode.o no longer requires input.h.
2025-05-26 23:14:39 +02:00
Eric
28fcd5ed7a change file trans.{c,h} to encode.{c,h} 2025-05-26 23:12:16 +02:00
Eric
221a8588c0 add writing to file output option 2025-05-26 22:38:33 +02:00
Eric
848c3749d2 change function definitions
Buffers are no longer wired into any input or translation functions.
They are supplied as arguments through main.
2025-05-26 12:23:54 +02:00
10 changed files with 247 additions and 182 deletions

View file

@ -1,12 +1,14 @@
CFLAGS = -g -Wall -Wextra -Werror CC = gcc
CFLAGS = -Og -g -Wall -Wextra -Werror
objects = main.o input.o trans.o objects = main.o input.o output.o encode.o
b64 : $(objects) b64 : $(objects)
cc -o b64 $(objects) $(CC) -o b64 $(objects)
main.o trans.o input.o : input.h main.o input.o : input.h
main.o trans.o : trans.h main.o encode.o : encode.h
main.o output.o : output.h
.PHONY : clean .PHONY : clean
clean : clean :

107
encode.c Normal file
View file

@ -0,0 +1,107 @@
#include "encode.h"
#define PADDING '='
static
unsigned char b64toascii[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz" \
"0123456789" \
"+/";
static
unsigned char b64urltoascii[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz" \
"0123456789" \
"-_";
static
unsigned char asciitob64[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 62, 0, 62, 0, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 0, 0,
0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 0, 0, 0, 0, 63, 0, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51
};
int
encode(unsigned char *op, int olen, unsigned char *sp, int url)
{
int tmp;
unsigned char *table;
unsigned char *sbeg;
unsigned char *tend;
table = (!url) ? b64toascii : b64urltoascii;
sbeg = sp;
tend = op + olen - (olen % 3);
while (op < tend) {
*sp++ = table[(*op & ~3) >> 2];
tmp = (*op++ & 3) << 4;
*sp++ = table[tmp + ((*op & ~15) >> 4)];
tmp = (*op++ & 15) << 2;
*sp++ = table[tmp + ((*op & 192) >> 6)];
*sp++ = table[*op++ & ~192];
}
switch (olen % 3) {
case 2:
*sp++ = table[(*op & ~3) >> 2];
tmp = (*op++ & 3) << 4;
*sp++ = table[tmp + ((*op & ~15) >> 4)];
*sp++ = table[(*op & 15) << 2];
*sp++ = PADDING;
break;
case 1:
*sp++ = table[(*op & ~3) >> 2];
*sp++ = table[(*op & 3) << 4];
*sp++ = PADDING;
*sp++ = PADDING;
break;
}
return sp-sbeg;
}
int
decode(unsigned char *sp, int slen, unsigned char *op)
{
int tmp, b;
unsigned char *obeg;
unsigned char *qend;
obeg = op;
qend = sp + slen - (slen % 4);
while (sp < qend) {
tmp = asciitob64[*sp++] << 2;
b = asciitob64[*sp++];
*op++ = tmp + ((b & ~15) >> 4);
tmp = (b & 15) << 4;
b = asciitob64[*sp++];
*op++ = tmp + ((b & ~3) >> 2);
*op++ = ((b & 3) << 6) + asciitob64[*sp++];
}
switch (slen % 4) {
case 3:
tmp = asciitob64[*sp++] << 2;
b = asciitob64[*sp++];
*op++ = tmp + ((b & ~15) >> 4);
tmp = (b & 15) << 4;
*op++ = tmp + ((asciitob64[*sp++] & ~3) >> 2);
break;
case 2:
tmp = asciitob64[*sp++] << 2;
*op++ = tmp + ((asciitob64[*sp++] & ~15) >> 4);
break;
}
return op-obeg;
}

10
encode.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef ENCODE_H
#define ENCODE_H
int
encode(unsigned char *op, int olen, unsigned char *sp, int url);
int
decode(unsigned char *sp, int slen, unsigned char *op);
#endif

54
input.c
View file

@ -1,37 +1,29 @@
#include "input.h" #include "input.h"
#define OBUFSIZE 4 #define PADDING '='
#define SBUFSIZE 5
#define PADDING '=' int
readb(FILE *fp, unsigned char *s, int slen)
unsigned char o[OBUFSIZE];
unsigned char s[SBUFSIZE];
unsigned char *
getocts(FILE *fp, int *np)
{ {
int n, c; int read, tread;
unsigned char *send, *sbeg;
unsigned char *l, *r;
read = tread = 0;
sbeg = l = r = s;
while (tread < slen && (read = fread(l, sizeof(*l), slen-tread, fp))) {
tread += read;
send = s + tread;
for (r = l; r < send; ++r)
if (*r != '\n')
*l++ = *r;
tread -= r - l;
if (l > sbeg) {
for (--l; *l == PADDING; --l)
;
++l;
}
}
n = 0; return l-sbeg;
while (n < OBUFSIZE-1 && (c = fgetc(fp)) != EOF)
o[n++] = c;
*np = n;
return (*np) ? o : NULL;
}
unsigned char *
getsxts(FILE *fp, int *np)
{
int n, p, c;
n = p = 0;
while (n < SBUFSIZE-1 && (c = fgetc(fp)) != EOF && c != PADDING)
s[n++] = c;
while (n+p < SBUFSIZE-1)
s[n+p++] = PADDING;
*np = n;
return (n) ? s : NULL;
} }

14
input.h
View file

@ -1,15 +1,9 @@
#ifndef HEADER_INPUT #ifndef INPUT_H
#define HEADER_INPUT #define INPUT_H
#include <stdio.h> #include <stdio.h>
extern unsigned char o[]; int
extern unsigned char s[]; readb(FILE *fp, unsigned char *s, int slen);
unsigned char *
getocts(FILE *fp, int *np);
unsigned char *
getsxts(FILE *fp, int *np);
#endif #endif

76
main.c
View file

@ -1,58 +1,80 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "input.h" #include "input.h"
#include "trans.h" #include "output.h"
#include "encode.h"
#define OCTETBUF 1500
#define SXTETBUF 2000
unsigned char obuf[OCTETBUF];
unsigned char sbuf[SXTETBUF];
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int c, n, dec, hlp; int c, n, last;
char *prog = *argv; int dec, url, hlp, wrp;
unsigned char *b; FILE *in, *out;
FILE *fp; char *prog;
dec = hlp = 0; prog = *argv;
dec = url = hlp = wrp = 0;
while (--argc > 0 && (*++argv)[0] == '-') while (--argc > 0 && (*++argv)[0] == '-')
while ((c = *++argv[0])) while ((c = *++argv[0]))
switch (c) { switch (c) {
case 'd': case 'd':
dec = 1; dec = 1;
break; break;
case 'u':
url = 1;
break;
case 'h': case 'h':
hlp = 1; hlp = 1;
break; break;
case 'w':
wrp = 1;
break;
default: default:
fprintf(stderr, "%s: illegal option %c\n", prog, c); fprintf(stderr, "%s: illegal option %c\n", prog, c);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
break; break;
} }
if (hlp) { if (hlp) {
fprintf(stdout, "Usage: %s -d -h file\n", prog); fprintf(stdout, "Usage: %s -duhw infile outfile\n", prog);
} else if (argc != 1) {
if (dec) {
while ((b = getsxts(stdin, &n))) {
b = decode(b, &n);
fwrite(b, sizeof(*b), n, stdout);
}
} else {
while ((b = getocts(stdin, &n)))
printf("%s", encode(b, n));
}
} else { } else {
if ((fp = fopen(*argv, "r")) == NULL) { in = out = NULL;
if (argc >= 1 && (in = fopen(*argv, "r")) == NULL) {
fprintf(stderr, "%s: can't open %s\n", prog, *argv); fprintf(stderr, "%s: can't open %s\n", prog, *argv);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
else if (dec) { if (argc == 2 && (out = fopen(*(argv+1), "w")) == NULL) {
while ((b = getsxts(fp, &n))) { fprintf(stderr, "%s: can't open %s\n", prog, *(argv+1));
b = decode(b, &n); exit(EXIT_FAILURE);
fwrite(b, sizeof(*b), n, stdout);
}
} else {
while ((b = getocts(fp, &n)))
printf("%s", encode(b, n));
} }
fclose(fp); if (dec) {
while ((n = readb((in) ? in : stdin, sbuf, SXTETBUF))) {
n = decode(sbuf, n, obuf);
fwrite(obuf, sizeof(*obuf), n, (out) ? out : stdout);
}
} else if (wrp) {
last = 0;
while ((n = fread(obuf, sizeof(*obuf), OCTETBUF, (in) ? in : stdin))) {
n = encode(obuf, n, sbuf, url);
last = printw((out) ? out : stdout, sbuf, n);
}
if (last != '\n')
fprintf((out) ? out : stdout, "\n");
} else {
while ((n = fread(obuf, sizeof(*obuf), OCTETBUF, (in) ? in : stdin))) {
n = encode(obuf, n, sbuf, url);
fwrite(sbuf, sizeof(*sbuf), n, (out) ? out : stdout);
}
}
if (in)
fclose(in);
if (out)
fclose(out);
} }
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

38
output.c Normal file
View file

@ -0,0 +1,38 @@
#include "output.h"
#define WRAPCOL 76
char
printw(FILE *fp, unsigned char *s, int slen)
{
static int col;
int c;
c = '\n';
if (col) {
if (slen >= WRAPCOL-col) {
fwrite(s, sizeof(*s), WRAPCOL-col, fp);
s += WRAPCOL-col;
slen -= WRAPCOL-col;
col = 0;
fputc('\n', fp);
} else {
fwrite(s, sizeof(*s), slen, fp);
s += slen;
col += slen;
slen -= slen;
c = *(s+slen-1);
}
}
for (; slen >= WRAPCOL; slen -= WRAPCOL, s += WRAPCOL) {
fwrite(s, sizeof(*s), WRAPCOL, fp);
fputc('\n', fp);
}
if (slen > 0) {
fwrite(s, sizeof(*s), slen, fp);
col += slen;
c = *(s+slen-1);
}
return c;
}

9
output.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef OUTPUT_H
#define OUTPUT_H
#include <stdio.h>
char
printw(FILE *fp, unsigned char *s, int slen);
#endif

97
trans.c
View file

@ -1,97 +0,0 @@
#include "trans.h"
#define PADDING '='
unsigned char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz" \
"0123456789" \
"+/";
unsigned char *
encode(unsigned char *op, int np)
{
extern unsigned char s[];
unsigned char *sp;
int n;
sp = s;
switch (np) {
case 3:
*sp++ = b64[(*op & ~3) >> 2];
n = (*op++ & 3) << 4;
*sp++ = b64[n + ((*op & ~15) >> 4)];
n = (*op++ & 15) << 2;
*sp++ = b64[n + ((*op & 192) >> 6)];
*sp = b64[*op & ~192];
break;
case 2:
*sp++ = b64[(*op & ~3) >> 2];
n = (*op++ & 3) << 4;
*sp++ = b64[n + ((*op & ~15) >> 4)];
*sp++ = b64[(*op & 15) << 2];
*sp = PADDING;
break;
case 1:
*sp++ = b64[(*op & ~3) >> 2];
*sp++ = b64[(*op & 3) << 4];
*sp++ = PADDING;
*sp = PADDING;
break;
}
return s;
}
unsigned char *
decode(unsigned char *sp, int *np)
{
extern unsigned char o[];
unsigned char *op;
int n, b, atob(int c);
op = o;
switch (*np) {
case 4:
n = atob(*sp++) << 2;
b = atob(*sp++);
*op++ = n + ((b & ~15) >> 4);
n = (b & 15) << 4;
b = atob(*sp++);
*op++ = n + ((b & ~3) >> 2);
*op = ((b & 3) << 6) + atob(*sp);
break;
case 3:
n = atob(*sp++) << 2;
b = atob(*sp++);
*op++ = n + ((b & ~15) >> 4);
n = (b & 15) << 4;
*op = n + ((atob(*sp) & ~3) >> 2);
break;
case 2:
n = atob(*sp++) << 2;
*op = n + ((atob(*sp) & ~15) >> 4);
break;
}
*np = op-o+1;
return o;
}
int atob(int c)
{
if (c >= 'A' && c <= 'Z')
c -= 'A';
else if (c >= 'a' && c <= 'z')
c = c - 'a' + 26;
else if (c >= '0' && c <= '9')
c = c - '0' + 26 * 2;
else if (c == '+')
c = 62;
else
c = 63;
return c;
}

12
trans.h
View file

@ -1,12 +0,0 @@
#ifndef HEADER_TRANS
#define HEADER_TRANS
#include "input.h"
unsigned char *
encode(unsigned char *op, int np);
unsigned char *
decode(unsigned char *sp, int *np);
#endif