|
|
@@ -0,0 +1,114 @@ |
|
|
|
/* |
|
|
|
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 <https://www.gnu.org/licenses/>. |
|
|
|
*/ |
|
|
|
|
|
|
|
// OrIdow6, late November 2021 |
|
|
|
|
|
|
|
|
|
|
|
// stdin - a urlencoded string |
|
|
|
// stdout - the decoded string |
|
|
|
|
|
|
|
#define _GNU_SOURCE |
|
|
|
#include <stdio.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <stdint.h> |
|
|
|
|
|
|
|
#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); |
|
|
|
} |
|
|
|
} |