mseek parameter offset passed as double for file size more than 2GB.
[scilab.git] / scilab / modules / spreadsheet / src / c / xls.c
1
2 /*
3  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
4  * Copyright (C) 2005-2008 - INRIA - Serge STEER <serge.steer@inria.fr>
5  * Copyright (C) 2005-2008 - INRIA - Pierrick MODE
6  *
7  * This file must be used under the terms of the CeCILL.
8  * This source file is licensed as described in the file COPYING, which
9  * you should have received as part of this distribution.  The terms
10  * are also available at
11  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
12  *
13  */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include "core_math.h"
19 #include "MALLOC.h" /* MALLOC */
20 #include "sciprint.h"
21 #include "returnanan.h"
22 #include "xls.h"
23 #include "mseek.h"
24 #include "mtell.h"
25 #include "mget.h"
26 /*------------------------------------------------------------------*/
27 #define  typ_short "s"
28 #define  typ_ushort "us"
29 #define  typ_char "c"
30 #define  typ_uchar "uc"
31 #define  typ_double "d"
32 #define  typ_int "i"
33 /*------------------------------------------------------------------*/
34 extern int ripole(char *inputfile, char *outputfile, int debug, int verbose);
35 /*------------------------------------------------------------------*/
36 /*Prototype*/
37 static double NumFromRk2(long rk);
38 static void getBoundsheets(int * fd, char ***Sheetnames, int** Abspos, int *nsheets, double *cur_pos, int *err);
39 static void getSST(int *fd, short Len, int BIFF, int *ns, char ***sst, int *err);
40 static void getBOF(int *fd , int* Data, int *err);
41 static void getString(int *fd, short *count, short *Len, int flag, char **str, int *err);
42
43 /**
44  ** Bruno : Defined but not used ... so what !!!!!!!!
45  static int get_oleheader(int *fd);
46 **/
47 /*------------------------------------------------------------------*/
48 void xls_read(int *fd, int *cur_pos, double **data, int **chainesind, int *N, int *M, int *err)
49 {
50     /*---------------Declaration Des Variables*--------------------*/
51     unsigned short Opcode = 0, Len = 0;   /*Code Operationnel et Longueur du tag a lire*/
52     double *valeur = NULL;    /*Tableau Recapitulatif (Final) des valeurs de la feuille Excel*/
53     double pos = 0;
54
55     int one = 1;
56     int three = 3;
57
58     int i = 0;  /*Variables de boucle*/
59     int hauteur = 0, longueur = 0, capacite = 0;   /*Hauteur, longueur de la feuille,  */
60     /*int taille = 0; Nombre de types de caract�ers a enregistrer*/
61     char *sheetname = NULL;   /*Nom de la feuille*/
62     int rkvalue = 0; /*RK value*/
63     /*for RK */
64     unsigned short row = 0, col = 0, xf = 0;/*Index to row, to column, and to XF record*/
65     /*for MULRK */
66     unsigned short ixfe = 0;
67     short colFirst = 0, colLast = 0, ncol = 0; /*Index to rox, to first column (fc)*/
68     /* for LABELSST */
69     short labelsst1[3];
70     int indsst = 0; /*Index to SST record*/
71     /* for DIMENSIONS */
72     int f_row = 0, l_row = 0;
73     unsigned short f_col = 0, l_col = 0, notused = 0;
74     /* for FORMULA */
75     double resultat = 0.;/*Result of the formula*/
76     short optionflag = 0;/*Option flags*/
77     int formula_notused = 0; /*Not used*/
78     double NaN = C2F(returnanan)();
79
80     int BOFData[7]; /*[BIFF  Version DataType Identifier Year HistoryFlags LowestXlsVersion]*/
81     /* initialization of pointers corresponding to malloc's */
82     valeur = (double *)NULL;
83     sheetname = (char *)NULL;
84     *chainesind = (int *) NULL;
85     *err = 0;
86
87     pos = (double)(*cur_pos);
88     C2F(mseek) (fd, &pos, "set", err);
89     if (*err > 0)
90     {
91         goto ErrL;
92     }
93
94     /* first record should be a BOF */
95     getBOF(fd , BOFData, err);
96
97     if (*err > 0)
98     {
99         return;
100     }
101     if (BOFData[0] < 0) /* not a BOF */
102     {
103         *err = 2;
104         return;
105     }
106     if (BOFData[0] != 8)   /* not a BIFF8 */
107     {
108         *err = 3;
109         return;
110     }
111
112     C2F(mtell) (fd, &pos, err);
113     if (*err > 0)
114     {
115         goto ErrL;
116     }
117
118     while (1)
119     {
120         C2F(mseek) (fd, &pos, "set", err);
121         if (*err > 0)
122         {
123             goto ErrL;
124         }
125         /*Enregistrement de l'Opcode et de la Len du tag*/
126         C2F(mgetnc) (fd, &Opcode, &one, typ_ushort, err);
127         if (*err > 0)
128         {
129             goto ErrL;
130         }
131         C2F(mgetnc) (fd, &Len, &one, typ_ushort, err);
132         if (*err > 0)
133         {
134             goto ErrL;
135         }
136         switch (Opcode)
137         {
138             case 10:/*EOF */
139                 *N = hauteur;
140                 *M = longueur;
141                 *data = valeur;
142                 *cur_pos = (int)pos;
143                 *cur_pos = *cur_pos + 4 + Len;
144                 return;
145             case 638: /*RK*/
146                 C2F(mgetnc) (fd, (void*)&row, &one, typ_ushort, err);
147                 if (*err > 0)
148                 {
149                     goto ErrL;
150                 }
151                 C2F(mgetnc) (fd, (void*)&col, &one, typ_ushort, err);
152                 if (*err > 0)
153                 {
154                     goto ErrL;
155                 }
156                 // Check col and row are in bounds
157                 if ((col >= longueur) || (row >= hauteur))
158                 {
159                     *err = 2;
160                     goto ErrL;
161                 }
162                 C2F(mgetnc) (fd, (void*)&xf , &one, typ_ushort, err);
163                 if (*err > 0)
164                 {
165                     goto ErrL;
166                 }
167                 C2F(mgetnc) (fd, (void*) &rkvalue , &one, typ_int, err);
168                 if (*err > 0)
169                 {
170                     goto ErrL;
171                 }
172                 valeur[col * (hauteur) + row] = NumFromRk2(rkvalue);
173                 break;
174             case 515: /*Number*/
175                 C2F(mgetnc) (fd, (void*)&row, &one, typ_ushort, err);
176                 if (*err > 0)
177                 {
178                     goto ErrL;
179                 }
180                 C2F(mgetnc) (fd, (void*)&col, &one, typ_ushort, err);
181                 if (*err > 0)
182                 {
183                     goto ErrL;
184                 }
185                 // Check col and row are in bounds
186                 if ((col >= longueur) || (row >= hauteur))
187                 {
188                     *err = 2;
189                     goto ErrL;
190                 }
191                 C2F(mgetnc) (fd, (void*)&xf , &one, typ_ushort, err);
192                 if (*err > 0)
193                 {
194                     goto ErrL;
195                 }
196                 C2F(mgetnc) (fd, (void*) &resultat , &one, typ_double, err);
197                 if (*err > 0)
198                 {
199                     goto ErrL;
200                 }
201                 valeur[col * (hauteur) + row] = resultat ;
202                 break;
203
204             case 189: /*MULRK*/
205                 C2F(mgetnc) (fd, (void*)&row, &one, typ_ushort, err);
206                 if (*err > 0)
207                 {
208                     goto ErrL;
209                 }
210                 C2F(mgetnc) (fd,  (void*)&colFirst, &one, typ_short, err);
211                 if (*err > 0)
212                 {
213                     goto ErrL;
214                 }
215                 // Check col and row are in bounds
216                 if ((colFirst >= longueur) || (row >= hauteur))
217                 {
218                     *err = 2;
219                     goto ErrL;
220                 }
221                 /*List of nc=lc-fc+1  XF/RK structures*/
222                 ncol = (Len - 6) / 6;
223                 for (i = 0; i < ncol; i++)
224                 {
225                     C2F(mgetnc) (fd, (void*) &ixfe, &one, typ_short, err);
226                     if (*err > 0)
227                     {
228                         goto ErrL;
229                     }
230                     C2F(mgetnc) (fd, (void*) &rkvalue, &one, typ_int, err);
231                     if (*err > 0)
232                     {
233                         goto ErrL;
234                     }
235                     valeur[row + (colFirst + i)*hauteur] = NumFromRk2(rkvalue);
236                 }
237
238                 /*Index of last column*/
239                 C2F(mgetnc) (fd, (void*) &colLast, &one, typ_ushort, err);
240                 if (*err > 0)
241                 {
242                     goto ErrL;
243                 }
244                 break;
245
246             case 253:/*LABELSST*/
247                 C2F(mgetnc) (fd, (void*) labelsst1, &three, typ_short, err);
248                 if (*err > 0)
249                 {
250                     goto ErrL;
251                 }
252                 C2F(mgetnc) (fd, (void*) &indsst , &one, typ_int, err);
253                 if (*err > 0)
254                 {
255                     goto ErrL;
256                 }
257                 /*Allocation dans le tableau final*/
258                 col = labelsst1[1];
259                 row = labelsst1[0];
260                 // Check col and row are in bounds
261                 if ((col >= longueur) || (row >= hauteur))
262                 {
263                     *err = 2;
264                     goto ErrL;
265                 }
266                 (*chainesind)[col * (hauteur) + row] = indsst + 1;
267                 break;
268             case 512:/* DIMENSIONS*/
269                 C2F(mgetnc) (fd, (void*) &f_row, &one, typ_int, err);
270                 if (*err > 0)
271                 {
272                     goto ErrL;
273                 }
274                 C2F(mgetnc) (fd, (void*) &l_row, &one, typ_int, err);
275                 if (*err > 0)
276                 {
277                     goto ErrL;
278                 }
279                 C2F(mgetnc) (fd, (void*) &f_col, &one, typ_ushort, err);
280                 if (*err > 0)
281                 {
282                     goto ErrL;
283                 }
284                 C2F(mgetnc) (fd, (void*) &l_col, &one, typ_ushort, err);
285                 if (*err > 0)
286                 {
287                     goto ErrL;
288                 }
289                 C2F(mgetnc) (fd, (void*) &notused, &one, typ_ushort, err);
290                 if (*err > 0)
291                 {
292                     goto ErrL;
293                 }
294
295                 /*Calcul de longueur, hauteur et capacite de la feuille*/
296                 hauteur = l_row; /*-f_row;*/
297                 longueur = l_col; /*-f_col;*/
298                 capacite = hauteur * longueur;
299
300                 /*Declaration des tableaux de synthese*/
301                 if ((valeur = (void*) MALLOC((capacite + 1) * sizeof(double))) == NULL)
302                 {
303                     goto ErrL;
304                 }
305                 if ((*chainesind = (int *) MALLOC((capacite + 1) * sizeof(int))) == NULL)
306                 {
307                     goto ErrL;
308                 }
309                 for (i = 0; i <= capacite; i++)
310                 {
311                     (*chainesind)[i] = 0;
312                     valeur[i] = NaN;
313                 }
314                 break;
315             case 6:/* FORMULA*/
316                 C2F(mgetnc) (fd, (void*) &row, &one, typ_ushort, err);
317                 if (*err > 0)
318                 {
319                     goto ErrL;
320                 }
321                 C2F(mgetnc) (fd, (void*) &col, &one, typ_ushort, err);
322                 if (*err > 0)
323                 {
324                     goto ErrL;
325                 }
326                 // Check col and row are in bounds
327                 if ((col >= longueur) || (row >= hauteur))
328                 {
329                     *err = 2;
330                     goto ErrL;
331                 }
332                 C2F(mgetnc) (fd, (void*) &xf, &one, typ_ushort, err);
333                 if (*err > 0)
334                 {
335                     goto ErrL;
336                 }
337
338                 C2F(mgetnc) (fd, (void*) &resultat, &one, typ_double, err);
339                 if (*err > 0)
340                 {
341                     goto ErrL;
342                 }
343
344                 valeur[(col * hauteur + row)] = resultat;
345
346                 C2F(mgetnc) (fd, (void*)&optionflag, &one, typ_short, err);
347                 if (*err > 0)
348                 {
349                     goto ErrL;
350                 }
351
352                 C2F(mgetnc) (fd, (void*) &formula_notused, &one, typ_int, err);
353                 if (*err > 0)
354                 {
355                     goto ErrL;
356                 }
357
358                 /*Formuled data*/
359
360                 /*taille=Len-2-2-2-8-2-4;
361                   char formuladata[taille];
362                   C2F(mgetnc) (fd, (void*) formuladata, &taille, typ_char, err);
363                   if (*err > 0) goto ErrL;*/
364
365                 break;
366         }
367
368         pos = pos + 4 + Len;
369     }
370
371     *cur_pos = (int)pos;
372     return;
373 ErrL:
374     {
375         FREE(sheetname);
376         FREE(valeur);
377         FREE(*chainesind);
378         if (*err == 0)
379         {
380             *err = 1;    /* malloc problem */
381         }
382         else
383         {
384             *err = 2;    /* read problem */
385         }
386         return;
387     }
388 }
389
390
391 void xls_open(int *err, int *fd, char ***sst, int *ns, char ***Sheetnames, int** Abspos, int *nsheets)
392 {
393     /* if opt==1 it is supposed that the current file position is at the beginning of oleheader
394      * if opt==0 it is supposed that the current file position is at the  beginning of workbook stream
395      */
396
397     /* we suppose that the ole file as a simple structure:
398      * Workbook stream should follows immediately the header
399      * and is strored in sequential sections
400      */
401
402     /*return *err:
403       0 = OK
404       1 = not an OLE file
405       2 = no Workbook included
406       3 = memory allocation problem
407       4 = incorrect file
408       5 = not a BIFF8 xls file
409      */
410     /*---------------D�claration Des Variables*--------------------*/
411     int k, one = 1;
412     double cur_pos, init_pos;
413     unsigned short Opcode, Len;
414     /*BOF data*/
415     int BOFData[7]; /*[BIFF  Version DataType Identifier Year HistoryFlags LowestXlsVersion]*/
416     *nsheets = 0;
417     *err = 0;
418     /*---------------D�claration Des Variables*--------------------*/
419
420     /*  if (get_oleheader(fd)) {
421       *err=1;
422       return;
423       }*/
424     C2F(mtell) (fd, &cur_pos, err);
425     init_pos = cur_pos;
426
427     /* first record should be a BOF */
428     getBOF(fd , BOFData, err);
429     if (*err > 0)
430     {
431         return;
432     }
433
434     if (BOFData[0] < 0) /* not a BOF */
435     {
436         *err = 4;
437         return;
438     }
439     if (BOFData[0] != 8)   /* not a BIFF8 */
440     {
441         *err = 5;
442         return;
443     }
444
445     C2F(mtell) (fd, &cur_pos, err);
446     if (*err > 0)
447     {
448         goto Err2;
449     }
450
451     /* loops on records till an EOF is found */
452     while (1)
453     {
454         C2F(mseek) (fd, &cur_pos, "set", err);
455         if (*err > 0)
456         {
457             goto Err2;
458         }
459         /*Enregistrement de l'Opcode et de la Len du tag*/
460         C2F(mgetnc) (fd, &Opcode, &one, typ_ushort, err);
461         if (*err > 0)
462         {
463             goto Err2;
464         }
465         C2F(mgetnc) (fd, &Len, &one, typ_ushort, err);
466         if (*err > 0)
467         {
468             goto Err2;
469         }
470
471         switch (Opcode)
472         {
473             case 10: /*EOF*/
474                 cur_pos = cur_pos + 4 + Len;
475                 return ;
476             case 133: /* Boundsheets */
477                 getBoundsheets(fd, Sheetnames, Abspos, nsheets, &cur_pos, err);
478                 for (k = 0; k < *nsheets; k++)
479                 {
480                     (*Abspos)[k] += init_pos;
481                 }
482                 if (*err > 0)
483                 {
484                     return;
485                 }
486                 break;
487             case 252: /* SST= Shared String table*/
488                 getSST(fd, Len, BOFData[0], ns, sst, err);
489                 if (*err > 0)
490                 {
491                     return;
492                 }
493                 cur_pos = cur_pos + 4 + Len;
494                 break;
495             default:
496                 cur_pos = cur_pos + 4 + Len;
497         }
498     }
499
500 Err2:
501     *err = 4; /* read problem */
502     return;
503
504 }
505
506 static double NumFromRk2(long rk)
507 {
508     double num;
509     if (rk & 0x02)
510     {
511         /* int*/
512         num = (double) (rk >> 2);
513     }
514     else
515     {
516         /* hi words of IEEE num*/
517         *((int *)&num + 1) = rk & 0xfffffffc;
518         *((int *)&num) = 0;
519     }
520     if (rk & 0x01)
521         /* divide by 100*/
522     {
523         num /= 100;
524     }
525     return num;
526 }
527
528 static void getBOF(int *fd , int* Data, int *err)
529 {
530     /* return Data a vector [BIFF  Version DataType Identifier Year HistoryFlags LowestXlsVersion]
531      * works for BIFF2 to BIFF8 records */
532     int BIFF;
533     short Version;
534     short DataType;
535     short Identifier = 0;
536     short Year = 0;
537     int HistoryFlags = 0;
538     int LowestXlsVersion = 0;
539
540     unsigned short Opcode;
541     unsigned short Len;
542     int one = 1;
543
544     C2F(mgetnc) (fd, (void*)&Opcode, &one, typ_ushort, err);
545     if (*err > 0)
546     {
547         return;
548     }
549     C2F(mgetnc) (fd, (void*)&Len, &one, typ_ushort, err);
550     if (*err > 0)
551     {
552         return;
553     }
554
555     switch (Opcode)
556     {
557         case 2057:     /*Begin of file, BOF for BIFF5 BIFF7 BIFF8 BIFF8X*/
558             C2F(mgetnc) (fd, (void*)&Version, &one, typ_short, err);
559             if (*err > 0)
560             {
561                 return;
562             }
563             C2F(mgetnc) (fd, (void*)&DataType, &one, typ_short, err);
564             if (*err > 0)
565             {
566                 return;
567             }
568             C2F(mgetnc) (fd, (void*)&Identifier, &one, typ_short, err);
569             if (*err > 0)
570             {
571                 return;
572             }
573             C2F(mgetnc) (fd, (void*)&Year, &one, typ_short, err);
574             if (*err > 0)
575             {
576                 return;
577             }
578             if (Len == 16)
579             {
580                 C2F(mgetnc) (fd, (void*)&HistoryFlags, &one, typ_int, err);
581                 if (*err > 0)
582                 {
583                     return;
584                 }
585                 C2F(mgetnc) (fd, (void*)&LowestXlsVersion, &one, typ_int, err);
586                 if (*err > 0)
587                 {
588                     return;
589                 }
590                 BIFF = 8;
591                 if (Version != 1536)
592                 {
593                     return;
594                 }
595             }
596             else
597             {
598                 BIFF = 7;
599             }
600             break;
601         case 1033 : /*Interpr�tation du BIFF4  0409 H*/
602             C2F(mgetnc) (fd, (void*)&Version, &one, typ_short, err);
603             if (*err > 0)
604             {
605                 return;
606             }
607             C2F(mgetnc) (fd, (void*)&DataType, &one, typ_short, err);
608             if (*err > 0)
609             {
610                 return;
611             }
612             BIFF = 4;
613             break;
614         case 521 : /*Interpr�tation du BIFF3  0209 H*/
615             C2F(mgetnc) (fd, (void*)&Version, &one, typ_short, err);
616             if (*err > 0)
617             {
618                 return;
619             }
620             C2F(mgetnc) (fd, (void*)&DataType, &one, typ_short, err);
621             if (*err > 0)
622             {
623                 return;
624             }
625             BIFF = 3;
626             break;
627         case 9 : /*Interpr�tation du BIFF2  0009 H*/
628             C2F(mgetnc) (fd, (void*)&Version, &one, typ_short, err);
629             if (*err > 0)
630             {
631                 return;
632             }
633             C2F(mgetnc) (fd, (void*)&DataType, &one, typ_short, err);
634             if (*err > 0)
635             {
636                 return;
637             }
638             BIFF = 2;
639             break;
640         default:
641             BIFF = -1; /* not a BOF record */
642             Version = 0;
643             DataType = 0;
644     }
645     Data[0] = BIFF;
646     Data[1] = Version;
647     Data[2] = DataType;
648     Data[3] = Identifier;
649     Data[4] = Year;
650     Data[5] = HistoryFlags;
651     Data[6] = LowestXlsVersion;
652
653 }
654
655 static void getSST(int *fd, short Len, int BIFF, int *ns, char ***sst, int *err)
656 {
657     int i = 0, one = 1;
658     /* SST data */
659     int ntot = 0; /*total number of strings */
660     int nm = 0;/*Number of following strings*/
661     short count = 0;
662
663     *ns = 0;
664     *sst = NULL;
665
666     if (BIFF == 8)
667     {
668         /*Total number of strings in the workbook*/
669         C2F(mgetnc) (fd, (void*)&ntot, &one, typ_int, err);
670         if (*err > 0)
671         {
672             goto ErrL;
673         }
674         C2F(mgetnc) (fd, (void*)&nm, &one, typ_int, err);
675         if (*err > 0)
676         {
677             goto ErrL;
678         }
679         *ns = nm;
680         count += 8;
681         if (nm != 0)
682         {
683             if ( (*sst = (char **)MALLOC(nm * sizeof(char*))) == NULL)
684             {
685                 goto ErrL;
686             }
687             for (i = 0; i < nm; i++)
688             {
689                 (*sst)[i] = NULL;
690             }
691             for (i = 0; i < nm; i++) /* LOOP ON STRINGS */
692             {
693                 *err = i; /*for debug*/
694                 getString(fd, &count, &Len, 1, &((*sst)[i]), err);
695                 if (*err > 0)
696                 {
697                     goto ErrL;
698                 }
699                 /*printf("i=%d, %s\n",i,(*sst)[i]);*/
700             }
701         }
702     }
703     return;
704 ErrL:
705     if (*sst != NULL)
706     {
707         for (i = 0; i < nm; i++)
708             if ( (*sst)[i] != NULL )
709             {
710                 FREE((*sst)[i]);
711             }
712         FREE(*sst);
713     }
714
715     if (*err == 0)
716     {
717         *err = 3;    /* malloc problem */
718     }
719     else
720     {
721         *err = 4;    /* read problem */
722     }
723 }
724
725 static void getString(int *fd, short *PosInRecord, short *RecordLen, int flag, char **str, int *err)
726 {
727     short ln = 0;
728     short Opcode = 0;/* to store tag information */
729     int BytesToBeRead = 0, one = 1, strindex = 0;
730     char OptionFlag = 0;
731     int sz = 0; /* for extended string data */
732     short rt = 0;/* for rich string data */
733     int UTFEncoding = 0, extendedString = 0, richString = 0;
734     int j = 0, l1 = 0;
735
736     *str = (char *)NULL;
737     *err = 0;
738     ln = 0;
739
740     /*check for continue tag */
741     if (flag && (*PosInRecord == *RecordLen)) /* data limit encountered */
742     {
743         /*check for continue tag */
744         /*lecture de l'Opcode et de la RecordLen du tag*/
745         C2F(mgetnc) (fd, &Opcode, &one, typ_ushort, err);
746         if ((*err > 0) || (Opcode != 60))
747         {
748             goto ErrL;
749         }
750         C2F(mgetnc) (fd, RecordLen, &one, typ_ushort, err);
751         if (*err > 0)
752         {
753             goto ErrL;
754         }
755         *PosInRecord = 0;
756     }
757
758     /* get the number of characters included in the string (number of bytes or number of couple of bytes) */
759     if (flag)   /* getString called by getSST */
760     {
761         C2F(mgetnc) (fd, (void*)&ln, &one, typ_short, err);
762         if (*err > 0)
763         {
764             goto ErrL;
765         }
766         *PosInRecord += 2;
767     }
768     else   /* getString called by getBoundsheets */
769     {
770         C2F(mgetnc) (fd, (void*)&ln, &one, typ_char, err);
771         if (*err > 0)
772         {
773             goto ErrL;
774         }
775         *PosInRecord += 1;
776     }
777
778     /*get the encoding options */
779     C2F(mgetnc) (fd, (void*)&OptionFlag, &one, typ_char, err);
780     if (*err > 0)
781     {
782         goto ErrL;
783     }
784     *PosInRecord += 1;
785
786     UTFEncoding = (OptionFlag & 0x01) == 1;
787     extendedString = (OptionFlag & 0x04) != 0;
788     richString = (OptionFlag & 0x08) != 0;
789
790     if (richString)   /*richString*/
791     {
792         C2F(mgetnc) (fd, (void*)&rt, &one, typ_short, err);
793         *PosInRecord += 2;
794         if (*err > 0)
795         {
796             goto ErrL;
797         }
798     }
799
800     if (extendedString)  /* extendedString */
801     {
802         C2F(mgetnc) (fd, (void*)&sz, &one, typ_int, err);
803         if (*err > 0)
804         {
805             goto ErrL;
806         }
807         *PosInRecord += 4;
808     }
809
810     /* number of bytes to be read */
811     BytesToBeRead = (UTFEncoding) ? ln * 2 : ln;
812
813
814     if ((*str = (char*) MALLOC((BytesToBeRead + 1) * sizeof(char))) == NULL)
815     {
816         goto ErrL;
817     }
818     /* read the bytes */
819
820     if (!flag || (*PosInRecord + BytesToBeRead <= *RecordLen))
821     {
822         /* all bytes are in the same record */
823         C2F(mgetnc) (fd, (void*)*str, &BytesToBeRead, typ_char, err);
824         if (*err > 0)
825         {
826             goto ErrL;
827         }
828         *PosInRecord += (short)BytesToBeRead;
829     }
830     else  /* char stream contains at least one "continue" */
831     {
832         int bytesRead = *RecordLen - *PosInRecord; /* number of bytes before continue */
833         strindex = 0; /*current position in str*/
834         /* read bytes before the "continue"  */
835         /* according to documentation  bytesRead should be strictly positive */
836         C2F(mgetnc) (fd, (void*)(*str + strindex), &bytesRead, typ_char, err);
837         if (*err > 0)
838         {
839             goto ErrL;
840         }
841         strindex += bytesRead;
842         *PosInRecord += (short)bytesRead;
843         while (BytesToBeRead - bytesRead > 0)
844         {
845             /*"continue" tag assumed, verify */
846             C2F(mgetnc) (fd, &Opcode, &one, typ_ushort, err);
847             if ((*err > 0) || (Opcode != 60))
848             {
849                 goto ErrL;
850             }
851             C2F(mgetnc) (fd, RecordLen, &one, typ_ushort, err);
852             if (*err > 0)
853             {
854                 goto ErrL;
855             }
856             *PosInRecord = 0;
857             /* encoding option may change !!!! */
858             C2F(mgetnc) (fd, (void*)&OptionFlag, &one, typ_char, err);
859             if (*err > 0)
860             {
861                 goto ErrL;
862             }
863             *PosInRecord += 1;
864
865             if ((!UTFEncoding && (OptionFlag == 0)) || (UTFEncoding && (OptionFlag != 0)))
866             {
867                 /*string encoding does not change */
868                 l1 = Min(BytesToBeRead - bytesRead, *RecordLen - *PosInRecord);
869                 C2F(mgetnc) (fd, (void*)(*str + strindex), &l1, typ_char, err);
870                 if (*err > 0)
871                 {
872                     goto ErrL;
873                 }
874                 bytesRead += l1;
875                 strindex += l1;
876                 *PosInRecord += (short)l1;
877             }
878             else if (UTFEncoding && (OptionFlag  == 0))
879             {
880                 /* character  encoding changes from twobytes to a single byte*/
881                 /* may this happen ???? */
882                 l1 = Min(BytesToBeRead - bytesRead, *RecordLen - *PosInRecord);
883                 for (j = 0; j < l1; j++)
884                 {
885                     C2F(mgetnc) (fd, (void*)(*str + strindex), &one, typ_char, err);
886                     if (*err > 0)
887                     {
888                         goto ErrL;
889                     }
890                     (*str)[strindex + 1] = '\0';
891                     strindex += 2;
892                     *PosInRecord += 2;
893                     UTFEncoding = 0;
894                 }
895             }
896             else
897             {
898                 /* character encoding changes from a single byte to two bytes */
899                 /* first, convert read characters to two bytes*/
900                 char *str1 = *str;
901                 strindex = 0;
902                 str = (char**) MALLOC((2 * BytesToBeRead + 1) * sizeof(char*));
903                 if (str == NULL)
904                 {
905                     goto ErrL;
906                 }
907                 for (j = 0; j < bytesRead; j++)
908                 {
909                     (*str)[strindex] = str1[j];
910                     (*str)[strindex + 1] = '\0';
911                     strindex += 2;
912                 }
913                 FREE(str1);
914                 BytesToBeRead = BytesToBeRead * 2;
915                 bytesRead = bytesRead * 2;
916                 /* read following two bytes characters */
917                 l1 = Min((BytesToBeRead - bytesRead) * 2, *RecordLen - *PosInRecord);
918                 C2F(mgetnc) (fd, (void*)(*str + strindex), &l1, typ_char, err);
919                 if (*err > 0)
920                 {
921                     goto ErrL;
922                 }
923                 bytesRead += l1;
924                 strindex += l1;
925                 *PosInRecord += (short)l1;
926                 UTFEncoding = 1;
927             }
928
929         }
930
931     } /*all character read */
932
933     /* For extended strings, skip over the extended string data*/
934     /* may continuation records appear here? */
935     l1 = 4 * rt;
936     if (richString)
937     {
938         double dl1 = (double)l1;
939         C2F(mseek) (fd, &dl1, "cur", err);
940         *PosInRecord += (short)l1;
941     }
942     if (extendedString)
943     {
944         double dsz = (double)sz;
945         C2F(mseek) (fd, &dsz, "cur", err);
946         *PosInRecord += (short)sz;
947     }
948
949     /* add string terminaison */
950     if (UTFEncoding)
951     {
952         /* Scilab currently do not support unicode, so we remove the second byte*/
953         strindex = 0;
954         for (j = 0; j < BytesToBeRead; j += 2)
955         {
956             (*str)[strindex] = (*str)[j];
957             strindex++;
958         }
959         BytesToBeRead = BytesToBeRead / 2;
960     }
961     (*str)[BytesToBeRead] = '\0';
962
963
964     return;
965 ErrL:
966     if (*err == 0)
967     {
968         FREE(*str);
969         *err = 3; /* malloc problem */
970     }
971     else
972     {
973         *err = 4;    /* read problem */
974     }
975 }
976
977 static void getBoundsheets(int * fd, char ***Sheetnames, int** Abspos, int *nsheets, double *cur_pos, int *err)
978 {
979     /* the global workbook contains a sequence of boudsheets this procedure reads all
980     * the sequence and returns a vector o sheetnames, a vector of absolute sheet positions*/
981     int abspos; /* Absolute stream position of BoF*/
982     char visibility, sheettype; /*Visiblity , Sheet type*/
983     double pos;
984     unsigned short Opcode;
985     unsigned short Len;
986     int one = 1;
987     int ns, i;
988
989     *Sheetnames = (char **)NULL;
990     *Abspos = (int *)NULL;
991     *err = 0;
992
993     /* memorize the first boundsheet beginning */
994     pos = *cur_pos;
995     /* Count number of boundsheets */
996     ns = 0;
997     while (1)
998     {
999         C2F(mseek) (fd, cur_pos, "set", err);
1000         if (*err > 0)
1001         {
1002             goto ErrL;
1003         }
1004         C2F(mgetnc) (fd, &Opcode, &one, typ_ushort, err);
1005         if (*err > 0)
1006         {
1007             goto ErrL;
1008         }
1009         C2F(mgetnc) (fd, &Len, &one, typ_ushort, err);
1010         if (*err > 0)
1011         {
1012             goto ErrL;
1013         }
1014         if (Opcode == 133)
1015         {
1016             C2F(mgetnc) (fd, (void*)&abspos, &one, typ_int, err);
1017             if (*err > 0)
1018             {
1019                 goto ErrL;
1020             }
1021             C2F(mgetnc) (fd, (void*)&visibility, &one, typ_char, err);
1022             if (*err > 0)
1023             {
1024                 goto ErrL;
1025             }
1026             C2F(mgetnc) (fd, (void*)&sheettype, &one, typ_char, err);
1027             if (sheettype == 0) /* worksheet */
1028             {
1029                 ns++;
1030             }
1031             *cur_pos = *cur_pos + 4 + Len;
1032         }
1033         else
1034         {
1035             break;
1036         }
1037
1038     }
1039
1040     *nsheets = ns;
1041     /*alloc the Sheetnames ans Abspos arrays */
1042     if ( (*Sheetnames = (char **)MALLOC(ns * sizeof(char*))) == NULL)
1043     {
1044         goto ErrL;
1045     }
1046     if ( (*Abspos = (int *)MALLOC(ns * sizeof(int))) == NULL)
1047     {
1048         goto ErrL;
1049     }
1050
1051     /* rescan boundsheet sequence to get the data */
1052     *cur_pos = pos;
1053     i = -1;
1054     while (1)
1055     {
1056         C2F(mseek) (fd, cur_pos, "set", err);
1057         if (*err > 0)
1058         {
1059             goto ErrL;
1060         }
1061         C2F(mgetnc) (fd, &Opcode, &one, typ_ushort, err);
1062         C2F(mgetnc) (fd, &Len, &one, typ_ushort, err);
1063         if (Opcode == 133)
1064         {
1065             C2F(mgetnc) (fd, (void*)&abspos, &one, typ_int, err);
1066             if (*err > 0)
1067             {
1068                 goto ErrL;
1069             }
1070             C2F(mgetnc) (fd, (void*)&visibility, &one, typ_char, err);
1071             if (*err > 0)
1072             {
1073                 goto ErrL;
1074             }
1075             C2F(mgetnc) (fd, (void*)&sheettype, &one, typ_char, err);
1076             if (sheettype == 0) /* worksheet */
1077             {
1078                 short count = 0;
1079                 i++;
1080                 (*Abspos)[i] = abspos;
1081                 getString(fd, &count, (short *) &Len, 0, &((*Sheetnames)[i]), err);
1082                 if (*err > 0)
1083                 {
1084                     goto ErrL;
1085                 }
1086             }
1087             *cur_pos = *cur_pos + 4 + Len;
1088         }
1089         else
1090         {
1091             break;
1092         }
1093
1094     }
1095     return;
1096 ErrL:
1097     if (*Sheetnames != NULL)
1098     {
1099         for (i = 0; i < ns; i++)
1100             if ( (*Sheetnames)[i] != NULL )
1101             {
1102                 FREE((*Sheetnames)[i]);
1103             }
1104         FREE(*Sheetnames);
1105     }
1106     FREE(*Abspos);
1107     if (*err == 0)
1108     {
1109         *err = 3;    /* malloc problem */
1110     }
1111     else
1112     {
1113         *err = 4;    /* read problem */
1114     }
1115 }
1116
1117 /**
1118  ** Bruno : Defined but not used... so what !!!!!!!!!
1119  **
1120  static int get_oleheader(int *fd)
1121  {
1122  unsigned char MAGIC[8] = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
1123  unsigned char header[512];
1124  int c,ierr;
1125
1126  C2F(mgetnc) (fd, (void *)header,(c=512,&c), typ_uchar, &ierr);
1127  if (ierr !=0)  return 1;
1128  if (memcmp (header, MAGIC, sizeof (MAGIC)) != 0) return 1;
1129  return 0;
1130  }
1131 **/