Skip to content

Commit

Permalink
Added support for escaping control chars in strings
Browse files Browse the repository at this point in the history
Initial fix for issue #42
  • Loading branch information
jmcnamara committed Dec 20, 2015
1 parent 71c7d5f commit 05af1bd
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 6 deletions.
2 changes: 2 additions & 0 deletions include/xlsxwriter/xmlwriter.h
Expand Up @@ -162,6 +162,8 @@ void _xml_data_element(FILE * xmlfile,
const char *data,
struct xml_attribute_list *attributes);

char *_escape_control_characters(const char *string);

/* *INDENT-OFF* */
#ifdef __cplusplus
}
Expand Down
13 changes: 13 additions & 0 deletions src/shared_strings.c
Expand Up @@ -138,12 +138,25 @@ _write_t(lxw_sst *self, char *string)
void
_write_si(lxw_sst *self, char *string)
{
uint8_t escaped_string = LXW_FALSE;

_xml_start_tag(self->file, "si", NULL);

/* Look for and escape control chars in the string. */
if (strpbrk(string, "\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C"
"\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16"
"\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F")) {
string = _escape_control_characters(string);
escaped_string = LXW_TRUE;
}

/* Write the t element. */
_write_t(self, string);

_xml_end_tag(self->file, "si");

if (escaped_string)
free(string);
}

/*
Expand Down
69 changes: 63 additions & 6 deletions src/xmlwriter.c
Expand Up @@ -96,7 +96,7 @@ _xml_empty_tag(FILE * xmlfile,

/*
* Write an XML start tag with optional, unencoded, attributes.
* This is a minor speed optimisation for elements that don't need encoding.
* This is a minor speed optimization for elements that don't need encoding.
*/
void
_xml_empty_tag_unencoded(FILE * xmlfile,
Expand Down Expand Up @@ -212,7 +212,64 @@ _escape_data(const char *data)
return encoded;
}

/* TODO */
/*
* Escape control characters in strings with with _xHHHH_.
*/
char *
_escape_control_characters(const char *string)
{
size_t escape_len = sizeof("_xHHHH_") - 1;
size_t encoded_len = (strlen(string) * escape_len + 1);

char *encoded = (char *) calloc(encoded_len, 1);
char *p_encoded = encoded;

while (*string) {
switch (*string) {
case '\x01':
case '\x02':
case '\x03':
case '\x04':
case '\x05':
case '\x06':
case '\x07':
case '\x08':
case '\x0B':
case '\x0C':
case '\x0D':
case '\x0E':
case '\x0F':
case '\x10':
case '\x11':
case '\x12':
case '\x13':
case '\x14':
case '\x15':
case '\x16':
case '\x17':
case '\x18':
case '\x19':
case '\x1A':
case '\x1B':
case '\x1C':
case '\x1D':
case '\x1E':
case '\x1F':
lxw_snprintf(p_encoded, escape_len + 1, "_x%04X_", *string);
p_encoded += escape_len;
break;
default:
*p_encoded = *string;
p_encoded++;
break;
}
string++;
}

return encoded;
}

/* Write out escaped attributes. */
void
_fprint_escaped_attributes(FILE * xmlfile,
struct xml_attribute_list *attributes)
Expand All @@ -239,7 +296,7 @@ _fprint_escaped_attributes(FILE * xmlfile,
}
}

/* TODO */
/* Write out escaped XML data. */
void
_fprint_escaped_data(FILE * xmlfile, const char *data)
{
Expand All @@ -256,7 +313,7 @@ _fprint_escaped_data(FILE * xmlfile, const char *data)
}
}

/* TODO */
/* Create a new string XML attribute. */
struct xml_attribute *
_new_attribute_str(const char *key, const char *value)
{
Expand All @@ -268,7 +325,7 @@ _new_attribute_str(const char *key, const char *value)
return attribute;
}

/* TODO */
/* Create a new integer XML attribute. */
struct xml_attribute *
_new_attribute_int(const char *key, uint32_t value)
{
Expand All @@ -280,7 +337,7 @@ _new_attribute_int(const char *key, uint32_t value)
return attribute;
}

/* TODO */
/* Create a new double XML attribute. */
struct xml_attribute *
_new_attribute_dbl(const char *key, double value)
{
Expand Down
28 changes: 28 additions & 0 deletions test/functional/src/test_shared_strings01.c
@@ -0,0 +1,28 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2015, John McNamara, jmcnamara@cpan.org
*
*/

#include "xlsxwriter.h"

int main() {

lxw_workbook *workbook = new_workbook("test_shared_strings01.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
uint8_t i;
char c[] = {0x00, 0x00};

for (i = 1; i < 127; i++) {
(*c)++;
if (i != 34) {
worksheet_write_string(worksheet, i, 0, c, NULL);

}
}

return workbook_close(workbook);
}
3 changes: 3 additions & 0 deletions test/functional/test_misc.py
Expand Up @@ -23,3 +23,6 @@ def test_firstsheet01(self):

def test_hide01(self):
self.run_exe_test('test_hide01')

def test_shared_strings01(self):
self.run_exe_test('test_shared_strings01')
Binary file added test/functional/xlsx_files/shared_strings01.xlsx
Binary file not shown.

0 comments on commit 05af1bd

Please sign in to comment.