1
1
#include "xlsxio_private.h"
2
2
#include "xlsxio_read_sharedstrings.h"
3
+ #include "xlsxio_read_cellstyles.h"
3
4
#include "xlsxio_read.h"
4
5
#include "xlsxio_version.h"
5
6
#include <stdlib.h>
@@ -181,7 +182,7 @@ int expat_process_zip_file (ZIPFILETYPE* zip, const XML_Char* filename, XML_Star
181
182
#endif
182
183
//return (status == XML_STATUS_ERROR != XML_ERROR_FINISHED ? 1 : 0);
183
184
return 0 ;
184
- }
185
+ }
185
186
186
187
XML_Parser expat_process_zip_file_suspendable (ZIPFILEENTRYTYPE * zipfile , XML_StartElementHandler start_handler , XML_EndElementHandler end_handler , XML_CharacterDataHandler data_handler , void * callbackdata )
187
188
{
@@ -246,7 +247,7 @@ int XML_Char_icmp_ins (const XML_Char* value, const XML_Char* name)
246
247
return -1 ;
247
248
}
248
249
#endif
249
-
250
+
250
251
//get expat attribute by name, returns NULL if not found
251
252
const XML_Char * get_expat_attr_by_name (const XML_Char * * atts , const XML_Char * name )
252
253
{
@@ -378,8 +379,8 @@ voidpf ZCALLBACK minizip_io_filehandle_open_file_fn (voidpf opaque, const char*
378
379
return NULL ;
379
380
return & ((struct minizip_io_filehandle_data * )opaque )-> filehandle ;
380
381
}
381
-
382
- uLong ZCALLBACK minizip_io_filehandle_read_file_fn (voidpf opaque , voidpf stream , void * buf , uLong size )
382
+
383
+ uLong ZCALLBACK minizip_io_filehandle_read_file_fn (voidpf opaque , voidpf stream , void * buf , uLong size )
383
384
{
384
385
IOSIZETYPE len ;
385
386
if (!opaque || !stream || !buf || size == 0 )
@@ -389,32 +390,32 @@ uLong ZCALLBACK minizip_io_filehandle_read_file_fn (voidpf opaque, voidpf stream
389
390
return len ;
390
391
}
391
392
392
- /*
393
- uLong ZCALLBACK minizip_io_filehandle_write_file_fn (voidpf opaque, voidpf stream, const void* buf, uLong size)
393
+ /*
394
+ uLong ZCALLBACK minizip_io_filehandle_write_file_fn (voidpf opaque, voidpf stream, const void* buf, uLong size)
394
395
{
395
396
return 0;
396
397
}
397
398
*/
398
-
399
- int ZCALLBACK minizip_io_filehandle_close_file_fn (voidpf opaque , voidpf stream )
399
+
400
+ int ZCALLBACK minizip_io_filehandle_close_file_fn (voidpf opaque , voidpf stream )
400
401
{
401
402
if (stream )
402
403
close (* (int * )stream );
403
404
free (opaque );
404
405
return 0 ;
405
406
}
406
-
407
- int ZCALLBACK minizip_io_filehandle_testerror_file_fn (voidpf opaque , voidpf stream )
407
+
408
+ int ZCALLBACK minizip_io_filehandle_testerror_file_fn (voidpf opaque , voidpf stream )
408
409
{
409
410
return 0 ;
410
411
}
411
-
412
- long ZCALLBACK minizip_io_filehandle_tell_file_fn (voidpf opaque , voidpf stream )
412
+
413
+ long ZCALLBACK minizip_io_filehandle_tell_file_fn (voidpf opaque , voidpf stream )
413
414
{
414
415
return IOFN (lseek )(* (int * )stream , 0 , SEEK_CUR );
415
416
}
416
-
417
- long ZCALLBACK minizip_io_filehandle_seek_file_fn (voidpf opaque , voidpf stream , uLong offset , int origin )
417
+
418
+ long ZCALLBACK minizip_io_filehandle_seek_file_fn (voidpf opaque , voidpf stream , uLong offset , int origin )
418
419
{
419
420
int whence ;
420
421
if (!opaque || !stream )
@@ -489,8 +490,8 @@ voidpf ZCALLBACK minizip_io_memory_open_file_fn (voidpf opaque, const char* file
489
490
}
490
491
return result ;
491
492
}
492
-
493
- uLong ZCALLBACK minizip_io_memory_read_file_fn (voidpf opaque , voidpf stream , void * buf , uLong size )
493
+
494
+ uLong ZCALLBACK minizip_io_memory_read_file_fn (voidpf opaque , voidpf stream , void * buf , uLong size )
494
495
{
495
496
uLong len ;
496
497
if (!opaque || !stream || !buf || size == 0 )
@@ -504,35 +505,35 @@ uLong ZCALLBACK minizip_io_memory_read_file_fn (voidpf opaque, voidpf stream, vo
504
505
return len ;
505
506
}
506
507
507
- /*
508
- uLong ZCALLBACK minizip_io_memory_write_file_fn (voidpf opaque, voidpf stream, const void* buf, uLong size)
508
+ /*
509
+ uLong ZCALLBACK minizip_io_memory_write_file_fn (voidpf opaque, voidpf stream, const void* buf, uLong size)
509
510
{
510
511
return 0;
511
512
}
512
513
*/
513
-
514
- int ZCALLBACK minizip_io_memory_close_file_fn (voidpf opaque , voidpf stream )
514
+
515
+ int ZCALLBACK minizip_io_memory_close_file_fn (voidpf opaque , voidpf stream )
515
516
{
516
517
free (stream );
517
518
if (opaque && ((struct minizip_io_memory_data * )opaque )-> freedata )
518
519
free (((struct minizip_io_memory_data * )opaque )-> data );
519
520
free (opaque );
520
521
return 0 ;
521
522
}
522
-
523
- int ZCALLBACK minizip_io_memory_testerror_file_fn (voidpf opaque , voidpf stream )
523
+
524
+ int ZCALLBACK minizip_io_memory_testerror_file_fn (voidpf opaque , voidpf stream )
524
525
{
525
526
return 0 ;
526
527
}
527
-
528
- long ZCALLBACK minizip_io_memory_tell_file_fn (voidpf opaque , voidpf stream )
528
+
529
+ long ZCALLBACK minizip_io_memory_tell_file_fn (voidpf opaque , voidpf stream )
529
530
{
530
531
if (!opaque || !stream )
531
532
return 0 ;
532
533
return ((struct minizip_io_memory_handle * )stream )-> pos ;
533
534
}
534
-
535
- long ZCALLBACK minizip_io_memory_seek_file_fn (voidpf opaque , voidpf stream , uLong offset , int origin )
535
+
536
+ long ZCALLBACK minizip_io_memory_seek_file_fn (voidpf opaque , voidpf stream , uLong offset , int origin )
536
537
{
537
538
switch (origin ) {
538
539
case ZLIB_FILEFUNC_SEEK_CUR :
@@ -888,6 +889,9 @@ struct data_sheet_callback_data {
888
889
XML_Char * celldata ;
889
890
size_t celldatalen ;
890
891
cell_string_type_enum cell_string_type ;
892
+ int cell_style_idx ;
893
+ int num_format ;
894
+ int * cell_style_formats ;
891
895
unsigned int flags ;
892
896
XML_Char * skiptag ; //tag to skip
893
897
size_t skiptagcount ; //nesting level for current tag to skip
@@ -899,7 +903,7 @@ struct data_sheet_callback_data {
899
903
void * callbackdata ;
900
904
};
901
905
902
- void data_sheet_callback_data_initialize (struct data_sheet_callback_data * data , struct sharedstringlist * sharedstrings , unsigned int flags , xlsxioread_process_cell_callback_fn cell_callback , xlsxioread_process_row_callback_fn row_callback , void * callbackdata )
906
+ void data_sheet_callback_data_initialize (struct data_sheet_callback_data * data , struct sharedstringlist * sharedstrings , unsigned int flags , xlsxioread_process_cell_callback_fn cell_callback , xlsxioread_process_row_callback_fn row_callback , void * callbackdata , int * cell_style_formats )
903
907
{
904
908
data -> xmlparser = NULL ;
905
909
data -> sharedstrings = sharedstrings ;
@@ -909,6 +913,8 @@ void data_sheet_callback_data_initialize (struct data_sheet_callback_data* data,
909
913
data -> celldata = NULL ;
910
914
data -> celldatalen = 0 ;
911
915
data -> cell_string_type = none ;
916
+ data -> cell_style_idx = -1 ;
917
+ data -> cell_style_formats = cell_style_formats ;
912
918
data -> flags = flags ;
913
919
data -> skiptag = NULL ;
914
920
data -> skiptagcount = 0 ;
@@ -925,6 +931,7 @@ void data_sheet_callback_data_cleanup (struct data_sheet_callback_data* data)
925
931
sharedstringlist_destroy (data -> sharedstrings );
926
932
free (data -> celldata );
927
933
free (data -> skiptag );
934
+ free (data -> cell_style_formats );
928
935
}
929
936
930
937
void data_sheet_expat_callback_skip_tag_start (void * callbackdata , const XML_Char * name , const XML_Char * * atts )
@@ -1122,6 +1129,13 @@ void data_sheet_expat_callback_find_cell_start (void* callbackdata, const XML_Ch
1122
1129
data -> cell_string_type = shared_string ;
1123
1130
else
1124
1131
data -> cell_string_type = value_string ;
1132
+
1133
+ const XML_Char * s = get_expat_attr_by_name (atts , X ("s" ));
1134
+ if (s != NULL ) {
1135
+ sscanf (s , "%d" , & data -> cell_style_idx );
1136
+ } else {
1137
+ data -> cell_style_idx = -1 ;
1138
+ }
1125
1139
//prepare empty value data
1126
1140
free (data -> celldata );
1127
1141
data -> celldata = NULL ;
@@ -1152,6 +1166,11 @@ void data_sheet_expat_callback_find_cell_end (void* callbackdata, const XML_Char
1152
1166
free (data -> celldata );
1153
1167
data -> celldata = NULL ;
1154
1168
}
1169
+ if (data -> cell_style_idx > -1 && data -> cell_style_idx < 256 ) {
1170
+ data -> num_format = data -> cell_style_formats [data -> cell_style_idx ];
1171
+ } else {
1172
+ data -> num_format = -1 ;
1173
+ }
1155
1174
}
1156
1175
//reset data
1157
1176
data -> colnr ++ ;
@@ -1268,17 +1287,29 @@ DLL_EXPORT_XLSXIO int xlsxioread_process (xlsxioreader handle, const XLSXIOCHAR*
1268
1287
shared_strings_callback_data_cleanup (& sharedstringsdata );
1269
1288
}
1270
1289
1290
+ // styles
1291
+ int * cell_style_formats = NULL ;
1292
+ if (getrelscallbackdata .stylesfile && getrelscallbackdata .stylesfile [0 ]) {
1293
+ cell_style_formats = malloc (256 * sizeof (int ));
1294
+ struct cell_styles_callback_data cell_styles_data ;
1295
+ cell_styles_callback_data_initialize (& cell_styles_data , cell_style_formats );
1296
+ if (expat_process_zip_file (handle -> zip , getrelscallbackdata .stylesfile , cell_styles_callback_find_start , NULL , NULL , & cell_styles_data , & cell_styles_data .xmlparser ) != 0 ) {
1297
+ free (cell_style_formats );
1298
+ cell_style_formats = NULL ;
1299
+ }
1300
+ }
1301
+
1271
1302
//process sheet
1272
1303
if (!(flags & XLSXIOREAD_NO_CALLBACK )) {
1273
1304
//use callback mechanism
1274
1305
struct data_sheet_callback_data processcallbackdata ;
1275
- data_sheet_callback_data_initialize (& processcallbackdata , sharedstrings , flags , cell_callback , row_callback , callbackdata );
1306
+ data_sheet_callback_data_initialize (& processcallbackdata , sharedstrings , flags , cell_callback , row_callback , callbackdata , cell_style_formats );
1276
1307
expat_process_zip_file (handle -> zip , getrelscallbackdata .sheetfile , data_sheet_expat_callback_find_worksheet_start , NULL , NULL , & processcallbackdata , & processcallbackdata .xmlparser );
1277
1308
data_sheet_callback_data_cleanup (& processcallbackdata );
1278
1309
} else {
1279
1310
//use simplified interface by suspending the XML parser when data is found
1280
1311
xlsxioreadersheet sheethandle = (xlsxioreadersheet )callbackdata ;
1281
- data_sheet_callback_data_initialize (& sheethandle -> processcallbackdata , sharedstrings , flags , NULL , NULL , sheethandle );
1312
+ data_sheet_callback_data_initialize (& sheethandle -> processcallbackdata , sharedstrings , flags , NULL , NULL , sheethandle , cell_style_formats );
1282
1313
if ((sheethandle -> zipfile = XML_Char_openzip (sheethandle -> handle -> zip , getrelscallbackdata .sheetfile , 0 )) == NULL ) {
1283
1314
result = 1 ;
1284
1315
}
@@ -1488,6 +1519,64 @@ DLL_EXPORT_XLSXIO XLSXIOCHAR* xlsxioread_sheet_next_cell (xlsxioreadersheet shee
1488
1519
return result ;
1489
1520
}
1490
1521
1522
+ DLL_EXPORT_XLSXIO XLSXIOCHAR * xlsxioread_sheet_next_cell_with_format (xlsxioreadersheet sheethandle , int * format )
1523
+ {
1524
+ XML_Char * result ;
1525
+ if (!sheethandle )
1526
+ return NULL ;
1527
+ //append empty column if needed
1528
+ if (sheethandle -> paddingcol ) {
1529
+ if (sheethandle -> paddingcol > sheethandle -> processcallbackdata .cols ) {
1530
+ //last empty column added, finish row
1531
+ sheethandle -> paddingcol = 0 ;
1532
+ //when padding rows prepare for the next one
1533
+ if (sheethandle -> paddingrow ) {
1534
+ sheethandle -> lastrownr ++ ;
1535
+ sheethandle -> paddingrow ++ ;
1536
+ if (sheethandle -> paddingrow + 1 < sheethandle -> processcallbackdata .rownr ) {
1537
+ sheethandle -> paddingcol = 1 ;
1538
+ }
1539
+ }
1540
+ return NULL ;
1541
+ } else {
1542
+ //add another empty column
1543
+ sheethandle -> paddingcol ++ ;
1544
+ return XML_Char_dup (X ("" ));
1545
+ }
1546
+ }
1547
+ //get value
1548
+ if (!sheethandle -> processcallbackdata .celldata )
1549
+ if (expat_process_zip_file_resume (sheethandle -> zipfile , sheethandle -> processcallbackdata .xmlparser ) != XML_STATUS_SUSPENDED )
1550
+ sheethandle -> processcallbackdata .celldata = NULL ;
1551
+ //insert empty rows if needed
1552
+ if (!(sheethandle -> processcallbackdata .flags & XLSXIOREAD_SKIP_EMPTY_ROWS ) && sheethandle -> lastrownr + 1 < sheethandle -> processcallbackdata .rownr ) {
1553
+ sheethandle -> paddingrow = sheethandle -> lastrownr + 1 ;
1554
+ sheethandle -> paddingcol = sheethandle -> processcallbackdata .colnr * 0 + 1 ;
1555
+ return xlsxioread_sheet_next_cell_with_format (sheethandle , format );
1556
+ }
1557
+ //insert empty column before if needed
1558
+ if (!(sheethandle -> processcallbackdata .flags & XLSXIOREAD_SKIP_EMPTY_CELLS )) {
1559
+ if (sheethandle -> lastcolnr + 1 < sheethandle -> processcallbackdata .colnr ) {
1560
+ sheethandle -> lastcolnr ++ ;
1561
+ return XML_Char_dup (X ("" ));
1562
+ }
1563
+ }
1564
+ result = sheethandle -> processcallbackdata .celldata ;
1565
+ sheethandle -> processcallbackdata .celldata = NULL ;
1566
+ //end of row
1567
+ if (!result ) {
1568
+ sheethandle -> lastrownr = sheethandle -> processcallbackdata .rownr ;
1569
+ //insert empty column at end if row if needed
1570
+ if (!result && !(sheethandle -> processcallbackdata .flags & XLSXIOREAD_SKIP_EMPTY_CELLS ) && sheethandle -> processcallbackdata .colnr < sheethandle -> processcallbackdata .cols ) {
1571
+ sheethandle -> paddingcol = sheethandle -> lastcolnr + 1 ;
1572
+ return xlsxioread_sheet_next_cell_with_format (sheethandle , format );
1573
+ }
1574
+ }
1575
+ sheethandle -> lastcolnr = sheethandle -> processcallbackdata .colnr ;
1576
+ * format = sheethandle -> processcallbackdata .num_format ;
1577
+ return result ;
1578
+ }
1579
+
1491
1580
DLL_EXPORT_XLSXIO int xlsxioread_sheet_next_cell_string (xlsxioreadersheet sheethandle , XLSXIOCHAR * * pvalue )
1492
1581
{
1493
1582
XML_Char * result ;
0 commit comments