[mgetl] Conditional jump or move depends on uninitialised value(s) fixed
[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 #include <iostream>
19 #include <fstream>
20
21 extern "C"
22 {
23 #include "mgetl.h"
24 #include "freeArrayOfString.h"
25 #include "charEncoding.h"
26 #include "sci_malloc.h"
27 #include "sciprint.h"
28 }
29 #include "filemanager.hxx"
30
31 #include <string.h>
32 #include <stdio.h>
33
34 #ifdef _MSC_VER
35 #include <Windows.h>
36 #endif
37
38 #ifdef BUFFER_SIZE
39 #undef BUFFER_SIZE
40 #endif
41 #define BUFFER_SIZE 4096
42
43 static const unsigned char UTF8_BOM[] = {0xEF, 0xBB, 0xBF, 0x00};
44
45 int mgetl(int iFileID, int iLineCount, wchar_t ***pwstLines)
46 {
47     *pwstLines = NULL;
48
49     // get file descriptor
50     types::File* pFile = FileManager::getFile(iFileID);
51     FILE *fd;
52     if (pFile != NULL)
53     {
54         fd = pFile->getFiledesc();
55     }
56     else
57     {
58         return -1;
59     }
60
61     if (iLineCount == 0)
62     {
63         return 0;
64     }
65
66     // check file is not empty
67     if (ftell(fd) == 0)
68     {
69         char cValues[4] = {0x00, 0x00, 0x00, 0x00};
70         if (fgets(cValues, 4 * sizeof(char), fd) != NULL)
71         {
72             // skip BOM
73             if (strcmp(cValues, (const char*)UTF8_BOM) != 0)
74             {
75                 rewind(fd);
76             }
77         }
78     }
79
80     int orig = ftell(fd);
81
82 #ifndef _MSC_VER
83     //must reopen the file
84     std::wstring wname = pFile->getFilename();
85     char* name = wide_string_to_UTF8(wname.data());
86     std::ifstream ifs(name);
87     FREE(name);
88 #else
89     std::ifstream ifs(fd);
90 #endif
91     //seek to same position
92     ifs.seekg(orig);
93
94     std::list<std::string> lst;
95
96     bool lineReach = false;
97     std::string previous;
98     size_t offset = 0;
99     while (lst.size() < iLineCount && ifs.eof() == false)
100     {
101         int delimiter_size = 1;
102         size_t sp = previous.size();
103 #define MAX_READ_LEN 262144
104         char buf[MAX_READ_LEN + 1] = {0};
105         ifs.read(buf, MAX_READ_LEN);
106         size_t s = strlen(buf);
107         //extract lines
108         char* ptr = buf;
109         for (int i = 0; i < s; ++i)
110         {
111             if (buf[i] == '\n')
112             {
113                 //delimit line
114                 buf[i] = '\0';
115                 if(i > 0 && buf[i - 1] == '\r')
116                 {
117                     buf[i - 1] = '\0';
118                     delimiter_size = 2;
119                 }
120
121                 //add line to list
122                 if (sp)
123                 {
124                     previous += ptr;
125                     lst.push_back(previous);
126 #ifdef _MSC_VER
127                     offset += previous.size() + 2;
128 #else
129                     offset += previous.size() + delimiter_size;
130 #endif
131                     previous.clear();
132                 }
133                 else
134                 {
135                     lst.emplace_back(ptr);
136 #ifdef _MSC_VER
137                     offset += strlen(ptr) + 2;
138 #else
139                     offset += strlen(ptr) + delimiter_size;
140 #endif
141                 }
142
143                 //move ptr to first next line char
144                 ptr = buf + i + 1;
145
146                 if (iLineCount != -1 && lst.size() >= iLineCount)
147                 {
148                     //rewind
149 #ifndef _MSC_VER
150                     auto t = ifs.tellg();
151 #else
152                     std::fpos_t t = ifs.tellg().seekpos();
153 #endif
154                     if (t <= 0)
155                     {
156                         ifs.clear();
157                     }
158
159                     ifs.seekg(orig + offset, std::ios::beg);
160                     lineReach = true;
161                     break;
162                 }
163             }
164         }
165
166         if (ptr == buf)
167         {
168             //long line
169             previous += buf;
170         }
171         else if (lineReach == false)
172         {
173             int offset = (int)(buf + s - ptr);
174             if (offset)
175             {
176                 if (!ifs.eof())
177                 {
178                     //some data stay in buf, rewind file to begin of this data and read it again
179                     ifs.seekg(-offset, std::ios::cur);
180                 }
181                 else
182                 {
183                     //some data stay in buf but oef is reached, add ptr data in list
184                     std::string str(ptr);
185                     lst.push_back(str);
186                 }
187             }
188         }
189     }
190
191     if (previous.size())
192     {
193         lst.push_back(previous);
194         previous.clear();
195     }
196
197     int nbLinesOut = (int)lst.size();
198     if (nbLinesOut == 0)
199     {
200         return 0;
201     }
202
203     *pwstLines = (wchar_t**)MALLOC(nbLinesOut * sizeof(wchar_t**));
204     if (*pwstLines == NULL)
205     {
206         return -1;
207     }
208
209     for (int i = 0; i < nbLinesOut; ++i)
210     {
211         std::string s = lst.front();
212         (*pwstLines)[i] = to_wide_string(s.data());
213         lst.pop_front();
214     }
215
216 #ifndef _MSC_VER
217     auto pos = ifs.tellg();
218     fseek(fd, pos, SEEK_SET);
219     ifs.close();
220 #endif
221
222     return nbLinesOut;
223 }