1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 16 июн. 2018 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <errno.h> 23 #include <core/io/charset.h> 24 #include <core/io/StdioFile.h> 25 #include <core/io/NativeFile.h> 26 #include <core/io/InFileStream.h> 27 #include <core/io/InSequence.h> 28 29 #define CBUF_SIZE 0x1000 30 #define BBUF_SIZE 0x4000 31 32 namespace lsp 33 { 34 namespace io 35 { InSequence()36 InSequence::InSequence() 37 { 38 pIS = NULL; 39 nWrapFlags = 0; 40 } 41 ~InSequence()42 InSequence::~InSequence() 43 { 44 // Close file descriptor 45 if (pIS != NULL) 46 { 47 if (nWrapFlags & WRAP_CLOSE) 48 pIS->close(); 49 if (nWrapFlags & WRAP_DELETE) 50 delete pIS; 51 pIS = NULL; 52 } 53 nWrapFlags = 0; 54 55 // Close decoder 56 sDecoder.close(); 57 } 58 close()59 status_t InSequence::close() 60 { 61 status_t res = STATUS_OK; 62 63 // Close file descriptor 64 if (pIS != NULL) 65 { 66 if (nWrapFlags & WRAP_CLOSE) 67 res = pIS->close(); 68 if (nWrapFlags & WRAP_DELETE) 69 delete pIS; 70 pIS = NULL; 71 } 72 nWrapFlags = 0; 73 74 // Close decoder 75 sDecoder.close(); 76 77 // Return result 78 return set_error(res); 79 } 80 wrap(FILE * fd,bool close,const char * charset)81 status_t InSequence::wrap(FILE *fd, bool close, const char *charset) 82 { 83 if (pIS != NULL) 84 return set_error(STATUS_BAD_STATE); 85 else if (fd == NULL) 86 return set_error(STATUS_BAD_ARGUMENTS); 87 88 // Create input file stream 89 InFileStream *is = new InFileStream(); 90 status_t res = is->wrap(fd, close); 91 if (res != STATUS_OK) 92 { 93 is->close(); 94 delete is; 95 return set_error(res); 96 } 97 98 // Wrap input file stream 99 res = wrap(is, WRAP_CLOSE | WRAP_DELETE, charset); 100 if (res != STATUS_OK) 101 { 102 is->close(); 103 delete is; 104 return set_error(res); 105 } 106 107 return set_error(res); 108 } 109 wrap_native(lsp_fhandle_t fd,bool close,const char * charset)110 status_t InSequence::wrap_native(lsp_fhandle_t fd, bool close, const char *charset) 111 { 112 if (pIS != NULL) 113 return set_error(STATUS_BAD_STATE); 114 115 // Create input file stream 116 InFileStream *is = new InFileStream(); 117 status_t res = is->wrap_native(fd, close); 118 if (res != STATUS_OK) 119 { 120 is->close(); 121 delete is; 122 return set_error(res); 123 } 124 125 // Wrap input file stream 126 res = wrap(is, WRAP_CLOSE | WRAP_DELETE, charset); 127 if (res != STATUS_OK) 128 { 129 is->close(); 130 delete is; 131 return set_error(res); 132 } 133 134 return set_error(res); 135 } 136 wrap(File * fd,size_t flags,const char * charset)137 status_t InSequence::wrap(File *fd, size_t flags, const char *charset) 138 { 139 if (pIS != NULL) 140 return set_error(STATUS_BAD_STATE); 141 else if (fd == NULL) 142 return set_error(STATUS_BAD_ARGUMENTS); 143 144 // Create input file stream 145 InFileStream *is = new InFileStream(); 146 status_t res = is->wrap(fd, flags); 147 if (res != STATUS_OK) 148 { 149 is->close(); 150 delete is; 151 return set_error(res); 152 } 153 154 // Wrap input file stream 155 res = wrap(is, WRAP_CLOSE | WRAP_DELETE, charset); 156 if (res != STATUS_OK) 157 { 158 is->close(); 159 delete is; 160 return set_error(res); 161 } 162 163 return set_error(res); 164 } 165 wrap(IInStream * is,size_t flags,const char * charset)166 status_t InSequence::wrap(IInStream *is, size_t flags, const char *charset) 167 { 168 if (pIS != NULL) 169 return set_error(STATUS_BAD_STATE); 170 else if (is == NULL) 171 return set_error(STATUS_BAD_ARGUMENTS); 172 173 // Initialize decoder 174 status_t res = sDecoder.init(charset); 175 if (res != STATUS_OK) 176 { 177 sDecoder.close(); 178 return set_error(res); 179 } 180 181 // Store pointers 182 pIS = is; 183 nWrapFlags = flags; 184 185 return set_error(STATUS_OK); 186 } 187 open(const char * path,const char * charset)188 status_t InSequence::open(const char *path, const char *charset) 189 { 190 if (pIS != NULL) 191 return set_error(STATUS_BAD_STATE); 192 else if (path == NULL) 193 return set_error(STATUS_BAD_ARGUMENTS); 194 195 LSPString tmp; 196 if (!tmp.set_utf8(path)) 197 return set_error(STATUS_NO_MEM); 198 return open(&tmp, charset); 199 } 200 open(const LSPString * path,const char * charset)201 status_t InSequence::open(const LSPString *path, const char *charset) 202 { 203 if (pIS != NULL) 204 return set_error(STATUS_BAD_STATE); 205 else if (path == NULL) 206 return set_error(STATUS_BAD_ARGUMENTS); 207 208 // Create input file stream 209 InFileStream *is = new InFileStream(); 210 status_t res = is->open(path); 211 if (res != STATUS_OK) 212 { 213 is->close(); 214 delete is; 215 return set_error(res); 216 } 217 218 // Wrap input file stream 219 res = wrap(is, WRAP_CLOSE | WRAP_DELETE, charset); 220 if (res != STATUS_OK) 221 { 222 is->close(); 223 delete is; 224 return set_error(res); 225 } 226 227 return set_error(res); 228 } 229 open(const Path * path,const char * charset)230 status_t InSequence::open(const Path *path, const char *charset) 231 { 232 return open(path->as_string(), charset); 233 } 234 read(lsp_wchar_t * dst,size_t count)235 ssize_t InSequence::read(lsp_wchar_t *dst, size_t count) 236 { 237 if (pIS == NULL) 238 return -set_error(STATUS_CLOSED); 239 240 // Clear line buffer 241 sLine.clear(); 242 243 size_t n_read = 0; 244 while (n_read < count) 245 { 246 // Try to fetch data 247 ssize_t fetched = sDecoder.fetch(dst, count - n_read); 248 if (fetched > 0) 249 { 250 n_read += fetched; 251 dst += fetched; 252 continue; 253 } 254 255 // No data to fetch? Try to fill buffer 256 ssize_t filled = sDecoder.fill(pIS); 257 if (filled > 0) 258 continue; 259 260 // Nothing to do more? Skip any errors if there was data processed 261 if (n_read > 0) 262 break; 263 264 // Analyze errors 265 if (fetched < 0) 266 return -set_error(-fetched); 267 else if (filled < 0) 268 return -set_error(-filled); 269 270 set_error(STATUS_OK); 271 break; 272 } 273 274 return n_read; 275 } 276 read_internal()277 lsp_swchar_t InSequence::read_internal() 278 { 279 // Try to fetch character 280 lsp_swchar_t ch = sDecoder.fetch(); 281 if (ch < 0) 282 { 283 // Analyze error 284 if (ch != -STATUS_EOF) 285 return -set_error(-ch); 286 287 // No data to fetch? Try to fill buffer 288 ssize_t filled = sDecoder.fill(pIS); 289 if (filled < 0) 290 return -set_error(-filled); 291 else if (filled == 0) 292 return -set_error(STATUS_EOF); 293 294 // Try to fetch character again 295 ch = sDecoder.fetch(); 296 if (ch < 0) 297 return -set_error(-ch); 298 } 299 return ch; 300 } 301 read()302 lsp_swchar_t InSequence::read() 303 { 304 if (pIS == NULL) 305 return -set_error(STATUS_CLOSED); 306 307 // Clear line buffer 308 sLine.clear(); 309 return read_internal(); 310 } 311 read_line(LSPString * s,bool force)312 status_t InSequence::read_line(LSPString *s, bool force) 313 { 314 if (pIS == NULL) 315 return set_error(STATUS_CLOSED); 316 317 while (true) 318 { 319 // Try to fetch character 320 lsp_swchar_t ch = read_internal(); 321 if (ch < 0) 322 { 323 if (ch == -STATUS_EOF) 324 break; 325 return set_error(-ch); 326 } 327 328 // End of line? 329 if (ch == '\n') 330 { 331 if (sLine.last() == '\r') 332 sLine.set_length(sLine.length() - 1); 333 s->take(&sLine); 334 return set_error(STATUS_OK); 335 } 336 337 // Append character 338 if (!sLine.append(lsp_wchar_t(ch))) 339 return set_error(STATUS_NO_MEM); 340 } 341 342 // Check force flag 343 if ((force) && (sLine.length() > 0)) 344 { 345 s->take(&sLine); 346 return set_error(STATUS_OK); 347 } 348 349 return set_error(STATUS_EOF); 350 } 351 skip(size_t count)352 ssize_t InSequence::skip(size_t count) 353 { 354 sLine.clear(); 355 return IInSequence::skip(count); 356 } 357 358 } 359 } /* namespace lsp */ 360