/* * Copyright (c) 2004 Teodor Sigaev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "tlog.h" #include "tmalloc.h" #include "prs_hmap.h" #define CS_WAITKEY 0 #define CS_INKEY 1 #define CS_WAITEQ 2 #define CS_WAITVALUE 3 #define CS_INVALUE 4 #define CS_IN2VALUE 5 #define CS_WAITDELIM 6 #define CS_INESC 7 #define CS_IN2ESC 8 static char * nstrdup(char *ptr, int len) { char *res = tmalloc(len + 1), *cptr; memcpy(res, ptr, len); res[len] = '\0'; cptr = ptr = res; while (*ptr) { if (*ptr == '\\') ptr++; *cptr = *ptr; ptr++; cptr++; } *cptr = '\0'; return res; } void parse_hmap(char *in, HMap ** m) { HMap *mptr; char *ptr = in, *begin = NULL; char num = 0; int state = CS_WAITKEY; while (*ptr) { if (*ptr == ',') num++; ptr++; } *m = mptr = (HMap *) t0malloc(sizeof(HMap) * (num + 2)); ptr = in; while (*ptr) { if (state == CS_WAITKEY) { if (isalpha((unsigned char) *ptr)) { begin = ptr; state = CS_INKEY; } else if (!isspace((unsigned char) *ptr)) tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr); } else if (state == CS_INKEY) { if (isspace((unsigned char) *ptr)) { mptr->key = nstrdup(begin, ptr - begin); state = CS_WAITEQ; } else if (*ptr == '=') { mptr->key = nstrdup(begin, ptr - begin); state = CS_WAITVALUE; } else if (!isalpha((unsigned char) *ptr)) tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr); } else if (state == CS_WAITEQ) { if (*ptr == '=') state = CS_WAITVALUE; else if (!isspace((unsigned char) *ptr)) tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr); } else if (state == CS_WAITVALUE) { if (*ptr == '"') { begin = ptr + 1; state = CS_INVALUE; } else if (!isspace((unsigned char) *ptr)) { begin = ptr; state = CS_IN2VALUE; } } else if (state == CS_INVALUE) { if (*ptr == '"') { mptr->value = nstrdup(begin, ptr - begin); mptr++; state = CS_WAITDELIM; } else if (*ptr == '\\') state = CS_INESC; } else if (state == CS_IN2VALUE) { if (isspace((unsigned char) *ptr) || *ptr == ',') { mptr->value = nstrdup(begin, ptr - begin); mptr++; state = (*ptr == ',') ? CS_WAITKEY : CS_WAITDELIM; } else if (*ptr == '\\') state = CS_INESC; } else if (state == CS_WAITDELIM) { if (*ptr == ',') state = CS_WAITKEY; else if (!isspace((unsigned char) *ptr)) tlog(TL_ALARM|TL_EXIT,"parse_hmap: Syntax error in position %d near \"%c\"\n", (int) (ptr - in), *ptr); } else if (state == CS_INESC) state = CS_INVALUE; else if (state == CS_IN2ESC) state = CS_IN2VALUE; else tlog(TL_CRIT|TL_EXIT,"parse_hmap: Bad parser state %d at position %d near \"%c\"\n", state, (int) (ptr - in), *ptr); ptr++; } if (state == CS_IN2VALUE) { mptr->value = nstrdup(begin, ptr - begin); mptr++; } else if (!(state == CS_WAITDELIM || state == CS_WAITKEY)) tlog(TL_ALARM|TL_EXIT,"parse_hmap: unexpected end of line\n"); } static int getnumber(char c) { if ( c == '\0' ) return 0; else if ( c >= '0' && c <= '9' ) return c - '0'; else if ( c >= 'A' && c <= 'F' ) return c - 'A' + 10; else if ( c >= 'a' && c <= 'f' ) return c - 'a' + 10; return -1; } static char * unescape(char *str, int len) { char *in = str, *out = tmalloc(sizeof(char)*(len+1)); char *res = out; while(in - str < len ) { char c = *in; if ( c == '+' ) c = ' '; else if ( c == '%' ) { char *ptr = in; int i1, i2; ptr++; if ( ptr - str >= len || (i1=getnumber(*ptr)) < 0 ) goto process; ptr++; if ( ptr - str >= len || (i2=getnumber(*ptr)) < 0 ) goto process; c = (i1<<4) | i2; in+=2; } process: *out = c; out++; in++; } *out = '\0'; return res; } #define QS_WAITKEY 1 #define QS_INKEY 2 #define QS_WAITVAL 3 #define QS_INVAL 4 int parse_query_string(char *in, HMap ** m) { HMap *mptr; char *ptr = in, *begin = NULL; char num = 0; int state = QS_WAITKEY; while (*ptr) { if (*ptr == '&') num++; ptr++; } *m = mptr = (HMap *) t0malloc(sizeof(HMap) * (num + 2)); ptr = in; while (*ptr) { if ( state == QS_WAITKEY ) { if ( !( *ptr == '&' || *ptr == '=' ) ) { begin = ptr; state = QS_INKEY; } } else if ( state == QS_INKEY ) { if ( *ptr == '=' ) { mptr->key = unescape( begin , ptr-begin ); state = QS_WAITVAL; } else if ( *ptr == '&' ) { mptr->key = unescape( begin , ptr-begin ); mptr->value = t0malloc(sizeof(char)); mptr++; state = QS_WAITKEY; } } else if ( state == QS_WAITVAL ) { if ( *ptr == '&' ) { mptr->value = t0malloc(sizeof(char)); state = QS_WAITKEY; mptr++; } else { begin = ptr; state = QS_INVAL; } } else if ( state == QS_INVAL ) { if ( *ptr == '&' ) { mptr->value = unescape( begin , ptr-begin ); mptr++; state = QS_WAITKEY; } } else tlog( TL_CRIT|TL_EXIT,"Wrong state of QUERY_STRING parser"); ptr++; } if ( state == QS_INVAL ) { mptr->value = unescape( begin , ptr-begin ); mptr++; } if ( state == QS_INKEY ) { mptr->key = unescape( begin , ptr-begin ); mptr->value = t0malloc(sizeof(char)); mptr++; } else if ( state == QS_WAITVAL ) { mptr->value = t0malloc(sizeof(char)); } return mptr - *m; }