#line 213 "/home/travis/build/felix-lang/felix/src/packages/codecs.fdoc"
  
  publish """
  Encoder Decoders for URIs, Translates characters not allowed in URIs
  to %HEX equivalants
  
  Usage example:
  open URICodec;
  var s = "THis is a & test < or a url \n encoder \r\r Hello >";
  var enc = uri_encode(s);
  var dec = uri_decode(enc);
  println("S:"+s);
  println("ENC:"+enc);
  println("DECX:"+dec);
  """
  
  class URICodec {
  
    header """
    /* Code from http://www.zedwood.com/article/111/cpp-urlencode-function **/
    std::string char2hex( char dec )
    {
      char dig1 = (dec&0xF0)>>4;
      char dig2 = (dec&0x0F);
      if ( 0<= dig1 && dig1<= 9) dig1+=48;    //0,48inascii
      if (10<= dig1 && dig1<=15) dig1+=97-10; //a,97inascii
      if ( 0<= dig2 && dig2<= 9) dig2+=48;
      if (10<= dig2 && dig2<=15) dig2+=97-10;
  
      std::string r;
      r.append( &dig1, 1);
      r.append( &dig2, 1);
      return r;
    }
  
    std::string urlencode(const std::string &c)
    {
      std::string escaped="";
      int max = c.length();
      for(int i=0; i<max; i++)
      {
        if ( (48 <= c[i] && c[i] <= 57) ||//0-9
             (65 <= c[i] && c[i] <= 90) ||//abc...xyz
             (97 <= c[i] && c[i] <= 122) || //ABC...XYZ
             (c[i]=='~' || c[i]=='!' || c[i]=='*' || c[i]=='(' || c[i]==')' || c[i]=='\\''))
          {
            escaped.append( &c[i], 1);
          }
          else
          {
            escaped.append("%");
            escaped.append( char2hex(c[i]) );//converts char 255 to string "ff"
          }
      }
      return escaped;
    }
  
  """ requires Cxx_headers::iostream;
  
    gen uri_encode: string -> string = "urlencode($1)";
  
    private fun isxdigit_c: char -> int = "isxdigit((int)$1)" requires C89_headers::ctype_h;
  
    private fun isxdigit (c:char):bool => if isxdigit_c(c) == 0 then false else true endif;
  
    private gen strtoul: string->ulong = "strtoul ((const char *)$1.c_str(),NULL,0)";
  
    fun uri_decode(encoded:string):string = {
      enum decode_state { SEARCH, CONVERT };
      var state = SEARCH;
      var decoded = "";
      for var i in 0 upto (int(len(encoded)) - 1) do
        match state with
          | #SEARCH => { if encoded.[i] != char('%') do
  
                           decoded = decoded +
                             if encoded.[i] == char('+') then char(' ') else encoded.[i] endif;
                         else
                           state = CONVERT;
                         done
                       }
          | #CONVERT => { var temp = encoded.[i to (i+2)];
                         var both = true;
                         for var j in 0 upto 1 do
                           if not isxdigit(temp.[j]) do
                             both = false;
                           done
                         done
                         if both do
                           decoded = decoded + char(strtoul("0x"+temp));
                           i++;
                         done
                         state = SEARCH;
                        }
        endmatch;
      done
      return decoded;
    }
  
  
  }