From d3a53b82aa57f5090d95b69e6f567b06eb544df9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 10 Feb 2013 20:06:08 +0100 Subject: initial commit of 1.13 sources --- src/vf_parser.c | 1182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1182 insertions(+) create mode 100644 src/vf_parser.c (limited to 'src/vf_parser.c') diff --git a/src/vf_parser.c b/src/vf_parser.c new file mode 100644 index 0000000..bf7b789 --- /dev/null +++ b/src/vf_parser.c @@ -0,0 +1,1182 @@ +/****************************************************************************** + + (C) Nick Marley, 2001 - + + This software is distributed under the GNU Lesser General Public Licence. + Please read and understand the comments at the top of vf_iface.h before use! + +FILE + $Workfile: vf_parser.c $ + $Revision: 1.22 $ + $Author: tilda $ + +ORIGINAL AUTHOR + Nick Marley + +DESCRIPTION + Parser for text stream in vobject format. + +REFERENCES + (none) + +MODIFICATION HISTORY + * $Log: vf_parser.c,v $ + * Revision 1.22 2002/11/16 13:19:10 tilda + * IID639288 - Implement method for adding subobjects. + * + * Revision 1.21 2002/11/15 09:15:00 tilda + * IID638823 - Various portability issues. + * + * Revision 1.20 2002/11/03 18:43:16 tilda + * IID619851 - Update and check headers and function prototypes. + * + * Revision 1.19 2002/11/02 18:29:26 tilda + * IID485157 - UI does character conversion based on CHARSET property. + * + * Revision 1.18 2002/11/02 08:56:17 tilda + * Start of internationalisation changes. + * + * Revision 1.17 2002/10/26 16:09:23 tilda + * IID629125 - Ensure string functions used are portable. + * + * Revision 1.16 2002/10/08 21:45:07 tilda + * IID620473 - reduce c-runtime dependencies. + * + * Revision 1.15 2002/10/08 21:25:28 tilda + * Assignment of parent property. + * + * Revision 1.14 2002/10/08 21:11:36 tilda + * Remove common.h. + * + * Revision 1.13 2002/02/24 17:10:34 tilda + * Add API for "is modified" functionality. + * + * Revision 1.12 2001/12/13 06:45:35 tilda + * IID488021 - Various bugs with quoted printable format. + * + * Revision 1.11 2001/10/24 18:36:06 tilda + * BASE64 bugfixes. Split reader/writer code. Start create/modify work. + * + * Revision 1.10 2001/10/24 05:32:19 tilda + * BASE64 bugfixes - first part + * + * Revision 1.9 2001/10/14 20:42:37 tilda + * Addition of group searching. + * + * Revision 1.8 2001/10/14 19:53:36 tilda + * Group handling. NO group searching functions. + * + * Revision 1.7 2001/10/13 16:22:08 tilda + * Introduce VBINDATA_T and VOBJDATA_T to tidy up internals. + * + * Revision 1.6 2001/10/13 14:58:56 tilda + * Tidy up version headers, add vf_strings.h where needed. + * + * Revision 1.5 2001/10/13 14:49:30 tilda + * Add string array code to unify handling of names / values. + * + * Revision 1.4 2001/10/12 16:20:03 tilda + * Correctly parse compound quoted printable properties. + * + * Revision 1.3 2001/10/10 20:53:56 tilda + * Various minor tidy ups. + * + * Revision 1.2 2001/10/09 22:01:59 tilda + * Remove older version control comments. + * + *****************************************************************************/ + +#ifndef NORCSID +static const char vf_parser_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_parser.c,v 1.22 2002/11/16 13:19:10 tilda Exp $"; +#endif + +/*============================================================================* + ANSI C & System-wide Header Files + *===========================================================================*/ + +#include + +/*============================================================================* + Interface Header Files + *===========================================================================*/ + +#include "vformat/vf_iface.h" + +/*============================================================================* + Local Header File + *===========================================================================*/ + +#include "vf_config.h" +#include "vf_malloc.h" +#include "vf_internals.h" +#include "vf_strings.h" +#include "vf_string_arrays.h" + +/*============================================================================* + Public Data + *===========================================================================*/ +/* None */ + +/*============================================================================* + Private Defines + *===========================================================================*/ + +/* + * Significant characters. + */ +#define PERIOD '.' +#define COLON ':' +#define SEMICOLON ';' +#define LINEFEED '\n' +#define CRETURN '\r' +#define TAB '\t' +#define BACKSLASH '\\' +#define SPACE ' ' +#define EQUALS '=' +#define PERIOD '.' + +/* + * dec hex oct char + * 10 0x0A 012 LF NL, line feed, new line, \n + * 13 0x0D 015 CR carriage return, \r + * + * => = 0x0D 0x0A + */ + +/* + * States associated with propname:propvalue parsing. + */ +#define _VF_STATE_PROPNAME (1) /* reading name (including groupings) */ +#define _VF_STATE_PROPNAMEESCAPE (2) /* escaped semicolon in name */ +#define _VF_STATE_RFC822VALUE (3) /* basic */ +#define _VF_STATE_RFC822VALUEFOLD (4) /* waiting for line fold (simple fields) */ +#define _VF_STATE_QPIDLE (5) /* Non escaped position in QP */ +#define _VF_STATE_QPIDLENL (6) /* Non escaped position in QP */ +#define _VF_STATE_QPEQUALSC1 (7) /* After = in QP */ +#define _VF_STATE_QPEQUALSC2 (8) /* After =X in QP */ +#define _VF_STATE_BASE64 (9) /* Reading BASE64 */ + +#define ISCRORNL(c) ((CRETURN == (c)) || (LINEFEED == (c))) + +/*============================================================================* + Private Data Types + *===========================================================================*/ + +/*----------------------------------------------------------------------------* + * PURPOSE + * Maintains state variables etc. for current VOBJECT_T parsing. + *----------------------------------------------------------------------------*/ + +typedef struct +{ + int state; /* Main state variable */ + char qpchar; /* Workspace for QuotedPrintable decoder */ + char *p_b64buf; /* Workspace for BASE64 decoder */ + VOBJECT_T **pp_root_object; /* Pointer to the root */ + VOBJECT_T *p_object; /* Current position in tree */ + VPROP_T prop; /* Current property, copied into tree on completion */ +} +VPARSE_T; + +/*============================================================================* + Private Function Prototypes + *===========================================================================*/ + +static bool_t append_value_to_object( + VPROP_T **pp_prop, /* Pointer to the new property */ + VPARSE_T *p_parse /* The property we're naming */ + ); + +static bool_t handle_base64_chars( + VPARSE_T *p_parse, /* The property value we're adding to */ + const char *p_chars, /* Pointer to characters to add */ + int numchars /* Number of characters */ + ); + +static vf_encoding_t deduce_encoding( + VSTRARRAY_T *p_propname /* Property name */ + ); + +static uint8_t base64_to_char( + char c /* Character to convert */ + ); + +static bool_t is_hex_digit( + char *p_nibble, /* Output nibble value */ + char c /* Character read from file */ + ); + +static bool_t handle_value_complete( + VPARSE_T *p_parse /* Current parse state info */ + ); + +static bool_t alloc_next_object( + VPARSE_T *p_parse, /* Current parse state info */ + char *p_type /* Type of object */ + ); + +static bool_t alloc_sub_object( + VPARSE_T *p_parse, /* Current parse state info */ + char *p_type /* Type of object */ + ); + +static bool_t alloc_object( + VOBJECT_T **pp_new, /* Pointer to output pointer */ + VOBJECT_T *p_parent, /* Parent of new node */ + char *p_type, /* Type of new node */ + VPARSE_T *p_parse /* Current parse info */ + ); + +static bool_t append_group_name( + VPROP_T *p_prop /* Property we're updating */ + ); + + +/*============================================================================* + Private Data + *===========================================================================*/ +/* None */ + +/*============================================================================* + Public Function Implementations + *===========================================================================*/ + + + +/*----------------------------------------------------------------------------* + * NAME + * vf_parse_init() + * + * DESCRIPTION + * Initialise a parsing instance. + * + * RETURNS + * (none) + *---------------------------------------------------------------------------*/ + +bool_t vf_parse_init( + VF_PARSER_T **pp_parser, /* The parser */ + VF_OBJECT_T **pp_object /* The object we're parsing into */ + ) +{ + bool_t ret = FALSE; + + if (pp_parser && pp_object) + { + VPARSE_T *p_parse = (VPARSE_T *)vf_malloc(sizeof(VPARSE_T)); + + if (p_parse) + { + p_memset(p_parse, '\0', sizeof(VPARSE_T)); + + p_parse->state = _VF_STATE_PROPNAME; + p_parse->p_object = NULL; + p_parse->pp_root_object = (VOBJECT_T **)pp_object; + + *pp_parser = (VF_PARSER_T *)p_parse; + + *pp_object = NULL; + + ret = TRUE; + } + } + + return ret; +} + + + + + + +/*----------------------------------------------------------------------------* + * NAME + * vf_parse_text() + * + * DESCRIPTION + * Parse indicated text into the object associated with the VPARSE_T. + * + * RETURNS + * TRUE <=> allocation & syntax OK, FALSE else. + *---------------------------------------------------------------------------*/ + +bool_t vf_parse_text( + VF_PARSER_T *p_parser, /* The parser */ + char *p_chars, /* New characters to parse into object */ + int numchars /* Number of new characters */ + ) +{ + int i; + bool_t ok; + VPARSE_T *p_parse = (VPARSE_T *)p_parser; + + /* + * Check pointer. + */ + if (!p_parse) + { + return FALSE; + } + + /* + * Push each character through the state machine. + */ + for (i = 0, ok = TRUE;ok && (i < numchars);i++) + { + char c = p_chars[i]; + + switch (p_parse->state) + { + case _VF_STATE_RFC822VALUEFOLD: + { + if (ISCRORNL(c)) + { + /* Ignore */ + } + else + if (SPACE == c) + { + ok = append_to_curr_string(&(p_parse->prop.value.v.s), NULL, &c, 1); + + p_parse->state = _VF_STATE_RFC822VALUE; + } + else + { + ok = handle_value_complete(p_parse); + + p_parse->state = _VF_STATE_PROPNAME; + } + } + if (_VF_STATE_PROPNAME == p_parse->state) + { + /* Fall through */ + } + else + { + break; + } + + /* Fall through */ + + + case _VF_STATE_PROPNAME: + { + if (COLON == c) + { + p_parse->prop.value.encoding = deduce_encoding(&p_parse->prop.name); + + switch (p_parse->prop.value.encoding) + { + case VF_ENC_7BIT: + p_parse->state = _VF_STATE_RFC822VALUE; + break; + + case VF_ENC_BASE64: + p_parse->state = _VF_STATE_BASE64; + break; + + case VF_ENC_QUOTEDPRINTABLE: + p_parse->state = _VF_STATE_QPIDLE; + break; + + default: + ok = FALSE; + break; + } + } + else + if (BACKSLASH == c) + { + p_parse->state = _VF_STATE_PROPNAMEESCAPE; + } + else + if (ISCRORNL(c)) + { + /* ignore */ + + free_string_array_contents(&p_parse->prop.name); + } + else + if (SEMICOLON == c) + { + ok = add_string_to_array(&p_parse->prop.name, ""); + } + else + if (PERIOD == c) + { + ok = append_group_name(&p_parse->prop); + } + else + { + ok = append_to_curr_string(&(p_parse->prop.name), NULL, &c, 1); + } + } + break; + + case _VF_STATE_PROPNAMEESCAPE: + { + if (SEMICOLON == c) + { + ok = append_to_curr_string(&(p_parse->prop.name), NULL, &c, 1); + } + else + { + ok = FALSE; + } + } + break; + + case _VF_STATE_RFC822VALUE: + { + if (p_parse->prop.value.v.s.pp_strings) + { + /* Already allocated */ + } + else + { + ok = add_string_to_array(&(p_parse->prop.value.v.s), NULL); + } + + if (ISCRORNL(c)) + { + p_parse->state = _VF_STATE_RFC822VALUEFOLD; + } + else + if (SEMICOLON == c) + { + ok = add_string_to_array(&(p_parse->prop.value.v.s), NULL); + } + else + { + ok = append_to_curr_string(&(p_parse->prop.value.v.s), NULL, &c, 1); + } + } + break; + + case _VF_STATE_QPIDLENL: + { + if (ISCRORNL(c)) + { + break; + } + else + { + p_parse->state = _VF_STATE_QPIDLE; + } + } + + case _VF_STATE_QPIDLE: + { + if (p_parse->prop.value.v.s.pp_strings) + { + /* Already allocated */ + } + else + { + ok = add_string_to_array(&(p_parse->prop.value.v.s), NULL); + } + + if (EQUALS == c) + { + p_parse->qpchar = 0x00; + p_parse->state = _VF_STATE_QPEQUALSC1; + } + else + if (SEMICOLON == c) + { + ok = add_string_to_array(&(p_parse->prop.value.v.s), NULL); + } + else + if (ISCRORNL(c)) + { + ok = handle_value_complete(p_parse); + } + else + { + ok = append_to_curr_string(&(p_parse->prop.value.v.s), NULL, &c, 1); + } + } + break; + + case _VF_STATE_QPEQUALSC1: + { + uint8_t nibble; + + if (ISCRORNL(c)) + { + p_parse->state = _VF_STATE_QPIDLENL; + } + else + if (is_hex_digit(&nibble, c)) + { + (p_parse->qpchar) <<= 4; + (p_parse->qpchar) |= nibble; + + p_parse->state = _VF_STATE_QPEQUALSC2; + } + else + { + ok = FALSE; + } + } + break; + + case _VF_STATE_QPEQUALSC2: + { + uint8_t nibble; + + if (is_hex_digit(&nibble, c)) + { + (p_parse->qpchar) <<= 4; + (p_parse->qpchar) |= nibble; + + ok = append_to_curr_string(&(p_parse->prop.value.v.s), NULL, &(p_parse->qpchar), 1); + + p_parse->state = _VF_STATE_QPIDLE; + } + else + { + ok = FALSE; + } + } + break; + + case _VF_STATE_BASE64: + { + /* + * The cr/nl stuff associated with line ends & termination of BASE64 encoding + * seems to be particularly problematic. Searching and reading vCards from the + * internet shows that all sorts of wierd things are out there in use! In the + * interests of interoperability we look for the next value as an indication of + * the end of the object. We build up each line and if it's still in BASE64 + * format append the decoded data. Otherwise we use the parser recursively to + * decode the buffered text, which is probably something like "NEXT-VALUE:" + */ + + if (ISCRORNL(c)) + { + if (p_parse->p_b64buf) + { + ok = handle_base64_chars(p_parse, p_parse->p_b64buf, p_strlen(p_parse->p_b64buf)); + + vf_free(p_parse->p_b64buf); + p_parse->p_b64buf = NULL; + } + } + else + { + ok = append_to_pointer(&(p_parse->p_b64buf), NULL, &c, 1); + + if ((COLON == c) || (SEMICOLON == c)) + { + ok = handle_value_complete(p_parse); + + ok = vf_parse_text(p_parser, p_parse->p_b64buf, p_strlen(p_parse->p_b64buf)); + + vf_free(p_parse->p_b64buf); + p_parse->p_b64buf = NULL; + } + } + } + break; + } + } + + if (ok) + { + /* no need to panic */ + } + else + { + vf_delete_object((VF_OBJECT_T *)*(p_parse->pp_root_object), TRUE); + *(p_parse->pp_root_object) = NULL; + p_parse->p_object = NULL; + + if (p_parse->p_b64buf) + { + vf_free(p_parse->p_b64buf); + p_parse->p_b64buf = NULL; + } + + delete_prop_contents((VF_PROP_T *)&p_parse->prop, TRUE); + } + + return ok; +} + + + + + + +/*----------------------------------------------------------------------------* + * NAME + * vf_parse_end() + * + * DESCRIPTION + * Ensure parse completion. + * + * RETURNS + * TRUE <=> allocation & syntax OK, FALSE else. + *---------------------------------------------------------------------------*/ + +bool_t vf_parse_end( + VF_PARSER_T *p_parser /* The parser */ + ) +{ + bool_t ret = FALSE; + VPARSE_T *p_parse = (VPARSE_T *)p_parser; + + /* + * Check pointer. + */ + if (p_parse) + { + ret = handle_value_complete(p_parse); + + vf_free(p_parse); + } + + return ret; +} + + + + +/*============================================================================* + Private Functions + *===========================================================================*/ + + +/*----------------------------------------------------------------------------* + * NAME + * append_group_name() + * + * DESCRIPTION + * After reading a ".", we transfer the segment of name we've read (which + * must be the first string ) into the group name. Keep the group name + * in one string of "." tokens for simplicity, so we may end up with a + * group called "X-PHONE-BOOK.ENTRY.1" etc. + * + * RETURNS + * TRUE <=> allocation OK. + *---------------------------------------------------------------------------*/ + +bool_t append_group_name( + VPROP_T *p_prop + ) +{ + bool_t ok = TRUE; + + if (p_prop->p_group) + { + ok &= append_to_pointer(&p_prop->p_group, NULL, ".", 1); + } + + if (ok) + { + const char *p_string = p_prop->name.pp_strings[0]; + + ok &= append_to_pointer(&p_prop->p_group, NULL, p_string, p_strlen(p_string)); + + if (ok) + { + vf_free(p_prop->name.pp_strings[0]); + p_prop->name.pp_strings[0] = NULL; + } + } + + return ok; +} + + + + + +/*----------------------------------------------------------------------------* + * NAME + * handle_value_complete() + * + * DESCRIPTION + * Called when a complete value is parsed. + * + * RETURNS + * (none). + *---------------------------------------------------------------------------*/ + +bool_t handle_value_complete( + VPARSE_T *p_parse /* Current parse state info */ + ) +{ + bool_t ret = TRUE; + VOBJECT_T *p_object; + + /* + * If we've got no object open we ignore values until we read a BEGIN at which point + * we create a vformat object and start to parse properties into it. If we subsequently + * read a BEGIN we add a property & parse the next vobject into that. Each time we read + * an END we pop the pp_object pointer back up to the owner of the object we're parsing + * into. There should be an easier way of doing this ... + */ + + p_object = p_parse->p_object; + + if (p_object) + { + if (string_array_contains_string(&p_parse->prop.name, NULL, 0, VFP_BEGIN, TRUE)) + { + char *p_type; + + p_type = p_parse->prop.value.v.s.pp_strings[0]; + p_parse->prop.value.v.s.pp_strings[0] = NULL; + + delete_prop_contents((VF_PROP_T *)(&(p_parse->prop)), TRUE); + + p_parse->prop.value.encoding = VF_ENC_VOBJECT; + + ret = add_string_to_array(&(p_parse->prop.name), p_type) && + alloc_sub_object(p_parse, p_type); + } + else + if (string_array_contains_string(&p_parse->prop.name, NULL, 0, VFP_END, TRUE)) + { + delete_prop_contents((VF_PROP_T *)(&(p_parse->prop)), TRUE); + + p_parse->p_object = p_parse->p_object->p_parent; + } + else + { + ret = append_value_to_object(NULL, p_parse); + } + } + else + { + if (string_array_contains_string(&p_parse->prop.name, NULL, 0, VFP_BEGIN, TRUE)) + { + char *p_type; + + p_type = p_parse->prop.value.v.s.pp_strings[0]; + p_parse->prop.value.v.s.pp_strings[0] = NULL; + + ret = alloc_next_object(p_parse, p_type); + } + + delete_prop_contents((VF_PROP_T *)(&(p_parse->prop)), TRUE); + } + + p_parse->state = _VF_STATE_PROPNAME; + + return ret; +} + + + + + + +/*----------------------------------------------------------------------------* + * NAME + * alloc_next_object() + * + * DESCRIPTION + * Allocate the "next" object, ie. annother vformat tagged to the p_next + * pointer to the current one. + * + * RETURNS + * TRUE iff memory allocated OK, FALSE else OK. + *---------------------------------------------------------------------------*/ + +bool_t alloc_next_object( + VPARSE_T *p_parse, /* Current parse state info */ + char *p_type /* Type of object */ + ) +{ + bool_t ok = TRUE; + VOBJECT_T *p_parent = p_parse->p_object; + VOBJECT_T *p_new = NULL; + + ok = alloc_object(&p_new, p_parent ? p_parent->p_parent : NULL, p_type, p_parse); + + if (ok) + { + if (*p_parse->pp_root_object) + { + /* root object already set */ + + if (p_new->p_parent) + { + /* Owned by property */ + } + else + { + /* Need to tag to end of top list */ + + VOBJECT_T **pp_tmp = p_parse->pp_root_object; + + while (*pp_tmp) + { + pp_tmp = &((*pp_tmp)->p_next); + } + + *pp_tmp = p_new; + } + } + else + { + *p_parse->pp_root_object = p_new; + } + } + + return ok; +} + + + + + + + +/*----------------------------------------------------------------------------* + * NAME + * alloc_sub_object() + * + * DESCRIPTION + * Allocate "sub" object, ie. annother vformat tagged to the p_object + * pointer of a VPROP_T allocated to contain it. + * + * RETURNS + * TRUE iff memory allocated OK, FALSE else OK. + *---------------------------------------------------------------------------*/ + +bool_t alloc_sub_object( + VPARSE_T *p_parse, /* Current parse state info */ + char *p_type /* Type of object */ + ) +{ + bool_t ok = FALSE; + VOBJECT_T *p_parent = p_parse->p_object; + + if (p_parent) + { + VPROP_T *p_tmp; + + ok = append_value_to_object(&p_tmp, p_parse); + + if (ok && p_tmp) + { + ok = alloc_object(&p_tmp->value.v.o.p_object, p_parent, p_type, p_parse); + } + } + + return ok; +} + + + + + + +/*----------------------------------------------------------------------------* + * NAME + * alloc_object() + * + * DESCRIPTION + * Allocate & initialise a new VOBJECT_T. The new element od made the + * current parse target (ie. new properties will be added to it). + * + * RETURNS + * TRUE <=> allocation went OK, FALSE else. + *---------------------------------------------------------------------------*/ + +bool_t alloc_object( + VOBJECT_T **pp_new, /* Pointer to output pointer */ + VOBJECT_T *p_parent, /* Parent of new node */ + char *p_type, /* Type of new node */ + VPARSE_T *p_parse /* Current parse info */ + ) +{ + bool_t ok = TRUE; + VOBJECT_T *p_new; + + p_new = (VOBJECT_T *)vf_malloc(sizeof(VOBJECT_T)); + + if (p_new) + { + p_memset(p_new, '\0', sizeof(VOBJECT_T)); + + p_new->p_parent = p_parent; + p_new->p_type = p_type; + + p_parse->p_object = p_new; + + *pp_new = p_new; + } + else + { + ok = FALSE; + } + + return ok; +} + + + + + + + +/*----------------------------------------------------------------------------* + * NAME + * handle_base64_chars() + * + * DESCRIPTION + * Handle BASE64 decoding. + * + * RETURNS + * TRUE <=> allocation OK, FALSE else. + *---------------------------------------------------------------------------*/ + +bool_t handle_base64_chars( + VPARSE_T *p_parse, /* The property value we're adding to */ + const char *p_chars, /* Pointer to characters to add */ + int numchars /* Number of characters */ + ) +{ + bool_t ok = TRUE; + + /* + * Skip spaces. + */ + while ((0 < numchars) && (SPACE == p_chars[0])) + { + numchars--; + p_chars++; + } + + /* + * Convert groups of 4 characters to byte triplets & append the bytes + * to the binary data. + */ + if (0 < numchars) + { + int i, j, len, num, left; + const char *p_quad; + + len = numchars; + num = len / 4; + left = len % 4; + + for (i = 0, p_quad = p_chars;(i < num);i++, p_quad += 4) + { + uint32_t b; + char bytes[3]; + uint8_t bits; + + for (j = 0, b = 0, bits = 0;(j < 4);j++) + { + b = (b << 6) | base64_to_char(p_quad[j]); + + if (EQUALS != p_quad[j]) + { + bits += 6; + } + } + + for (j = 0;(j < 3);j++) + { + bytes[2 - j] = (unsigned char)(b & 0xFF); + + b >>= 8; + } + + ok = append_to_pointer(&(p_parse->prop.value.v.b.p_buffer), &(p_parse->prop.value.v.b.n_bufsize), bytes, bits / 8); + } + } + + return ok; +} + + + + + + +/*----------------------------------------------------------------------------* + * NAME + * append_value_to_object() + * + * DESCRIPTION + * Append characters to the name half of a VOBJECT_T. The VOBJECT is + * allocated if not already present. + * + * RETURNS + * TRUE <=> allocation OK, FALSE else. + *---------------------------------------------------------------------------*/ + +bool_t append_value_to_object( + VPROP_T **pp_prop, /* Pointer to the new property */ + VPARSE_T *p_parse /* The property we're naming */ + ) +{ + bool_t ok = FALSE; + + VPROP_T **pp_tmp; + VPROP_T *p_prop; + + pp_tmp = &(p_parse->p_object->p_props); + + while (*pp_tmp) + { + pp_tmp = &((*pp_tmp)->p_next); + } + + *pp_tmp = p_prop = (VPROP_T *)vf_malloc(sizeof(VPROP_T)); + + if (pp_prop) + { + *pp_prop = p_prop; + } + + if (p_prop) + { + p_memset(p_prop, '\0', sizeof(VPROP_T)); + + *p_prop = p_parse->prop; + + p_memset(&(p_parse->prop), '\0', sizeof(VPROP_T)); + + p_prop->p_parent = p_parse->p_object; + + ok = TRUE; + } + + return ok; +} + + + + + + + +/*----------------------------------------------------------------------------* + * NAME + * deduce_encoding() + * + * DESCRIPTION + * Check property name for encoding tags. If none present, return the + * default encoding. + * + * RETURNS + * vf_encoding_t. + *---------------------------------------------------------------------------*/ + +vf_encoding_t deduce_encoding( + VSTRARRAY_T *p_propname /* Property name */ + ) +{ + vf_encoding_t ret = VF_ENC_7BIT; + + if (string_array_contains_string(p_propname, NULL, -1, VFP_QUOTEDPRINTABLE, FALSE)) + { + ret = VF_ENC_QUOTEDPRINTABLE; + } + else + if (string_array_contains_string(p_propname, NULL, -1, VFP_BASE64, FALSE)) + { + ret = VF_ENC_BASE64; + } + else + if (string_array_contains_string(p_propname, NULL, -1, VFP_8BIT, FALSE)) + { + ret = VF_ENC_8BIT; + } + + return ret; +} + + + + + + + +/*----------------------------------------------------------------------------* + * NAME + * is_hex_digit() + * + * DESCRIPTION + * + * + * RETURNS + * TRUE <=> valid HEX digit read. + *---------------------------------------------------------------------------*/ + +bool_t is_hex_digit( + char *p_nibble, /* Output nibble value */ + char c /* Character read from file */ + ) +{ + bool_t ret = TRUE; + + if (('A' <= c) && (c <= 'F')) + { + *p_nibble = c - 'A' + 10; + } + else + if (('a' <= c) && (c <= 'f')) + { + *p_nibble = c - 'a' + 10; + } + else + if (('0' <= c) && (c <= '9')) + { + *p_nibble = c - '0'; + } + else + { + ret = FALSE; + } + + return ret; +} + + + + + +/*----------------------------------------------------------------------------* + * NAME + * base64_to_char() + * + * DESCRIPTION + * Convert base 64 char to byte. + * + * RETURNS + * Number corresponding to char. + *---------------------------------------------------------------------------*/ + +uint8_t base64_to_char(char c) +{ + if (('A' <= c) && (c <= 'Z')) + return c - 'A'; + + if (('a' <= c) && (c <= 'z')) + return c - 'a' + 26; + + if (('0' <= c) && (c <= '9')) + return c - '0' + 52; + + if ('+' == c) + return 62; + + if ('/' == c) + return 63; + + return 0x00; +} + + +/*============================================================================* + End Of File + *===========================================================================*/ -- cgit v1.1-32-gdbae