c1cf6e1a270938a3be7ba815f3c2bf98895a5e37
[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                         //reset error flags
157                         ifs.clear();
158                     }
159
160                     ifs.seekg(orig + offset, std::ios::beg);
161                     lineReach = true;
162                     break;
163                 }
164             }
165         }
166
167         if (ptr == buf)
168         {
169             //long line
170             previous += buf;
171         }
172         else if (lineReach == false)
173         {
174             int offset = (int)(buf + s - ptr);
175             if (offset)
176             {
177                 if (!ifs.eof())
178                 {
179                     //some data stay in buf, rewind file to begin of this data and read it again
180 #ifndef _MSC_VER
181                     auto cur1 = ifs.tellg();
182 #else
183                     std::fpos_t cur1 = ifs.tellg().seekpos();
184 #endif
185                     ifs.seekg((std::streamoff)cur1 - offset, std::ios::beg);
186                 }
187                 else
188                 {
189                     //some data stay in buf but oef is reached, add ptr data in list
190                     std::string str(ptr);
191                     lst.push_back(str);
192                 }
193             }
194         }
195     }
196
197     if (previous.size())
198     {
199         lst.push_back(previous);
200         previous.clear();
201     }
202
203     int nbLinesOut = (int)lst.size();
204     if (nbLinesOut == 0)
205     {
206         return 0;
207     }
208
209     *pwstLines = (wchar_t**)MALLOC(nbLinesOut * sizeof(wchar_t**));
210     if (*pwstLines == NULL)
211     {
212         return -1;
213     }
214
215     for (int i = 0; i < nbLinesOut; ++i)
216     {
217         std::string s = lst.front();
218         (*pwstLines)[i] = to_wide_string(s.data());
219         lst.pop_front();
220     }
221
222 #ifndef _MSC_VER
223     auto pos = ifs.tellg();
224     if (pos == -1)
225     {
226         fseek(fd, 0, SEEK_END);
227     }
228     else
229     {
230         fseek(fd, pos, SEEK_SET);
231     }
232     ifs.close();
233 #endif
234
235     return nbLinesOut;
236 }