comparison deps/Platinum/ThirdParty/Neptune/Source/System/StdC/NptStdcFile.cpp @ 0:3425707ddbf6

Initial import (hopefully this mercurial stuff works...)
author fraserofthenight
date Mon, 06 Jul 2009 08:06:28 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3425707ddbf6
1 /*****************************************************************
2 |
3 | Neptune - Files :: Standard C Implementation
4 |
5 | (c) 2001-2008 Gilles Boccon-Gibod
6 | Author: Gilles Boccon-Gibod (bok@bok.net)
7 |
8 ****************************************************************/
9
10 /*----------------------------------------------------------------------
11 | includes
12 +---------------------------------------------------------------------*/
13 #define _LARGEFILE_SOURCE
14 #define _LARGEFILE_SOURCE64
15 #define _FILE_OFFSET_BITS 64
16
17 #include <stdio.h>
18 #if !defined(_WIN32_WCE)
19 #include <string.h>
20 #include <sys/stat.h>
21 #include <errno.h>
22 #else
23 #include <stdio.h>
24 #define errno GetLastError()
25 #endif
26
27 #include "NptConfig.h"
28 #include "NptUtils.h"
29 #include "NptFile.h"
30 #include "NptThreads.h"
31 #include "NptInterfaces.h"
32 #include "NptStrings.h"
33 #include "NptLogging.h"
34
35 #if defined(NPT_CONFIG_HAVE_SHARE_H)
36 #include <share.h>
37 #endif
38
39 #if defined(_MSC_VER) && _MSC_VER < 1500
40 extern "C" {
41 __int64 __cdecl _ftelli64(FILE *);
42 int __cdecl _fseeki64(FILE *, __int64, int);
43 }
44 #endif
45
46 #if defined(_WIN32)
47 extern FILE *NPT_fsopen_utf8(const char* path, const char* mode, int sh_flags);
48 extern FILE *NPT_fopen_utf8(const char* path, const char* mode);
49 #define fopen NPT_fopen_utf8
50 #define fopen_s NPT_fopen_s_utf8
51 #define _fsopen NPT_fsopen_utf8
52 #endif
53
54
55 /*----------------------------------------------------------------------
56 | logging
57 +---------------------------------------------------------------------*/
58 NPT_SET_LOCAL_LOGGER("neptune.stdc.file")
59
60 /*----------------------------------------------------------------------
61 | compatibility wrappers
62 +---------------------------------------------------------------------*/
63 #if !defined(NPT_CONFIG_HAVE_FOPEN_S)
64 static int fopen_s(FILE** file,
65 const char* filename,
66 const char* mode)
67 {
68 *file = fopen(filename, mode);
69
70 #if defined(_WIN32_WCE)
71 if (*file == NULL) return ENOENT;
72 #else
73 if (*file == NULL) return errno;
74 #endif
75 return 0;
76 }
77 #endif // defined(NPT_CONFIG_HAVE_FOPEN_S
78
79 /*----------------------------------------------------------------------
80 | MapErrno
81 +---------------------------------------------------------------------*/
82 static NPT_Result
83 MapErrno(int err) {
84 switch (err) {
85 case EACCES: return NPT_ERROR_PERMISSION_DENIED;
86 case EPERM: return NPT_ERROR_PERMISSION_DENIED;
87 case ENOENT: return NPT_ERROR_NO_SUCH_FILE;
88 #if defined(ENAMETOOLONG)
89 case ENAMETOOLONG: return NPT_ERROR_INVALID_PARAMETERS;
90 #endif
91 case EBUSY: return NPT_ERROR_FILE_BUSY;
92 case EROFS: return NPT_ERROR_FILE_NOT_WRITABLE;
93 case ENOTDIR: return NPT_ERROR_FILE_NOT_DIRECTORY;
94 default: return NPT_ERROR_ERRNO(err);
95 }
96 }
97
98 /*----------------------------------------------------------------------
99 | NPT_StdcFileWrapper
100 +---------------------------------------------------------------------*/
101 class NPT_StdcFileWrapper
102 {
103 public:
104 // constructors and destructor
105 NPT_StdcFileWrapper(FILE* file) : m_File(file) {}
106 ~NPT_StdcFileWrapper() {
107 if (m_File != NULL &&
108 m_File != stdin &&
109 m_File != stdout &&
110 m_File != stderr) {
111 fclose(m_File);
112 }
113 }
114
115 // methods
116 FILE* GetFile() { return m_File; }
117
118 private:
119 // members
120 FILE* m_File;
121 };
122
123 typedef NPT_Reference<NPT_StdcFileWrapper> NPT_StdcFileReference;
124
125 /*----------------------------------------------------------------------
126 | NPT_StdcFileStream
127 +---------------------------------------------------------------------*/
128 class NPT_StdcFileStream
129 {
130 public:
131 // constructors and destructor
132 NPT_StdcFileStream(NPT_StdcFileReference file) :
133 m_FileReference(file) {}
134
135 // NPT_FileInterface methods
136 NPT_Result Seek(NPT_Position offset);
137 NPT_Result Tell(NPT_Position& offset);
138 NPT_Result Flush();
139
140 protected:
141 // constructors and destructors
142 virtual ~NPT_StdcFileStream() {}
143
144 // members
145 NPT_StdcFileReference m_FileReference;
146 };
147
148 /*----------------------------------------------------------------------
149 | NPT_StdcFileStream::Seek
150 +---------------------------------------------------------------------*/
151 NPT_Result
152 NPT_StdcFileStream::Seek(NPT_Position offset)
153 {
154 size_t result;
155
156 result = NPT_fseek(m_FileReference->GetFile(), offset, SEEK_SET);
157 if (result == 0) {
158 return NPT_SUCCESS;
159 } else {
160 return NPT_FAILURE;
161 }
162 }
163
164 /*----------------------------------------------------------------------
165 | NPT_StdcFileStream::Tell
166 +---------------------------------------------------------------------*/
167 NPT_Result
168 NPT_StdcFileStream::Tell(NPT_Position& offset)
169 {
170 offset = 0;
171
172 NPT_Int64 pos = NPT_ftell(m_FileReference->GetFile());
173 if (pos <=0) return NPT_FAILURE;
174
175 offset = pos;
176 return NPT_SUCCESS;
177 }
178
179 /*----------------------------------------------------------------------
180 | NPT_StdcFileStream::Flush
181 +---------------------------------------------------------------------*/
182 NPT_Result
183 NPT_StdcFileStream::Flush()
184 {
185 fflush(m_FileReference->GetFile());
186 return NPT_SUCCESS;
187 }
188
189 /*----------------------------------------------------------------------
190 | NPT_StdcFileInputStream
191 +---------------------------------------------------------------------*/
192 class NPT_StdcFileInputStream : public NPT_InputStream,
193 private NPT_StdcFileStream
194
195 {
196 public:
197 // constructors and destructor
198 NPT_StdcFileInputStream(NPT_StdcFileReference& file, NPT_LargeSize size) :
199 NPT_StdcFileStream(file), m_Size(size) {}
200
201 // NPT_InputStream methods
202 NPT_Result Read(void* buffer,
203 NPT_Size bytes_to_read,
204 NPT_Size* bytes_read);
205 NPT_Result Seek(NPT_Position offset) {
206 return NPT_StdcFileStream::Seek(offset);
207 }
208 NPT_Result Tell(NPT_Position& offset) {
209 return NPT_StdcFileStream::Tell(offset);
210 }
211 NPT_Result GetSize(NPT_LargeSize& size);
212 NPT_Result GetAvailable(NPT_LargeSize& available);
213
214 private:
215 // members
216 NPT_LargeSize m_Size;
217 };
218
219 /*----------------------------------------------------------------------
220 | NPT_StdcFileInputStream::Read
221 +---------------------------------------------------------------------*/
222 NPT_Result
223 NPT_StdcFileInputStream::Read(void* buffer,
224 NPT_Size bytes_to_read,
225 NPT_Size* bytes_read)
226 {
227 size_t nb_read;
228
229 // check the parameters
230 if (buffer == NULL) {
231 return NPT_ERROR_INVALID_PARAMETERS;
232 }
233
234 // read from the file
235 nb_read = fread(buffer, 1, bytes_to_read, m_FileReference->GetFile());
236 if (nb_read > 0) {
237 if (bytes_read) *bytes_read = (NPT_Size)nb_read;
238 return NPT_SUCCESS;
239 } else if (feof(m_FileReference->GetFile())) {
240 if (bytes_read) *bytes_read = 0;
241 return NPT_ERROR_EOS;
242 } else {
243 if (bytes_read) *bytes_read = 0;
244 return NPT_ERROR_READ_FAILED;
245 }
246 }
247
248 /*----------------------------------------------------------------------
249 | NPT_StdcFileInputStream::GetSize
250 +---------------------------------------------------------------------*/
251 NPT_Result
252 NPT_StdcFileInputStream::GetSize(NPT_LargeSize& size)
253 {
254 // keep track of where we are
255 NPT_Position offset = NPT_ftell(m_FileReference->GetFile());
256
257 // seek to the end to get the size
258 NPT_fseek(m_FileReference->GetFile(), 0, SEEK_END);
259 size = NPT_ftell(m_FileReference->GetFile());
260
261 // seek back to where we were
262 NPT_fseek(m_FileReference->GetFile(), offset, SEEK_SET);
263 return NPT_SUCCESS;
264 }
265
266 /*----------------------------------------------------------------------
267 | NPT_StdcFileInputStream::GetAvailable
268 +---------------------------------------------------------------------*/
269 NPT_Result
270 NPT_StdcFileInputStream::GetAvailable(NPT_LargeSize& available)
271 {
272 NPT_LargeSize size;
273 GetSize(size);
274
275 NPT_Int64 offset = NPT_ftell(m_FileReference->GetFile());
276 if (offset >= 0 && (NPT_LargeSize)offset <= size) {
277 available = size - offset;
278 return NPT_SUCCESS;
279 } else {
280 available = 0;
281 return NPT_FAILURE;
282 }
283 }
284
285 /*----------------------------------------------------------------------
286 | NPT_StdcFileOutputStream
287 +---------------------------------------------------------------------*/
288 class NPT_StdcFileOutputStream : public NPT_OutputStream,
289 private NPT_StdcFileStream
290 {
291 public:
292 // constructors and destructor
293 NPT_StdcFileOutputStream(NPT_StdcFileReference& file) :
294 NPT_StdcFileStream(file) {}
295
296 // NPT_InputStream methods
297 NPT_Result Write(const void* buffer,
298 NPT_Size bytes_to_write,
299 NPT_Size* bytes_written);
300 NPT_Result Seek(NPT_Position offset) {
301 return NPT_StdcFileStream::Seek(offset);
302 }
303 NPT_Result Tell(NPT_Position& offset) {
304 return NPT_StdcFileStream::Tell(offset);
305 }
306 NPT_Result Flush() {
307 return NPT_StdcFileStream::Flush();
308 }
309 };
310
311 /*----------------------------------------------------------------------
312 | NPT_StdcFileOutputStream::Write
313 +---------------------------------------------------------------------*/
314 NPT_Result
315 NPT_StdcFileOutputStream::Write(const void* buffer,
316 NPT_Size bytes_to_write,
317 NPT_Size* bytes_written)
318 {
319 size_t nb_written;
320
321 nb_written = fwrite(buffer, 1, bytes_to_write, m_FileReference->GetFile());
322
323 if (nb_written > 0) {
324 if (bytes_written) *bytes_written = (NPT_Size)nb_written;
325 return NPT_SUCCESS;
326 } else {
327 if (bytes_written) *bytes_written = 0;
328 return NPT_ERROR_WRITE_FAILED;
329 }
330 }
331
332 /*----------------------------------------------------------------------
333 | NPT_StdcFile
334 +---------------------------------------------------------------------*/
335 class NPT_StdcFile: public NPT_FileInterface
336 {
337 public:
338 // constructors and destructor
339 NPT_StdcFile(NPT_File& delegator);
340 ~NPT_StdcFile();
341
342 // NPT_FileInterface methods
343 NPT_Result Open(OpenMode mode);
344 NPT_Result Close();
345 NPT_Result GetSize(NPT_LargeSize& size);
346 NPT_Result GetInputStream(NPT_InputStreamReference& stream);
347 NPT_Result GetOutputStream(NPT_OutputStreamReference& stream);
348
349 private:
350 // members
351 NPT_File& m_Delegator;
352 OpenMode m_Mode;
353 NPT_StdcFileReference m_FileReference;
354 };
355
356 /*----------------------------------------------------------------------
357 | NPT_StdcFile::NPT_StdcFile
358 +---------------------------------------------------------------------*/
359 NPT_StdcFile::NPT_StdcFile(NPT_File& delegator) :
360 m_Delegator(delegator),
361 m_Mode(0)
362 {
363 }
364
365 /*----------------------------------------------------------------------
366 | NPT_StdcFile::~NPT_StdcFile
367 +---------------------------------------------------------------------*/
368 NPT_StdcFile::~NPT_StdcFile()
369 {
370 Close();
371 }
372
373 /*----------------------------------------------------------------------
374 | NPT_StdcFile::Open
375 +---------------------------------------------------------------------*/
376 NPT_Result
377 NPT_StdcFile::Open(NPT_File::OpenMode mode)
378 {
379 FILE* file = NULL;
380
381 // check if we're already open
382 if (!m_FileReference.IsNull()) {
383 return NPT_ERROR_FILE_ALREADY_OPEN;
384 }
385
386 // store the mode
387 m_Mode = mode;
388
389 // check for special names
390 const char* name = (const char*)m_Delegator.GetPath();
391 if (NPT_StringsEqual(name, NPT_FILE_STANDARD_INPUT)) {
392 file = stdin;
393 } else if (NPT_StringsEqual(name, NPT_FILE_STANDARD_OUTPUT)) {
394 file = stdout;
395 } else if (NPT_StringsEqual(name, NPT_FILE_STANDARD_ERROR)) {
396 file = stderr;
397 } else {
398 // compute mode
399 const char* fmode = "";
400 if (mode & NPT_FILE_OPEN_MODE_WRITE) {
401 if (mode & NPT_FILE_OPEN_MODE_CREATE) {
402 if (mode & NPT_FILE_OPEN_MODE_TRUNCATE) {
403 /* write, read, create, truncate */
404 fmode = "w+b";
405 } else {
406 /* write, read, create */
407 fmode = "a+b";
408 }
409 } else {
410 if (mode & NPT_FILE_OPEN_MODE_TRUNCATE) {
411 /* write, read, truncate */
412 fmode = "w+b";
413 } else {
414 /* write, read */
415 fmode = "r+b";
416 }
417 }
418 } else {
419 /* read only */
420 fmode = "rb";
421 }
422
423 // open the file
424 #if defined(NPT_CONFIG_HAVE_FSOPEN)
425 file = _fsopen(name, fmode, _SH_DENYWR);
426 int open_result = file == NULL ? ENOENT : 0;
427 #else
428 int open_result = fopen_s(&file, name, fmode);
429 #endif
430
431 // test the result of the open
432 if (open_result != 0) return MapErrno(errno);
433 }
434
435 // unbuffer the file if needed
436 if ((mode & NPT_FILE_OPEN_MODE_UNBUFFERED) && file != NULL) {
437 #if !defined(_WIN32_WCE)
438 setvbuf(file, NULL, _IONBF, 0);
439 #endif
440 }
441
442 // create a reference to the FILE object
443 m_FileReference = new NPT_StdcFileWrapper(file);
444
445 return NPT_SUCCESS;
446 }
447
448 /*----------------------------------------------------------------------
449 | NPT_StdcFile::Close
450 +---------------------------------------------------------------------*/
451 NPT_Result
452 NPT_StdcFile::Close()
453 {
454 // release the file reference
455 m_FileReference = NULL;
456
457 // reset the mode
458 m_Mode = 0;
459
460 return NPT_SUCCESS;
461 }
462
463 /*----------------------------------------------------------------------
464 | NPT_StdcFile::GetSize
465 +---------------------------------------------------------------------*/
466 NPT_Result
467 NPT_StdcFile::GetSize(NPT_LargeSize& size)
468 {
469 // default value
470 size = 0;
471
472 // check that the file is open
473 if (m_FileReference.IsNull()) return NPT_ERROR_FILE_NOT_OPEN;
474
475 // get the size from the info (call GetInfo() in case it has not
476 // yet been called)
477 NPT_FileInfo info;
478 NPT_CHECK_FATAL(m_Delegator.GetInfo(info));
479 size = info.m_Size;
480 return NPT_SUCCESS;
481 }
482
483 /*----------------------------------------------------------------------
484 | NPT_StdcFile::GetInputStream
485 +---------------------------------------------------------------------*/
486 NPT_Result
487 NPT_StdcFile::GetInputStream(NPT_InputStreamReference& stream)
488 {
489 // default value
490 stream = NULL;
491
492 // check that the file is open
493 if (m_FileReference.IsNull()) return NPT_ERROR_FILE_NOT_OPEN;
494
495 // check that the mode is compatible
496 if (!(m_Mode & NPT_FILE_OPEN_MODE_READ)) {
497 return NPT_ERROR_FILE_NOT_READABLE;
498 }
499
500 // create a stream
501 NPT_LargeSize size = 0;
502 GetSize(size);
503 stream = new NPT_StdcFileInputStream(m_FileReference, size);
504
505 return NPT_SUCCESS;
506 }
507
508 /*----------------------------------------------------------------------
509 | NPT_StdcFile::GetOutputStream
510 +---------------------------------------------------------------------*/
511 NPT_Result
512 NPT_StdcFile::GetOutputStream(NPT_OutputStreamReference& stream)
513 {
514 // default value
515 stream = NULL;
516
517 // check that the file is open
518 if (m_FileReference.IsNull()) return NPT_ERROR_FILE_NOT_OPEN;
519
520 // check that the mode is compatible
521 if (!(m_Mode & NPT_FILE_OPEN_MODE_WRITE)) {
522 return NPT_ERROR_FILE_NOT_WRITABLE;
523 }
524
525 // create a stream
526 stream = new NPT_StdcFileOutputStream(m_FileReference);
527
528 return NPT_SUCCESS;
529 }
530
531 /*----------------------------------------------------------------------
532 | NPT_File::NPT_File
533 +---------------------------------------------------------------------*/
534 NPT_File::NPT_File(const char* path) :
535 m_Path(path)
536 {
537 m_Delegate = new NPT_StdcFile(*this);
538
539 if (NPT_StringsEqual(path, NPT_FILE_STANDARD_INPUT) ||
540 NPT_StringsEqual(path, NPT_FILE_STANDARD_OUTPUT) ||
541 NPT_StringsEqual(path, NPT_FILE_STANDARD_ERROR)) {
542 m_Info.m_Type = NPT_FileInfo::FILE_TYPE_SPECIAL;
543 }
544 }
545
546 /*----------------------------------------------------------------------
547 | NPT_File::operator=
548 +---------------------------------------------------------------------*/
549 NPT_File&
550 NPT_File::operator=(const NPT_File& file)
551 {
552 if (this != &file) {
553 delete m_Delegate;
554 m_Path = file.m_Path;
555 m_Info = file.m_Info;
556 m_Delegate = new NPT_StdcFile(*this);
557 }
558 return *this;
559 }
560