/* 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() { 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); } }