/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
// OrIdow6, late November 2021
// stdin - a urlencoded string
// stdout - the decoded string
#define _GNU_SOURCE
#include
#include
#include
#define BUFFER_SIZE 1024 * 300
int main(int argc, char** argv) {
uint8_t* inbuf = malloc(sizeof(uint8_t) * BUFFER_SIZE);
uint8_t* outbuf = malloc(sizeof(uint8_t) * BUFFER_SIZE + 2);
size_t outp = 0;
int state = -1;
int8_t digita = 0x0;
int8_t digitb = 0x0;
uint8_t digita_real;
uint8_t digitb_real;
// https://stackoverflow.com/questions/10324/convert-a-hexadecimal-string-to-an-integer-efficiently-in-c
// Because I can't be bothered to generate this manually
// Could be faster if you had a table for 16-bit integers, depending on caching
static const int8_t hextable[] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1, 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
};
while (1) {
size_t readS = fread(inbuf, sizeof(char), BUFFER_SIZE, stdin);
if (readS == 0) {
break;
}
for (size_t p = 0; p < readS; p++) {
if (state == -1) {
if (inbuf[p] != '%') {
outbuf[outp++] = inbuf[p];
} else {
state = 0;
}
} else if (state == 0) {
digita = hextable[inbuf[p]];
if (digita == (int8_t)-1 ) {
outbuf[outp++] = '%';
if (inbuf[p] != '%') {
outbuf[outp++] = inbuf[p];
state = -1;
} // else state remains 0
continue;
}
digita_real = inbuf[p];
state = 1;
} else {
digitb = hextable[inbuf[p]];
if (digitb == (int8_t)-1 ) {
digitb_real = inbuf[p];
outbuf[outp++] = '%';
outbuf[outp++] = digita_real;
if (inbuf[p] != '%') {
outbuf[outp++] = digitb_real;
state = -1;
} else {
state = 0;
}
continue;
}
outbuf[outp++] = digita << 4 | digitb;
state = -1;
}
}
fwrite(outbuf, outp, 1, stdout);
outp = 0;
if (readS < BUFFER_SIZE) {
break;
}
}
if (state == 0 || state == 1) {
fwrite("%", 1, 1, stdout);
}
if (state == 1) {
fwrite(&digita_real, 1, 1, stdout);
}
}