Mercurial > projects > hoofbaby
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 |