CGI-Cookie-XS

 view release on metacpan or  search on metacpan

XS.xs  view on Meta::CPAN

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "INLINE.h"

#define DDD(x)

#ifndef DDD
#define DDD(x) fprintf(stderr, "%s\n", x);
#endif

#define COOKIE_LEN_LIMIT 1024 * 4
#ifndef NULL
#define NULL (void*)0
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#ifndef BOOL
#define BOOL short int
#endif

//static char *encode_hex_str(const char*, char **);
extern char** XS_unpack_charPtrPtr(SV* arg);
extern void XS_pack_charPtrPtr( SV* arg, char** array, int count);

char Buffer[COOKIE_LEN_LIMIT];

static int _decode_hex_str(const char*, char **);

SV* _parse_cookie(char* cs) {
    int i, value_flag;
    char* p; /* moving first for look-ahead */
    char* q; /* moving slower for tracking values */
    char* decode;
    AV *array = NULL;
    HV *hash = NULL;
    BOOL parsing_value = FALSE;

    decode = (char *) malloc (COOKIE_LEN_LIMIT * sizeof(decode));
    if (decode == NULL) {
        croak("CGI::Cookie::XS::parse - Failed to malloc");
    }
    strncpy(Buffer, cs, COOKIE_LEN_LIMIT);
    Buffer[COOKIE_LEN_LIMIT-1] = '\0';
    hash = newHV();


    p = Buffer;
    DDD("before loop");
    while (*p == ' ' || *p == '\t') p++; // remove leading spaces
    q = p;
    while (*p) {
        //DDD("in loop");
        if (*p == '=' && !parsing_value ){
            array = newAV();
            *p = '\0';

            // Only move on if not the end of the cookie value
            if (*(p+1) != ';' && *(p+1) != ',' && *(p+1) != '\0')
              p++;

            _decode_hex_str(q, &decode);
            q = p;
            hv_store(
                hash, decode, strlen(decode), newRV_noinc((SV *)array), 0
            );
            //array = NULL;
            parsing_value = TRUE;
        } else if (*p == ';' || *p == ',') {
            *p = '\0';
            p++;
            while (*p == ' ')
                p++;
            _decode_hex_str(q, &decode);
            q = p;
            if (*decode != '\0' && parsing_value && array != NULL)
                av_push(array, newSVpvf("%s", decode));
            parsing_value = FALSE;
        } else if (*p == '&') { // find a second value
            *p = 0; p++;
            _decode_hex_str(q, &decode);
            q = p;
            if (parsing_value && array != NULL)
                av_push(array, newSVpvf("%s", decode));
        }
        p++;
    }
    DDD("before decode");
    if (*q != '\0' && parsing_value) {
        _decode_hex_str(q, &decode);
        DDD("before push array");
        if (array != NULL)
            av_push(array, newSVpvf("%s", decode));
        DDD("after push array");
    }
    if (decode) free(decode);
    DDD("before return");
    return newRV_noinc((SV *) hash);
}

char *encode_hex_str(const char *str, char **out_buf)

XS.xs  view on Meta::CPAN

        if ((isalnum(*str) && !(*str & 0x80)) || strchr(verbatim, *str))
            *c++ = *str;
        else if (*str == ' ')
            *c++ = '+';
        else if (*str == '\n') {
            *c++ = '%';
            *c++ = '0';
            *c++ = 'D';
            *c++ = '%';
            *c++ = '0';
            *c++ = 'A';
        } else {
            *c++ = '%';
            *c++ = hex[(*str >> 4) & 15];
            *c++ = hex[*str & 15];
        }
    *c = 0;
    return newstr;
}

static int decode_hex_octet(const char *s)
{
    int hex_value;
    char *tail, hex[3];

    if (s && (hex[0] = s[0]) && (hex[1] = s[1])) {
        hex[2] = 0;
        hex_value = strtol(hex, &tail, 16);
        if (tail - hex == 2)
            return hex_value;
    }
    return -1;
}


int _decode_hex_str (const char *str, char **out)
{
    char *dest = *out;
    int i, val;

    memset(dest, 0, COOKIE_LEN_LIMIT);

    if (!str && ! dest)
        return 0;

    // most cases won't have hex octets 
    if (!strchr(str, '%')){
        strcpy(dest, str);
        return 1;
    }


    for (i = 0; str[i]; i++) {
        *dest++ = (str[i] == '%' && (val = decode_hex_octet(str+i+1)) >= 0) ?
        i+=2, val : str[i];
    }
    return 1;
}


MODULE = CGI::Cookie::XS	PACKAGE = CGI::Cookie::XS

PROTOTYPES: DISABLE


SV *
_parse_cookie (cs)
	char *	cs

int
_decode_hex_str (str, out)
	char *	str
	char **	out



( run in 1.023 second using v1.01-cache-2.11-cpan-5a3173703d6 )