/***************************************************************************
 *                                                                         *
 *   ENCUTIL.CPP                                                           *
 *                                                                         *
 *   Copyright (c) 1999 Galacticomm, Inc.         All Rights Reserved.     *
 *                                                                         *
 *   Utilities for HTML/URL encoding output.                               *
 *                                                                         *
 *                                            - J. Alvrus   02/03/1999     *
 *                                                                         *
 ***************************************************************************/

#include "encutil.h"

#define FILREV "$Revision: 1 $"
MARKSOURCE(encutil)

CHAR *                             //   returns allocated buffer
urlEncodeStr(                      // encode special characters in a URL
const CHAR *src)                   //   unencoded URL
{
     ASSERT(src != NULL);
     size_t len=urlEncodeSize(src);
     CHAR *buf=new CHAR[len];
     return(urlEncodeBuf(buf,src,len));
}

size_t
urlEncodeSize(                     // size of encoded URL (incl '\0')
const CHAR *src)                   //   unencoded URL
{
     size_t len=0;
     CHAR c;
     ASSERT(src != NULL);
     while ((c=*src++) != '\0') {
          if (urlNeedEncode(c)) {
               len+=CSTRLEN("%XX");
          }
          else {
               ++len;
          }
     }
     return(len+1);
}

CHAR *                             //   returns pointer to destination
urlEncodeBuf(                      // encode special characters in URL
CHAR *buf,                         //   buffer to receive encoded string
const CHAR *src,                   //   unencoded URL
size_t bufSiz)                     //   size of destination buffer
{
     if (bufSiz > 0) {
          size_t i=0;
          CHAR c;
          ASSERT(src != NULL);
          ASSERT(buf != NULL);
          while ((c=*src++) != '\0' && i < bufSiz-1) {
               if (urlNeedEncode(c)) {
                    if (i >= bufSiz-CSTRLEN("%XX")) {
                         break;
                    }
                    buf[i++]='%';
                    buf[i++]=hexdig((c>>4)&0x0F);
                    buf[i++]=hexdig(c&0x0F);
               }
               else {
                    buf[i++]=c;
               }
          }
          buf[i]='\0';
     }
     return(buf);
}

size_t
urlDecodeSize(                     // size of decoded URL (incl '\0')
const CHAR *src)                   //   encoded URL
{
     size_t len=0;
     CHAR c;
     ASSERT(src != NULL);
     while ((c=*src++) != '\0') {
          if (c == '%' && isxdigit(*src) && isxdigit(*(src+1))) {
               src+=2;
          }
          ++len;
     }
     return(len+1);
}

CHAR *                             //   returns pointer to destination
urlDecodeBuf(                      // decode special characters in URL
CHAR *buf,                         //   buffer to receive decoded string
const CHAR *src,                   //   unencoded URL
size_t bufSiz)                     //   size of destination buffer
{
     if (bufSiz > 0) {
          size_t i=0;
          CHAR c;
          ASSERT(src != NULL);
          ASSERT(buf != NULL);
          while ((c=*src++) != '\0' && i < bufSiz-1) {
               if (c == '%' && isxdigit(*src) && isxdigit(*(src+1))) {
                    c=(hexval(*src++)<<4)|(hexval(*src++));
               }
               buf[i++]=c;
          }
          buf[i]='\0';
     }
     return(buf);
}

bool
urlNeedEncode(                     // does this character need to be encoded?
CHAR c)                            //   character to check
{
     return(c <= ' ' || c >= '~' || strchr("\t\"#%<>?[\\]^`'{|}",c) != NULL);
}

CHAR *                             //   returns allocated buffer
entEncodeStr(                      // encode entities in a string
const CHAR *src)                   //   unencoded string
{
     ASSERT(src != NULL);
     size_t len=entSize(src);
     CHAR *buf=new CHAR[len];
     return(entEncodeBuf(buf,src,len));
}

size_t
entSize(                           // size of entity-encoded string (incl '\0')
const CHAR *src)                   //   unencoded string
{
     CHAR c;
     size_t len=0;
     ASSERT(src != NULL);
     while ((c=*src++) != '\0') {
          switch (c) {
          case '<':
               len+=CSTRLEN("&lt;");
               break;
          case '>':
               len+=CSTRLEN("&gt;");
               break;
          case '"':
               len+=CSTRLEN("&quot;");
               break;
          case '&':
               len+=CSTRLEN("&amp;");
               break;
          default:
               ++len;
               break;
          }
     }
     return(++len);
}

CHAR *                             //   returns pointer to destination
entEncodeBuf(                      // encode string using HTML entities
CHAR *buf,                         //   buffer to receive encoded string
const CHAR *src,                   //   unencoded string
size_t bufSiz)                     //   size of destination buffer
{
     CHAR c,*pOut=buf;
     ASSERT(buf != NULL);
     ASSERT(src != NULL);
     ASSERT(bufSiz != 0);
     while ((c=*src++) != '\0') {
          const CHAR *pAdd=NULL;
          switch (c) {
          case '<':
               pAdd="&lt;";
               break;
          case '>':
               pAdd="&gt;";
               break;
          case '"':
               pAdd="&quot;";
               break;
          case '&':
               pAdd="&amp;";
               break;
          }
          size_t addLen=pAdd == NULL ? 1 : strlen(pAdd);
          if ((size_t)(pOut-buf)+addLen >= bufSiz) {
               break;
          }
          if (pAdd != NULL) {
               pOut=stpcpy(pOut,pAdd);
          }
          else {
               *pOut++=c;
          }
     }
     *pOut='\0';
     return(buf);
}