// url_decode.cpp
#include "url_decode.h"
#include <FL/filename.H>  // FL_PATH_MAX
#include <string.h>
#include <stdio.h>        // fprintf

/*****************************************************************************/

// decode lookup table: hex code, character
// A very short Google search revealed these ones. Add to the list as needed.
// List must be terminated with a empty entry

static const char *lookup_table[][2] = {
   {"20", " "}, {"24", "$"}, {"23", "#"}, {"25", "%"},  {"26", "&"}, {"27", "'"},
   {"2F", "/"}, {"3A", ":"}, {"3B", ";"}, {"3C", "<"},  {"3D", "="}, {"3E", ">"},
   {"3F", "?"}, {"40", "@"}, {"5B", "["}, {"5C", "\\"}, {"5D", "]"}, {"5E", "^"},
   {"60", "`"}, {"7B", "{"}, {"7C", "|"}, {"7D", "}"}, {"7E", "~"},
   {0, 0}
};

/*****************************************************************************/

const char *decode_lookup(const char *s)
{
   const char *val    = NULL;
   const char **entry = NULL;

   for(int i = 0; lookup_table[i][0]; i++)
   {
      entry = lookup_table[i];

      if(!strcasecmp(s, entry[0]))
      {
         // found match
         val = entry[1];
         break;
      }
   }

   return val;
}

/*****************************************************************************/

char* url_decode(const char *s)
{
   char s2[FL_PATH_MAX];   // Buffer to hold the decoded string
   char hexcode[3];        // Buffer to hold the 2-digit hex code.

   int i = 0;   // index into s2

   const char *symbol = NULL;   // The decoded character

   // init the buffers
   memset(s2, '\0', FL_PATH_MAX*sizeof(char));
   memset(hexcode, '\0', 3*sizeof(char));

   // Decode s but looking at each character.
   // If a '%' found, then decode the 2-digit
   // hex value that follows it. If the hex value
   // is missing or not in our limited table,
   for(const char *c = s; *c != '\0' && i < FL_PATH_MAX; ++c)
   {
      // Only dive into the encoding if the '%' occurrs within 2+1 positions
      // from the end.
      if(*c == '%' && (c - s > 3))   // start of hex code
      {
         strncpy(hexcode, c+1, 2); // copy the 2 digits

         symbol = decode_lookup(hexcode);

         // Was hexcode known?
         if(symbol)
         {
            // Special cases.
            switch(*symbol)
            {
               // If s has a %25%25 it should be resolved to
               // a singled '%'. Atleast this is what I noticed
               // should happen with Konqueror encoded strings
               case '%':
                  if(i == 0 || s2[i-1] != '%')
                     s2[i++] = *symbol;
               break;

               default:
                  s2[i++] = *symbol;
            }
         }
         else
            fprintf(stderr, "decode: Unknown hex code: %%%s\n", hexcode);

         c += 2; // skip over the hex digits
   }
   else
      s2[i++] = *c;
}

   // Make a stand-alone copy for the caller
   int len      = strlen(s2);
   char *retval = new char[len + 1]; // +1='\0'

   // Should be safe to use strcpy here since s2 is init'd with all '\0'
   strcpy(retval, s2);

   return retval;
}

