/* Unescape the buffer pointed to by s 'in-place' using the (un)escape mechanizm
 described at http://www.postgresql.org/docs/9.0/static/datatype-binary.html
 The new size of s is assigned to r. Returns s. See PostgresqlResultSet_getBlob()
 below for usage and further info. See also Postgres' PQunescapeBytea() function
 which this function mirrors except it does not allocate a new string.
 */
static inline const void *unescape_bytea(uchar_t *s, int len, int *r) {
        assert(s);
        register int i, j;
        if (s[0] == '\\' && s[1] == 'x') { // bytea hex format
                static const uchar_t hex[128] = {
                        0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0,  1,  2,  3,  4,  5,  6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
                        0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0
                };
                for (i = 0, j = 2; j < len; j++) {
                        /*
                         According to the doc, whitespace between hex pairs are allowed. Blarg!!
                         */
                        if (isxdigit(s[j])) {
                                s[i] = hex[s[j]] << 4;
                                s[i] |= hex[s[j + 1]];
                                i++;
                                j++;
                        }
                }
        } else { // bytea escaped format
                uchar_t byte;
                for (i = j = 0; j < len; i++, j++) {
                        if ((s[i] = s[j]) == '\\') {
                                if (s[j + 1] == '\\')
                                        j++;
                                else if ((ISFIRSTOCTDIGIT(s[j + 1]))
                                         && (ISOCTDIGIT(s[j + 2]))
                                         && (ISOCTDIGIT(s[j + 3]))) {
                                        byte = OCTVAL(s[j + 1]);
                                        byte = (byte << 3) + OCTVAL(s[j + 2]);
                                        byte = (byte << 3) + OCTVAL(s[j + 3]);
                                        s[i] = byte;
                                        j += 3;
                                }
                        }
                }
        }
        *r = i;
        if (i < j)
                s[i] = 0; // If unescape was performed, terminate the buffer to mirror postgres behavior
        return s;
}
int esc( const tchar * * s)
{
     /* Map escape sequences into their equivalent symbols. Return
      * the equivalent ASCII character. *s is advanced past the
      * escape sequence. If no escape sequence is present, the
      * current character is returned and the string is advanced by
      * one. The following are recognized:
      *
      *  \b     backspace
      *  \f     formfeed
      *  \n     newline
      *  \r     carriage return
      *  \s     space
      *  \t     tab
      *  \e     ASCII ESC character ('\033')
      *  \DDD   number formed of 1-3 octal digits
      *  \xDDD  number formed of 1-3 hex digits
      *  \^C    C = any letter. Control code
      */

     int rval;

     if( **s != _T('\\') )
          rval = *( (*s)++ );
     else {
          ++(*s);                                 /* Skip the \ */
          switch( toupper(**s) ) {
            case _T('\0'):  rval = _T('\\');             break;
            case _T('B'):   rval = _T('\b') ;            break;
            case _T('F'):   rval = _T('\f') ;            break;
            case _T('N'):   rval = _T('\n') ;            break;
            case _T('R'):   rval = _T('\r') ;            break;
            case _T('S'):   rval = _T(' ')  ;            break;
            case _T('T'):   rval = _T('\t') ;            break;
            case _T('E'):   rval = _T('\033');           break;

            case _T('^'):
              rval = *++(*s) ;
              rval = _toupper(rval) - _T('@') ;
              break;

            case _T('X'):
              rval = 0;
              ++(*s);
              if( ISHEXDIGIT(**s) ) {
                   rval  = hex2bin( *(*s)++ );
              }
              if( ISHEXDIGIT(**s) ) {
                   rval <<= 4;
                   rval  |= hex2bin( *(*s)++ );
              }
              if( ISHEXDIGIT(**s) ) {
                   rval <<= 4;
                   rval  |= hex2bin( *(*s)++ );
              }
              --(*s);
              break;

            default:
              if( !ISOCTDIGIT(**s) )
                   rval = **s;
              else {
                   ++(*s);
                   rval = oct2bin( *(*s)++ );
                   if( ISOCTDIGIT(**s) ) {
                        rval <<= 3;
                        rval  |= oct2bin( *(*s)++ );
                   }
                   if( ISOCTDIGIT(**s) ) {
                        rval <<= 3;
                        rval  |= oct2bin( *(*s)++ );
                   }
                   --(*s);
              }
              break;
          }
          ++(*s);
     }
     return rval;
}