* Bug #15034 fixed : Unable to create a structure using mlist.
[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     std::string str;
96
97     if (1)
98     {
99         bool lineReach = false;
100         std::string previous;
101         size_t offset = 0;
102         while (lst.size() < iLineCount && ifs.eof() == false)
103         {
104             int delimiter_size = 1;
105             size_t sp = previous.size();
106 #define MAX_READ_LEN 262144
107             char buf[MAX_READ_LEN + 1] = {0};
108             ifs.read(buf, MAX_READ_LEN);
109             size_t s = strlen(buf);
110             //extract lines
111             char* ptr = buf;
112             for (int i = 0; i < s; ++i)
113             {
114                 if (buf[i] == '\n')
115                 {
116                     //delimit line
117                     buf[i] = '\0';
118                     if(buf[i - 1] == '\r')
119                     {
120                         buf[i - 1] = '\0';
121                         delimiter_size = 2;
122                     }
123
124                     //add line to list
125                     if (sp)
126                     {
127                         previous += ptr;
128                         lst.push_back(previous);
129 #ifdef _MSC_VER
130                         offset += previous.size() + 2;
131 #else
132                         offset += previous.size() + delimiter_size;
133 #endif
134                         previous.clear();
135                     }
136                     else
137                     {
138                         lst.emplace_back(ptr);
139 #ifdef _MSC_VER
140                         offset += strlen(ptr) + 2;
141 #else
142                         offset += strlen(ptr) + delimiter_size;
143 #endif
144                     }
145
146                     //move ptr to first next line char
147                     ptr = buf + i + 1;
148
149                     if (iLineCount != -1 && lst.size() >= iLineCount)
150                     {
151                         //rewind
152 #ifndef _MSC_VER
153                         auto t = ifs.tellg();
154 #else
155                         std::fpos_t t = ifs.tellg().seekpos();
156 #endif
157                         if (t <= 0)
158                         {
159                             ifs.clear();
160                         }
161
162                         ifs.seekg(orig + offset, std::ios::beg);
163                         lineReach = true;
164                         break;
165                     }
166                 }
167             }
168
169             if (ptr == buf)
170             {
171                 //long line
172                 previous += buf;
173             }
174             else if (lineReach == false)
175             {
176                 int offset = (int)(buf + s - ptr);
177                 if (offset)
178                 {
179                     if (!ifs.eof())
180                     {
181                         //some data stay in buf, rewind file to begin of this data and read it again
182                         ifs.seekg(-offset, std::ios::cur);
183                     }
184                     else
185                     {
186                         //some data stay in buf but oef is reached, add ptr data in list
187                         std::string str(ptr);
188                         lst.push_back(str);
189                     }
190                 }
191             }
192         }
193     }
194     else
195     {
196         while (lst.size() < iLineCount && std::getline(ifs, str))
197         {
198             lst.push_back(str);
199         }
200     }
201
202     int nbLinesOut = (int)lst.size();
203     if (nbLinesOut == 0)
204     {
205         return 0;
206     }
207
208     *pwstLines = (wchar_t**)MALLOC(nbLinesOut * sizeof(wchar_t**));
209     if (*pwstLines == NULL)
210     {
211         return -1;
212     }
213
214     for (int i = 0; i < nbLinesOut; ++i)
215     {
216         std::string s = lst.front();
217         (*pwstLines)[i] = to_wide_string(s.data());
218         lst.pop_front();
219     }
220
221 #ifndef _MSC_VER
222     auto pos = ifs.tellg();
223     fseek(fd, pos, SEEK_SET);
224     ifs.close();
225 #endif
226
227     return nbLinesOut;
228 }