1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *
3  * Copyright 2004 Komarov Valery
4  * Copyright 2006 Christophe Leitienne
5  * Copyright 2008-2017 David Hoerl
6  * Copyright 2013 Bob Colbert
7  * Copyright 2013-2018 Evan Miller
8  *
9  * This file is part of libxls -- A multiplatform, C/C++ library for parsing
10  * Excel(TM) files.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  *    1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  *    2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS
23  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
26  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  */
35 
36 #include "config.h"
37 
38 #include <sys/types.h>
39 #include <wchar.h>
40 #include <stdio.h>
41 
42 #ifdef HAVE_ICONV
43 #include <iconv.h>
44 #endif
45 
46 #include <limits.h>
47 #include <stdlib.h>
48 #include <errno.h>
49 #include <memory.h>
50 #include <string.h>
51 
52 //#include "xls.h"
53 #include "../include/libxls/xlstypes.h"
54 #include "../include/libxls/xlsstruct.h"
55 #include "../include/libxls/xlstool.h"
56 #include "../include/libxls/brdb.h"
57 #include "../include/libxls/endian.h"
58 #include "../include/libxls/locale.h"
59 
60 extern int xls_debug;
61 
62 /* Not a complete list */
63 enum xls_format_e {
64     XLS_FORMAT_GENERAL, // ""
65     XLS_FORMAT_NUMBER1, // "0"
66     XLS_FORMAT_NUMBER2,  //     "0.00",
67     XLS_FORMAT_NUMBER3,  //     "#,##0",
68     XLS_FORMAT_NUMBER4,  //     "#,##0.00",
69     XLS_FORMAT_CURRENCY1,  //   "\"$\"#,##0_);(\"$\"#,##0)",
70     XLS_FORMAT_CURRENCY2,  //   "\"$\"#,##0_);[Red](\"$\"#,##0)",
71     XLS_FORMAT_CURRENCY3,  //   "\"$\"#,##0.00_);(\"$\"#,##0.00)",
72     XLS_FORMAT_CURRENCY4,  //   "\"$\"#,##0.00_);[Red](\"$\"#,##0.00)",
73     XLS_FORMAT_PERCENT1,  //    "0%",
74     XLS_FORMAT_PERCENT2,  //    "0.00%",
75     XLS_FORMAT_SCIENTIFIC1,  // "0.00E+00",
76     XLS_FORMAT_SCIENTIFIC2 = 34 // "##0.0E+0"
77 };
78 
79 static const DWORD colors[] =
80     {
81         0x000000,
82         0xFFFFFF,
83         0xFF0000,
84         0x00FF00,
85         0x0000FF,
86         0xFFFF00,
87         0xFF00FF,
88         0x00FFFF,
89         0x800000,
90         0x008000,
91         0x000080,
92         0x808000,
93         0x800080,
94         0x008080,
95         0xC0C0C0,
96         0x808080,
97         0x9999FF,
98         0x993366,
99         0xFFFFCC,
100         0xCCFFFF,
101         0x660066,
102         0xFF8080,
103         0x0066CC,
104         0xCCCCFF,
105         0x000080,
106         0xFF00FF,
107         0xFFFF00,
108         0x00FFFF,
109         0x800080,
110         0x800000,
111         0x008080,
112         0x0000FF,
113         0x00CCFF,
114         0xCCFFFF,
115         0xCCFFCC,
116         0xFFFF99,
117         0x99CCFF,
118         0xFF99CC,
119         0xCC99FF,
120         0xFFCC99,
121         0x3366FF,
122         0x33CCCC,
123         0x99CC00,
124         0xFFCC00,
125         0xFF9900,
126         0xFF6600,
127         0x666699,
128         0x969696,
129         0x003366,
130         0x339966,
131         0x003300,
132         0x333300,
133         0x993300,
134         0x993366,
135         0x333399,
136         0x333333
137     };
138 
139 
140 // Display string if in debug mode
verbose(char * str)141 void verbose(char* str)
142 {
143     if (xls_debug)
144         printf("libxls : %s\n",str);
145 }
146 
147 #ifdef HAVE_ICONV
148 
149 struct codepage_entry_t {
150     int code;
151     const char *name;
152 };
153 
154 static struct codepage_entry_t _codepage_entries[] = {
155     { .code = 874, .name = "WINDOWS-874" },
156     { .code = 932, .name = "SHIFT-JIS" },
157     { .code = 936, .name = "WINDOWS-936" },
158     { .code = 950, .name = "BIG-5" },
159     { .code = 951, .name = "BIG5-HKSCS" },
160     { .code = 1250, .name = "WINDOWS-1250" },
161     { .code = 1251, .name = "WINDOWS-1251" },
162     { .code = 1252, .name = "WINDOWS-1252" },
163     { .code = 1253, .name = "WINDOWS-1253" },
164     { .code = 1254, .name = "WINDOWS-1254" },
165     { .code = 1255, .name = "WINDOWS-1255" },
166     { .code = 1256, .name = "WINDOWS-1256" },
167     { .code = 1257, .name = "WINDOWS-1257" },
168     { .code = 1258, .name = "WINDOWS-1258" },
169     { .code = 10000, .name = "MACROMAN" },
170     { .code = 10004, .name = "MACARABIC" },
171     { .code = 10005, .name = "MACHEBREW" },
172     { .code = 10006, .name = "MACGREEK" },
173     { .code = 10007, .name = "MACCYRILLIC" },
174     { .code = 10010, .name = "MACROMANIA" },
175     { .code = 10017, .name = "MACUKRAINE" },
176     { .code = 10021, .name = "MACTHAI" },
177     { .code = 10029, .name = "MACCENTRALEUROPE" },
178     { .code = 10079, .name = "MACICELAND" },
179     { .code = 10081, .name = "MACTURKISH" },
180     { .code = 10082, .name = "MACCROATIAN" },
181 };
182 
codepage_compare(const void * key,const void * value)183 static int codepage_compare(const void *key, const void *value) {
184     const struct codepage_entry_t *cp1 = key;
185     const struct codepage_entry_t *cp2 = value;
186     return cp1->code - cp2->code;
187 }
188 
encoding_for_codepage(WORD codepage)189 static const char *encoding_for_codepage(WORD codepage) {
190     struct codepage_entry_t key = { .code = codepage };
191     struct codepage_entry_t *result = bsearch(&key, _codepage_entries,
192             sizeof(_codepage_entries)/sizeof(_codepage_entries[0]),
193             sizeof(_codepage_entries[0]), &codepage_compare);
194     if (result) {
195         return result->name;
196     }
197     return "WINDOWS-1252";
198 }
199 
unicode_decode_iconv(const char * s,size_t len,iconv_t ic)200 static char* unicode_decode_iconv(const char *s, size_t len, iconv_t ic) {
201     char* outbuf = 0;
202 
203     if(s && len && ic)
204     {
205         size_t outlenleft = len;
206         int outlen = len;
207         size_t inlenleft = len;
208         const char* src_ptr = s;
209         char* out_ptr = 0;
210 
211         size_t st;
212         outbuf = malloc(outlen + 1);
213 
214 		if(outbuf)
215         {
216             out_ptr = outbuf;
217             while(inlenleft)
218             {
219                 st = iconv(ic, (ICONV_CONST char **)&src_ptr, &inlenleft, (char **)&out_ptr,(size_t *) &outlenleft);
220                 if(st == (size_t)(-1))
221                 {
222                     if(errno == E2BIG)
223                     {
224                         size_t diff = out_ptr - outbuf;
225                         outlen += inlenleft;
226                         outlenleft += inlenleft;
227                         outbuf = realloc(outbuf, outlen + 1);
228                         if(!outbuf)
229                         {
230                             break;
231                         }
232                         out_ptr = outbuf + diff;
233                     }
234                     else
235                     {
236                         free(outbuf), outbuf = NULL;
237                         break;
238                     }
239                 }
240             }
241         }
242         outlen -= outlenleft;
243 
244         if(outbuf)
245         {
246             outbuf[outlen] = 0;
247         }
248     }
249     return outbuf;
250 }
251 
252 #endif
253 
254 // Convert UTF-16 to UTF-8 without iconv
unicode_decode_wcstombs(const char * s,size_t len,xls_locale_t locale)255 static char *unicode_decode_wcstombs(const char *s, size_t len, xls_locale_t locale) {
256 	// Do wcstombs conversion
257     char *converted = NULL;
258     int count, count2;
259     size_t i;
260     wchar_t *w = NULL;
261 
262     w = malloc((len/2+1)*sizeof(wchar_t));
263 
264     for(i=0; i<len/2; i++)
265     {
266         w[i] = (BYTE)s[2*i] + ((BYTE)s[2*i+1] << 8);
267     }
268     w[len/2] = '\0';
269 
270     count = xls_wcstombs_l(NULL, w, INT_MAX, locale);
271 
272     if (count <= 0) {
273         goto cleanup;
274     }
275 
276     converted = calloc(count+1, sizeof(char));
277     count2 = xls_wcstombs_l(converted, w, count, locale);
278     if (count2 <= 0) {
279         printf("wcstombs failed (%lu)\n", (unsigned long)len/2);
280         goto cleanup;
281     }
282 
283 cleanup:
284     free(w);
285     return converted;
286 }
287 
288 // Converts Latin-1 to UTF-8 the old-fashioned way
transcode_latin1_to_utf8(const char * str,DWORD len)289 static char *transcode_latin1_to_utf8(const char *str, DWORD len)
290 {
291 	int utf8_chars = 0;
292 	char *ret = NULL;
293     DWORD i;
294 
295     for(i=0; i<len; ++i) {
296         if(str[i] & (BYTE)0x80) {
297             ++utf8_chars;
298         }
299     }
300 
301     char *out = ret = malloc(len+utf8_chars+1);
302     // UTF-8 encoding inline
303     for(i=0; i<len; ++i) {
304         BYTE c = str[i];
305         if(c & (BYTE)0x80) {
306             *out++ = (BYTE)0xC0 | (c >> 6);
307             *out++ = (BYTE)0x80 | (c & 0x3F);
308         } else {
309             *out++ = c;
310         }
311     }
312     *out = 0;
313 
314 	return ret;
315 }
316 
317 // Convert BIFF5 string or compressed BIFF8 string to the encoding desired
318 // by the workbook. Returns a NUL-terminated string
codepage_decode(const char * s,size_t len,xlsWorkBook * pWB)319 char* codepage_decode(const char *s, size_t len, xlsWorkBook *pWB) {
320     if (!pWB->is5ver && strcmp(pWB->charset, "UTF-8") == 0)
321         return transcode_latin1_to_utf8(s, len);
322 
323 #ifdef HAVE_ICONV
324     if (!pWB->converter) {
325         const char *from_encoding = pWB->is5ver ? encoding_for_codepage(pWB->codepage) : "ISO-8859-1";
326         iconv_t converter = iconv_open(pWB->charset, from_encoding);
327         if (converter == (iconv_t)-1) {
328             printf("conversion from '%s' to '%s' not available", from_encoding, pWB->charset);
329             return NULL;
330         }
331         pWB->converter = (void *)converter;
332     }
333     return unicode_decode_iconv(s, len, pWB->converter);
334 #else
335     char *ret = malloc(len+1);
336     memcpy(ret, s, len);
337     ret[len] = 0;
338     return ret;
339 #endif
340 }
341 
342 // Convert unicode string to UTF-8
transcode_utf16_to_utf8(const char * s,size_t len)343 char* transcode_utf16_to_utf8(const char *s, size_t len) {
344     xls_locale_t locale = xls_createlocale();
345     char *result = unicode_decode_wcstombs(s, len, locale);
346     xls_freelocale(locale);
347     return result;
348 }
349 
350 // Convert unicode string to the encoding desired by the workbook
unicode_decode(const char * s,size_t len,xlsWorkBook * pWB)351 char* unicode_decode(const char *s, size_t len, xlsWorkBook *pWB)
352 {
353 #ifdef HAVE_ICONV
354 #if defined(_AIX) || defined(__sun)
355     const char *from_enc = "UTF-16le";
356 #else
357     const char *from_enc = "UTF-16LE";
358 #endif
359     if (!pWB->utf16_converter) {
360         iconv_t converter = iconv_open(pWB->charset, from_enc);
361         if (converter == (iconv_t)-1) {
362             printf("conversion from '%s' to '%s' not available\n", from_enc, pWB->charset);
363             return NULL;
364         }
365         pWB->utf16_converter = (void *)converter;
366     }
367     return unicode_decode_iconv(s, len, pWB->utf16_converter);
368 #else
369     if (!pWB->utf8_locale) {
370         xls_locale_t locale = xls_createlocale();
371         if (locale == NULL) {
372             printf("creation of UTF-8 locale failed\n");
373             return NULL;
374         }
375         pWB->utf8_locale = (void *)locale;
376     }
377     return unicode_decode_wcstombs(s, len, pWB->utf8_locale);
378 #endif
379 }
380 
381 // Read and decode string
get_string(const char * s,size_t len,BYTE is2,xlsWorkBook * pWB)382 char *get_string(const char *s, size_t len, BYTE is2, xlsWorkBook* pWB)
383 {
384     WORD ln;
385     DWORD ofs = 0;
386     BYTE flag = 0;
387     const char *str = s;
388     char *ret = NULL;
389 
390     if (is2) {
391 		// length is two bytes
392         if (ofs + 2 > len) {
393             return NULL;
394         }
395         ln= ((BYTE*)str)[0] + (((BYTE*)str)[1] << 8);
396         ofs+=2;
397     } else {
398 		// single byte length
399         if (ofs + 1 > len) {
400             return NULL;
401         }
402         ln=*(BYTE*)str;
403         ofs++;
404     }
405 
406 	if(!pWB->is5ver) {
407 		// unicode strings have a format byte before the string
408         if (ofs + 1 > len) {
409             return NULL;
410         }
411 		flag=*(BYTE*)(str+ofs);
412 		ofs++;
413 	}
414     if (flag&0x8) {
415 		// WORD rt;
416         // rt=*(WORD*)(str+ofs); // unused
417         ofs+=2;
418     }
419     if (flag&0x4) {
420 		// DWORD sz;
421         // sz=*(DWORD*)(str+ofs); // unused
422         ofs+=4;
423     }
424     if(flag & 0x1) {
425         if (ofs + 2*ln > len) {
426             return NULL;
427         }
428         ret = unicode_decode(str+ofs, ln*2, pWB);
429     } else {
430         if (ofs + ln > len) {
431             return NULL;
432         }
433         ret = codepage_decode(str+ofs, ln, pWB);
434     }
435 
436 #if 0	// debugging
437 	if(xls_debug == 100) {
438 		ofs += (flag & 0x1) ? ln*2 : ln;
439 
440 		printf("ofs=%d ret[0]=%d\n", ofs, *ret);
441 		{
442 			unsigned char *ptr;
443 
444 			ptr = ret;
445 
446 			printf("%x %x %x %x %x %x %x %x\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7] );
447 			printf("%s\n", ret);
448 		}
449 	}
450 #endif
451 
452     return ret;
453 }
454 
xls_getColor(const WORD color,WORD def)455 DWORD xls_getColor(const WORD color,WORD def)
456 {
457     int cor=8;
458     int size = 64 - cor;
459     int max = size;
460     WORD idx=color;
461     if( idx >= cor)
462         idx -= cor;
463     if( idx < max )
464     {
465         return colors[idx];
466     }
467     else
468         return colors[def];
469 }
470 
471 
xls_showBookInfo(xlsWorkBook * pWB)472 void xls_showBookInfo(xlsWorkBook* pWB)
473 {
474     verbose("BookInfo");
475     printf("  is5ver: %i\n",pWB->is5ver);
476     printf("codepage: %i\n",pWB->codepage);
477     printf("    type: %.4X ",pWB->type);
478     switch (pWB->type)
479     {
480     case 0x5:
481         printf("Workbook globals\n");
482         break;
483     case 0x6:
484         printf("Visual Basic module\n");
485         break;
486     case 0x10:
487         printf("Worksheet\n");
488         break;
489     case 0x20:
490         printf("Chart\n");
491         break;
492     case 0x40:
493         printf("BIFF4 Macro sheet\n");
494         break;
495     case 0x100:
496         printf("BIFF4W Workbook globals\n");
497         break;
498     }
499     printf("------------------- END BOOK INFO---------------------------\n");
500 }
501 
502 
xls_showBOF(BOF * bof)503 void xls_showBOF(BOF* bof)
504 {
505     printf("----------------------------------------------\n");
506     verbose("BOF");
507     printf("   ID: %.4Xh %s (%s)\n",bof->id,brdb[get_brbdnum(bof->id)].name,brdb[get_brbdnum(bof->id)].desc);
508     printf("   Size: %i\n",bof->size);
509 }
510 
511 #if 0
512 static void xls_showBOUNDSHEET(BOUNDSHEET* bsheet)
513 {
514     switch (bsheet->type & 0x000f)
515     {
516     case 0x0000:
517         /* worksheet or dialog sheet */
518         verbose ("85: Worksheet or dialog sheet");
519         break;
520     case 0x0001:
521         /* Microsoft Excel 4.0 macro sheet */
522         verbose ("85: Microsoft Excel 4.0 macro sheet");
523         break;
524     case 0x0002:
525         /* Chart */
526         verbose ("85: Chart sheet");
527         break;
528     case 0x0006:
529         /* Visual Basic module */
530         verbose ("85: Visual Basic sheet");
531         break;
532     default:
533         break;
534     }
535     printf("    Pos: %Xh\n",bsheet->filepos);
536     printf("  flags: %.4Xh\n",bsheet->type);
537     //	printf("   Name: [%i] %s\n",bsheet->len,bsheet->name);
538 }
539 #endif
540 
xls_showROW(struct st_row_data * row)541 void xls_showROW(struct st_row_data* row)
542 {
543     verbose("ROW");
544     printf("    Index: %i \n",row->index);
545     printf("First col: %i \n",row->fcell);
546     printf(" Last col: %i \n",row->lcell);
547     printf("   Height: %i (1/20 px)\n",row->height);
548     printf("    Flags: %.4X \n",row->flags);
549     printf("       xf: %i \n",row->xf);
550     printf("----------------------------------------------\n");
551 }
552 
xls_showColinfo(struct st_colinfo_data * col)553 void xls_showColinfo(struct st_colinfo_data* col)
554 {
555     verbose("COLINFO");
556     printf("First col: %i \n",col->first);
557     printf(" Last col: %i \n",col->last);
558     printf("    Width: %i (1/256 px)\n",col->width);
559     printf("       XF: %i \n",col->xf);
560     printf("    Flags: %i (",col->flags);
561     if (col->flags & 0x1)
562         printf("hidden ");
563     if (col->flags & 0x700)
564         printf("outline ");
565     if (col->flags & 0x1000)
566         printf("collapsed ");
567     printf(")\n");
568     printf("----------------------------------------------\n");
569 }
570 
xls_showCell(struct st_cell_data * cell)571 void xls_showCell(struct st_cell_data* cell)
572 {
573     printf("  -----------\n");
574     printf("     ID: %.4Xh %s (%s)\n",cell->id, brdb[get_brbdnum(cell->id)].name, brdb[get_brbdnum(cell->id)].desc);
575     printf("   Cell: %c:%u  [%u:%u]\n",cell->col+'A',cell->row+1,cell->col,cell->row);
576 //    printf("   Cell: %u:%u\n",cell->col+1,cell->row+1);
577     printf("     xf: %i\n",cell->xf);
578 	if(cell->id == XLS_RECORD_BLANK) {
579 		//printf("BLANK_CELL!\n");
580 		return;
581 	}
582     printf(" double: %f\n",cell->d);
583     printf("    int: %d\n",cell->l);
584     if (cell->str!=NULL)
585         printf("    str: %s\n",cell->str);
586 }
587 
588 
xls_showFont(struct st_font_data * font)589 void xls_showFont(struct st_font_data* font)
590 {
591 
592     printf("      name: %s\n",font->name);
593     printf("    height: %i\n",font->height);
594     printf("      flag: %.4X\n",font->flag);
595     printf("     color: %.6X\n",font->color);
596     printf("      bold: %i\n",font->bold);
597     printf("escapement: %i\n",font->escapement);
598     printf(" underline: %i\n",font->underline);
599     printf("    family: %i\n",font->family);
600     printf("   charset: %i\n",font->charset);
601 
602 }
603 #if 0
604 typedef struct st_format
605 	{
606 		long count;		//Count of FORMAT's
607 		struct st_format_data
608 		{
609 			WORD index;
610 			char *value;
611 		}
612 		* format;
613 	}
614 	st_format;
615 #endif
616 
xls_showFormat(struct st_format_data * frmt)617 void xls_showFormat(struct st_format_data* frmt)
618 {
619 	printf("    index : %u\n", frmt->index);
620     printf("     value: %s\n", frmt->value);
621 }
622 
xls_showXF(XF8 * xf)623 void xls_showXF(XF8* xf)
624 {
625 	static int idx;
626 
627     printf("      Index: %u\n",idx++);
628     printf("       Font: %u\n",xf->font);
629     printf("     Format: %u\n",xf->format);
630     printf("       Type: 0x%x\n",xf->type);
631     printf("      Align: 0x%x\n",xf->align);
632     printf("   Rotation: 0x%x\n",xf->rotation);
633     printf("      Ident: 0x%x\n",xf->ident);
634     printf("   UsedAttr: 0x%x\n",xf->usedattr);
635     printf("  LineStyle: 0x%x\n",xf->linestyle);
636     printf("  Linecolor: 0x%x\n",xf->linecolor);
637     printf("GroundColor: 0x%x\n",xf->groundcolor);
638 }
639 
xls_getfcell(xlsWorkBook * pWB,struct st_cell_data * cell,BYTE * label)640 char *xls_getfcell(xlsWorkBook* pWB, struct st_cell_data* cell, BYTE *label)
641 {
642     struct st_xf_data *xf = NULL;
643 	WORD	len = 0;
644     DWORD   offset = 0;
645     char	*ret = NULL;
646     size_t  retlen = 100;
647 
648     if (cell->xf < pWB->xfs.count)
649         xf=&pWB->xfs.xf[cell->xf];
650 
651     switch (cell->id)
652     {
653     case XLS_RECORD_LABELSST:
654         offset = label[0] + (label[1] << 8);
655         if(!pWB->is5ver) {
656             offset += ((DWORD)label[2] << 16);
657             offset += ((DWORD)label[3] << 24);
658         }
659         if(offset < pWB->sst.count && pWB->sst.string[offset].str) {
660             ret = strdup(pWB->sst.string[offset].str);
661         }
662         break;
663     case XLS_RECORD_BLANK:
664     case XLS_RECORD_MULBLANK:
665         ret = strdup("");
666         break;
667     case XLS_RECORD_LABEL:
668     case XLS_RECORD_RSTRING:
669         len = label[0] + (label[1] << 8);
670         label += 2;
671         if (pWB->is5ver || (*(label++) & 0x01) == 0) {
672             ret = codepage_decode((char *)label, len, pWB);
673         } else {
674             ret = unicode_decode((char *)label, len*2, pWB);
675         }
676         break;
677     case XLS_RECORD_RK:
678     case XLS_RECORD_NUMBER:
679         ret = malloc(retlen);
680         snprintf(ret, retlen, "%lf", cell->d);
681 		break;
682 		//		if( RK || MULRK || NUMBER || FORMULA)
683 		//		if (cell->id==0x27e || cell->id==0x0BD || cell->id==0x203 || 6 (formula))
684     default:
685         if (xf) {
686             ret = malloc(retlen);
687             switch (xf->format)
688             {
689                 case XLS_FORMAT_GENERAL:
690                 case XLS_FORMAT_NUMBER1:
691                 case XLS_FORMAT_NUMBER3:
692                     snprintf(ret, retlen, "%.0lf", cell->d);
693                     break;
694                 case XLS_FORMAT_NUMBER2:
695                 case XLS_FORMAT_NUMBER4:
696                     snprintf(ret, retlen, "%.2f", cell->d);
697                     break;
698                 case XLS_FORMAT_PERCENT1:
699                     snprintf(ret, retlen, "%.0lf%%", 100 * cell->d);
700                     break;
701                 case XLS_FORMAT_PERCENT2:
702                     snprintf(ret, retlen, "%.2lf%%", 100 * cell->d);
703                     break;
704                 case XLS_FORMAT_SCIENTIFIC1:
705                     snprintf(ret, retlen, "%.2e", cell->d);
706                     break;
707                 case XLS_FORMAT_SCIENTIFIC2:
708                     snprintf(ret, retlen, "%.1e", cell->d);
709                     break;
710                 default:
711                     snprintf(ret, retlen, "%.2f", cell->d);
712                     break;
713             }
714             break;
715         }
716     }
717 
718     return ret;
719 }
720 
xls_getCSS(xlsWorkBook * pWB)721 char* xls_getCSS(xlsWorkBook* pWB)
722 {
723     char color[255];
724     char* align;
725     char* valign;
726     char borderleft[255];
727     char borderright[255];
728     char bordertop[255];
729     char borderbottom[255];
730     char italic[255];
731     char underline[255];
732     char bold[255];
733     WORD size;
734     char fontname[255];
735     struct st_xf_data* xf;
736     DWORD background;
737     DWORD i;
738 
739     char *ret = malloc(65535);
740     char *buf = malloc(4096);
741 	ret[0] = '\0';
742 
743     for (i=0;i<pWB->xfs.count;i++)
744     {
745         xf=&pWB->xfs.xf[i];
746         switch ((xf->align & 0x70)>>4)
747         {
748         case 0:
749             valign=(char*)"top";
750             break;
751         case 1:
752             valign=(char*)"middle";
753             break;
754         case 2:
755             valign=(char*)"bottom";
756             break;
757             //			case 3: valign=(char*)"right"; break;
758             //			case 4: valign=(char*)"right"; break;
759         default:
760             valign=(char*)"middle";
761             break;
762         }
763 
764         switch (xf->align & 0x07)
765         {
766         case 1:
767             align=(char*)"left";
768             break;
769         case 2:
770             align=(char*)"center";
771             break;
772         case 3:
773             align=(char*)"right";
774             break;
775         default:
776             align=(char*)"left";
777             break;
778         }
779 
780         switch (xf->linestyle & 0x0f)
781         {
782         case 0:
783             sprintf(borderleft,"%s", "");
784             break;
785         default:
786             sprintf(borderleft,"border-left: 1px solid black;");
787             break;
788         }
789 
790         switch (xf->linestyle & 0x0f0)
791         {
792         case 0:
793             sprintf(borderright,"%s", "");
794             break;
795         default:
796             sprintf(borderright,"border-right: 1px solid black;");
797             break;
798         }
799 
800         switch (xf->linestyle & 0x0f00)
801         {
802         case 0:
803             sprintf(bordertop,"%s", "");
804             break;
805         default:
806             sprintf(bordertop,"border-top: 1px solid black;");
807             break;
808         }
809 
810         switch (xf->linestyle & 0x0f000)
811         {
812         case 0:
813             sprintf(borderbottom,"%s", "");
814             break;
815         default:
816             sprintf(borderbottom,"border-bottom: 1px solid Black;");
817             break;
818         }
819 
820         if (xf->font)
821             sprintf(color,"color:#%.6X;",xls_getColor(pWB->fonts.font[xf->font-1].color,0));
822         else
823             sprintf(color,"%s", "");
824 
825         if (xf->font && (pWB->fonts.font[xf->font-1].flag & 2))
826             sprintf(italic,"font-style: italic;");
827         else
828             sprintf(italic,"%s", "");
829 
830         if (xf->font && (pWB->fonts.font[xf->font-1].bold>400))
831             sprintf(bold,"font-weight: bold;");
832         else
833             sprintf(bold,"%s", "");
834 
835         if (xf->font && (pWB->fonts.font[xf->font-1].underline))
836             sprintf(underline,"text-decoration: underline;");
837         else
838             sprintf(underline,"%s", "");
839 
840         if (xf->font)
841             size=pWB->fonts.font[xf->font-1].height/20;
842         else
843             size=10;
844 
845         if (xf->font)
846             sprintf(fontname,"%s",pWB->fonts.font[xf->font-1].name);
847         else
848             sprintf(fontname,"Arial");
849 
850         background=xls_getColor((WORD)(xf->groundcolor & 0x7f),1);
851         sprintf(buf,".xf%i{ font-size:%ipt;font-family: \"%s\";background:#%.6X;text-align:%s;vertical-align:%s;%s%s%s%s%s%s%s%s}\n",
852                 i,size,fontname,background,align,valign,borderleft,borderright,bordertop,borderbottom,color,italic,bold,underline);
853 
854 		strcat(ret,buf);
855     }
856 	ret = realloc(ret, strlen(ret)+1);
857 	free(buf);
858 
859     return ret;
860 }
861