57cc4a47d2af99fb1046293a992fd2c1cbfcad44
[scilab.git] / scilab / modules / fileio / src / cpp / mgetl.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2010 - DIGITEO - Allan CORNET
4 * Copyright (C) 2010 - DIGITEO - Antoine ELIAS
5 *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14 *
15 */
16 /*--------------------------------------------------------------------------*/
17
18 extern "C"
19 {
20 #include "mgetl.h"
21 #include "freeArrayOfString.h"
22 #include "charEncoding.h"
23 #include "sci_malloc.h"
24 }
25 #include "filemanager.hxx"
26
27 #include <string.h>
28 #include <stdio.h>
29
30 #ifdef _MSC_VER
31 #include <Windows.h>
32 #endif
33
34 #ifdef BUFFER_SIZE
35 #undef BUFFER_SIZE
36 #endif
37 #define BUFFER_SIZE 4096
38
39 static const char UTF8_BOM[] = { 0xEF, 0xBB, 0xBF, 0x00 };
40
41 int mgetl(int iFileID, int iLineCount, wchar_t ***pwstLines)
42 {
43     *pwstLines = NULL;
44
45     // get file descriptor
46     types::File* pFile = FileManager::getFile(iFileID);
47     FILE *fd;
48     if (pFile != NULL)
49     {
50         fd = pFile->getFiledesc();
51     }
52     else
53     {
54         return -1;
55     }
56
57     if (iLineCount == 0)
58     {
59         return 0;
60     }
61
62     // check file is not empty
63     if (ftell(fd) == 0)
64     {
65         char cValues[4] = { 0x00, 0x00, 0x00, 0x00 };
66         if (fgets(cValues, 4 * sizeof(char), fd) != NULL)
67         {
68             // skip BOM
69             if (strcmp(cValues, UTF8_BOM) != 0)
70             {
71                 rewind(fd);
72             }
73         }
74     }
75
76     if (iLineCount > 0)
77     {
78         *pwstLines = (wchar_t**)MALLOC(iLineCount * sizeof(wchar_t*));
79         if (pwstLines == NULL)
80         {
81             return -1;
82         }
83     }
84
85     // allocate initial reading buffer, it will grow depending on line size
86     int iBufferSize = BUFFER_SIZE;
87     char *pstBuffer = (char *) malloc(iBufferSize * sizeof(char));
88     if (pstBuffer == NULL)
89     {
90         freeArrayOfWideString(*pwstLines, iLineCount);
91         *pwstLines = NULL;
92         return -1;
93     }
94
95     int iReadLineCount = 0;
96     while (fgets(pstBuffer, iBufferSize * sizeof(char), fd) != NULL)
97     {
98         iReadLineCount++;
99         *pwstLines = (wchar_t**)REALLOC(*pwstLines, iReadLineCount * sizeof(wchar_t*));
100         if (*pwstLines == NULL)
101         {
102             free(pstBuffer);
103             return -1;
104         }
105
106         // is the line complete in the buffer (= zero terminal found) ?
107         int len = strnlen(pstBuffer, iBufferSize);
108         int totalLen = len;
109         if (len >= iBufferSize - 1)
110         {
111             // no, there is another data to read for this line
112             // allocate a temporary buffer for reading it
113             char *pstBufferTmp = (char*) malloc(BUFFER_SIZE * sizeof(char));
114             if (pstBufferTmp == NULL)
115             {
116                 freeArrayOfWideString(*pwstLines, iReadLineCount);
117                 *pwstLines = NULL;
118                 free(pstBuffer);
119                 return -1;
120             }
121             char *pstNewBuffer = pstBuffer;
122             // loop until line is complete
123             do
124             {
125                 // reallocate a new bigger buffer for the line
126                 iBufferSize += BUFFER_SIZE;
127                 pstNewBuffer = (char*) REALLOC(pstNewBuffer, iBufferSize * sizeof(char));
128                 if (pstNewBuffer == NULL)
129                 {
130                     freeArrayOfWideString(*pwstLines, iReadLineCount);
131                     *pwstLines = NULL;
132                     free(pstBufferTmp);
133                     return -1;
134                 }
135
136                 // read the remaining data and copy it in the new buffer
137                 if (fgets(pstBufferTmp, BUFFER_SIZE * sizeof(char), fd) != NULL)
138                 {
139                     len = strnlen(pstBufferTmp, BUFFER_SIZE);
140                     totalLen += len;
141                     strncat(pstNewBuffer, pstBufferTmp, BUFFER_SIZE);
142                 }
143                 else
144                 {
145                     break;
146                 }
147             }
148             while (len >= BUFFER_SIZE - 1);
149
150             free(pstBufferTmp);
151             // the bigger buffer becomes the current buffer
152             pstBuffer = pstNewBuffer;
153         }
154         if ((totalLen > 0) && (pstBuffer[totalLen - 1] == '\n'))
155         {
156             pstBuffer[totalLen - 1] = '\0';
157             if ((totalLen > 1) && (pstBuffer[totalLen - 2] == '\r'))
158             {
159                 pstBuffer[totalLen - 2] = '\0';
160             }
161         }
162         // add the line in the array
163         (*pwstLines)[iReadLineCount - 1] = to_wide_string(pstBuffer);
164
165         if ((iLineCount > 0) && (iReadLineCount >= iLineCount))
166         {
167             break;
168         }
169     }
170
171     free(pstBuffer);
172     return iReadLineCount;
173 }
174