/****************************************************************************** (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$ $Revision: 1.12 $ $Author: tilda $ ORIGINAL AUTHOR Nick Marley. DESCRIPTION Code for writing vformat files. This is temporary as it is not based around a state machine for converting the object to a character stream. REFERENCES (none) MODIFICATION HISTORY * $Log: vf_writer.c,v $ * Revision 1.12 2002/11/03 18:43:16 tilda * IID619851 - Update and check headers and function prototypes. * * Revision 1.11 2002/11/02 08:56:17 tilda * Start of internationalisation changes. * * Revision 1.10 2002/10/26 16:09:23 tilda * IID629125 - Ensure string functions used are portable. * * Revision 1.9 2002/10/08 21:45:07 tilda * IID620473 - reduce c-runtime dependencies. * * Revision 1.8 2002/10/08 21:11:35 tilda * Remove common.h. * * Revision 1.7 2002/02/24 17:10:34 tilda * Add API for "is modified" functionality. * * Revision 1.6 2001/12/13 06:45:35 tilda * IID488021 - Various bugs with quoted printable format. * * Revision 1.5 2001/11/18 21:45:10 tilda * Add newline after BASE64 encodings * * Revision 1.4 2001/11/14 22:36:55 tilda * Add parameter to vf_find_prop_qual_index() * * Revision 1.3 2001/11/06 22:51:05 tilda * Supporting access functions for image selection / deletion. * * Revision 1.2 2001/10/24 18:56:29 tilda * Tidy headers after import. Fix include path in release build. * * Revision 1.1 2001/10/24 18:34:35 tilda * Initial Version. * *******************************************************************************/ #ifndef NORCSID static const char vf_writer_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_writer.c,v 1.12 2002/11/03 18:43:16 tilda Exp $"; #endif /*=============================================================================* ANSI C & System-wide Header Files *=============================================================================*/ #include #include /*============================================================================* Interface Header Files *============================================================================*/ #include /*============================================================================* Local Header File *============================================================================*/ #include "vf_config.h" #include "vf_internals.h" #include "vf_malloc.h" #include "vf_strings.h" /*============================================================================* Public Data *============================================================================*/ /* None */ /*============================================================================* Private Defines *============================================================================*/ #define QPMAXPERLINE (76) #define BASE64PERLINE (64) /*============================================================================* Private Data Types *============================================================================*/ /* None */ /*============================================================================* Private Function Prototypes *============================================================================*/ static bool_t write_name_fields( FILE *fp, uint32_t *p_charsonline, VPROP_T *p_prop ); static void write_base64_chars( FILE *fp, /* File we're writing */ uint8_t *s, /* Pointer to buffer */ uint32_t len /* buffer length */ ); static bool_t write_quoted_printable( FILE *fp, /* File we're writing */ uint8_t *s, /* Pointer to buffer */ uint32_t *p_charsonline /* Num on line so far */ ); static char char_to_base64( uint8_t b /* Byte to convert */ ); static bool_t qp_needs_quoting( uint8_t c /* Char to test */ ); static bool_t write_vobject_to_file( FILE *fp, VOBJECT_T *p_object, bool_t write_all ); /*============================================================================* Private Data *============================================================================*/ static const char szEndOfLine[] = "\r\n"; /*============================================================================* Public Function Implementations *============================================================================*/ /*----------------------------------------------------------------------------* * NAME * vf_write_file() * * DESCRIPTION * Write indicated vobject to file. * * RETURNS * TRUE <=> written OK, FALSE else. *----------------------------------------------------------------------------*/ bool_t vf_write_file( const char *p_name, /* Outpt filename */ VF_OBJECT_T *p_object, /* The object to write */ bool_t write_all /* Should write p_next as well? */ ) { FILE *fp; bool_t ret = FALSE; fp = fopen(p_name, "wb"); if (fp) { ret = write_vobject_to_file(fp, (VOBJECT_T *)p_object, write_all); if (0 == fclose(fp)) { /* as is */ } else { ret = FALSE; } } return ret; } /*============================================================================* Private Function Implementations *============================================================================*/ /*----------------------------------------------------------------------------* * NAME * write_vobject_to_file() * * DESCRIPTION * Write each field of the indicated vformat object to the indicated FILE* * invoking write_vobject_to_file() recursively if a field is found which * contains a vformat object. * * RETURNS * TRUE <=> file acces OK, FALSE else. *----------------------------------------------------------------------------*/ bool_t write_vobject_to_file( FILE *fp, VOBJECT_T *p_object, bool_t write_all ) { bool_t ret = TRUE; VOBJECT_T *p_obj = (VOBJECT_T *)p_object; VPROP_T *p_props = p_obj->p_props; fprintf(fp, "%s:%s", VFP_BEGIN, p_obj->p_type); fprintf(fp, szEndOfLine); for (;NULL != p_props;p_props = p_props->p_next) { uint32_t charsonline; switch (p_props->value.encoding) { default: case VF_ENC_7BIT: { ret = write_name_fields(fp, &charsonline, p_props); if (ret) { uint32_t n; for (n = 0;ret && (n < p_props->value.v.s.n_strings);n++) { if (n) fprintf(fp, ";"); if (p_props->value.v.s.pp_strings[n]) { fprintf(fp, "%s", p_props->value.v.s.pp_strings[n]); } } } } break; case VF_ENC_BASE64: { ret = write_name_fields(fp, &charsonline, p_props); if (ret) { write_base64_chars(fp, p_props->value.v.b.p_buffer, p_props->value.v.b.n_bufsize); } } break; case VF_ENC_QUOTEDPRINTABLE: { ret = write_name_fields(fp, &charsonline, p_props); if (ret) { uint32_t n; for (n = 0;ret && (n < p_props->value.v.s.n_strings);n++) { if (n) fprintf(fp, ";"); if (p_props->value.v.s.pp_strings[n]) { ret = write_quoted_printable(fp, p_props->value.v.s.pp_strings[n], &charsonline); } } } } break; case VF_ENC_VOBJECT: { write_vobject_to_file(fp, p_props->value.v.o.p_object, TRUE); } break; } if (VF_ENC_VOBJECT != p_props->value.encoding) fprintf(fp, szEndOfLine); } fprintf(fp, "%s:%s", VFP_END, p_obj->p_type); fprintf(fp, szEndOfLine); if (ret && p_obj->p_next && write_all) { ret = write_vobject_to_file(fp, p_obj->p_next, TRUE); } p_obj->modified = !ret; return ret; } /*----------------------------------------------------------------------------* * NAME * write_base64_chars() * * DESCRIPTION * Write the indicated binary data stream out to FILE* using BASE64 * encoding. * * RETURNS * (none) *----------------------------------------------------------------------------*/ static void write_base64_chars( FILE *fp, /* File we're writing */ uint8_t *p_buffer, /* Pointer to buffer */ uint32_t n_chars /* buffer length */ ) { uint32_t posn; char quad[5]; uint8_t b; quad[4] = 0; for (posn = 0;posn < n_chars;) { int i; uint32_t triplet = 0; uint8_t bits = 0; /* Form triplet from data if available */ for (i = 0;i < 3;i++, posn++) { triplet = triplet << 8; if (posn < n_chars) { triplet |= *(p_buffer + posn); bits += 8; } } /* Convert the triplet to text */ for (i = 0;i < 4;i++) { b = (uint8_t)((0xFC0000 & triplet) >> 18); triplet = triplet << 6; quad[i] = (i <= (bits/6)) ? char_to_base64(b) : '='; } /* Output the text prefixed by newlines if necessary */ if (((posn - 3) % (BASE64PERLINE / 4)) == 0) { fprintf(fp, szEndOfLine); fprintf(fp, " "); } fprintf(fp, "%s", quad); } fprintf(fp, szEndOfLine); } /*----------------------------------------------------------------------------* * NAME * write_quoted_printable() * * DESCRIPTION * Write the indicated field back to the file in quoted printable format. * * RETURNS * (none) *----------------------------------------------------------------------------*/ static bool_t write_quoted_printable( FILE *fp, /* File we're writing */ uint8_t *s, /* Pointer to buffer */ uint32_t *p_charsonline /* Num on line so far */ ) { uint32_t i; uint32_t charsonline = *p_charsonline; for (i = 0;s;i++) { uint8_t c = s[i]; if ('\0' == c) { break; } else { if (3 + charsonline > QPMAXPERLINE) { fprintf(fp, "="); fprintf(fp, szEndOfLine); charsonline = 0; } if (qp_needs_quoting(c)) { fprintf(fp, "=%02X", c); charsonline += 3; if (0x0D == c) { fprintf(fp, "="); fprintf(fp, szEndOfLine); charsonline = 0; } } else { fprintf(fp, "%c", c); charsonline += 1; } } } *p_charsonline = charsonline; return TRUE; } /*----------------------------------------------------------------------------* * NAME * char_to_base64() * * DESCRIPTION * Converts byte to BASE64. * * RETURNS * Character encoded. *----------------------------------------------------------------------------*/ static char char_to_base64( uint8_t b /* Byte to convert */ ) { char ret; if (b < 26) { ret = (char)b + 'A'; } else if (b < 52) { ret = (char)(b - 26) + 'a'; } else if (b < 62) { ret = (char)(b - 52) + '0'; } else if (b == 62) { ret = '+'; } else { ret = '/'; } return ret; } /*----------------------------------------------------------------------------* * NAME * qp_needs_quoting() * * DESCRIPTION * Works out of 'c' needs quoting in quoted printable format. * * RETURNS * TRUE <=> need to quote. *----------------------------------------------------------------------------*/ static bool_t qp_needs_quoting( uint8_t c /* Char to test */ ) { /* TBD - look in the RFC?! */ bool_t needs_quoting = FALSE; switch (c) { case ' ': case ',': case '-': case '.': case '!': case '?': case '\'': return FALSE; default: if (isalnum(c)) needs_quoting = FALSE; else needs_quoting = TRUE; break; } return needs_quoting; } /*----------------------------------------------------------------------------* * NAME * write_name_fields() * * DESCRIPTION * Write name fields to file. * * RETURNS * TRUE <=> OK so far. *----------------------------------------------------------------------------*/ bool_t write_name_fields( FILE *fp, uint32_t *p_charsonline, VPROP_T *p_prop ) { VSTRARRAY_T *p_strarray = &(p_prop->name); bool_t ret = FALSE; *p_charsonline = 0; if (p_prop->p_group) { *p_charsonline += fprintf(fp, "%s.", p_prop->p_group); } if (p_strarray->pp_strings) { uint32_t i; for (i = 0;i < p_strarray->n_strings;i++) { char *p_name_field = p_strarray->pp_strings[i]; if (p_name_field && (0 < p_strlen(p_name_field))) { if (0 < i) { fprintf(fp, ";"); *p_charsonline += 1; } *p_charsonline += fprintf(fp, "%s", p_name_field); } } fprintf(fp, ":"); *p_charsonline += 1; ret = TRUE; } return ret; } /*============================================================================* End Of File *============================================================================*/