]> git.saurik.com Git - wxWidgets.git/blame - src/common/file.cpp
Add class factories for filter streams. Also filters now follow the convention
[wxWidgets.git] / src / common / file.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: file.cpp
3// Purpose: wxFile - encapsulates low-level "file descriptor"
4// wxTempFile
5// Author: Vadim Zeitlin
6// Modified by:
7// Created: 29/01/98
8// RCS-ID: $Id$
9// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 10// Licence: wxWindows licence
c801d85f
KB
11/////////////////////////////////////////////////////////////////////////////
12
13// ----------------------------------------------------------------------------
14// headers
15// ----------------------------------------------------------------------------
16
c801d85f
KB
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
c801d85f
KB
19
20#ifdef __BORLANDC__
ce4169a4 21 #pragma hdrstop
c801d85f
KB
22#endif
23
ce4169a4
RR
24#if wxUSE_FILE
25
c801d85f 26// standard
1c193821 27#if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
30a5be97 28
a3ef5bf5 29#ifndef __SALFORDC__
49d5d881
VZ
30 #define WIN32_LEAN_AND_MEAN
31 #define NOSERVICE
32 #define NOIME
33 #define NOATOM
34 #define NOGDI
35 #define NOGDICAPMASKS
36 #define NOMETAFILE
37 #define NOMINMAX
38 #define NOMSG
39 #define NOOPENFILE
40 #define NORASTEROPS
41 #define NOSCROLL
42 #define NOSOUND
43 #define NOSYSMETRICS
44 #define NOTEXTMETRIC
45 #define NOWH
46 #define NOCOMM
47 #define NOKANJI
48 #define NOCRYPT
49 #define NOMCX
a3ef5bf5
JS
50#endif
51
1c193821 52#elif defined(__WXMSW__) && defined(__WXWINCE__)
d109c584 53 #include "wx/msw/missing.h"
5a3912f2
SN
54#elif (defined(__OS2__))
55 #include <io.h>
c801d85f 56#elif (defined(__UNIX__) || defined(__GNUWIN32__))
3f4a0c5b 57 #include <unistd.h>
fd938b11 58 #include <time.h>
732b8386 59 #include <sys/stat.h>
3f4a0c5b 60 #ifdef __GNUWIN32__
9ed0d735 61 #include "wx/msw/wrapwin.h"
3f4a0c5b 62 #endif
d3b4d710
VS
63#elif defined(__DOS__)
64 #if defined(__WATCOMC__)
65 #include <io.h>
66 #elif defined(__DJGPP__)
67 #include <io.h>
68 #include <unistd.h>
69 #include <stdio.h>
70 #else
71 #error "Please specify the header with file functions declarations."
72 #endif
34138703 73#elif (defined(__WXSTUBS__))
3f4a0c5b
VZ
74 // Have to ifdef this for different environments
75 #include <io.h>
17dff81c 76#elif (defined(__WXMAC__))
5b781a67 77#if __MSL__ < 0x6000
3f4a0c5b 78 int access( const char *path, int mode ) { return 0 ; }
5b781a67
SC
79#else
80 int _access( const char *path, int mode ) { return 0 ; }
81#endif
3f4a0c5b 82 char* mktemp( char * path ) { return path ;}
5b781a67 83 #include <stat.h>
6294ac2e 84 #include <unistd.h>
c801d85f 85#else
3f4a0c5b 86 #error "Please specify the header with file functions declarations."
c801d85f
KB
87#endif //Win/UNIX
88
89#include <stdio.h> // SEEK_xxx constants
1c193821 90
4ea2c29f
VZ
91// Windows compilers don't have these constants
92#ifndef W_OK
93 enum
94 {
95 F_OK = 0, // test for existence
96 X_OK = 1, // execute permission
97 W_OK = 2, // write
98 R_OK = 4 // read
99 };
100#endif // W_OK
34138703 101
b12915c1
VZ
102// there is no distinction between text and binary files under Unix, so define
103// O_BINARY as 0 if the system headers don't do it already
104#if defined(__UNIX__) && !defined(O_BINARY)
49d5d881 105 #define O_BINARY (0)
246037e2 106#endif //__UNIX__
c801d85f 107
a3ef5bf5 108#ifdef __SALFORDC__
3f4a0c5b 109 #include <unix.h>
a3ef5bf5
JS
110#endif
111
81d66cf3 112#ifndef MAX_PATH
3f4a0c5b 113 #define MAX_PATH 512
81d66cf3 114#endif
c801d85f 115
49d5d881
VZ
116// some broken compilers don't have 3rd argument in open() and creat()
117#ifdef __SALFORDC__
118 #define ACCESS(access)
119 #define stat _stat
120#else // normal compiler
121 #define ACCESS(access) , (access)
122#endif // Salford C
123
77ffb593 124// wxWidgets
ade35f11
VZ
125#ifndef WX_PRECOMP
126 #include "wx/string.h"
127 #include "wx/intl.h"
ade35f11
VZ
128 #include "wx/log.h"
129#endif // !WX_PRECOMP
130
131#include "wx/filename.h"
44d568b6 132#include "wx/file.h"
4ea2c29f 133#include "wx/filefn.h"
f6bcfd97 134
28f5082b
VS
135#ifdef __WXMSW__
136 #include "wx/msw/mslu.h"
137#endif
138
1c193821
JS
139#ifdef __WXWINCE__
140 #include "wx/msw/private.h"
141#endif
142
30984dea 143
c801d85f
KB
144// ============================================================================
145// implementation of wxFile
146// ============================================================================
147
148// ----------------------------------------------------------------------------
149// static functions
150// ----------------------------------------------------------------------------
4ea2c29f 151
50920146 152bool wxFile::Exists(const wxChar *name)
246037e2 153{
4ea2c29f 154 return wxFileExists(name);
d1427b70
VZ
155}
156
50920146 157bool wxFile::Access(const wxChar *name, OpenMode mode)
d1427b70 158{
4ea2c29f
VZ
159 int how;
160
161 switch ( mode )
162 {
163 default:
164 wxFAIL_MSG(wxT("bad wxFile::Access mode parameter."));
165 // fall through
d1427b70 166
49d5d881
VZ
167 case read:
168 how = R_OK;
169 break;
d1427b70 170
49d5d881
VZ
171 case write:
172 how = W_OK;
173 break;
d1427b70 174
4ea2c29f
VZ
175 case read_write:
176 how = R_OK | W_OK;
177 break;
49d5d881 178 }
d1427b70 179
4ea2c29f 180 return wxAccess(name, how) == 0;
c801d85f
KB
181}
182
183// ----------------------------------------------------------------------------
184// opening/closing
185// ----------------------------------------------------------------------------
186
187// ctors
50920146 188wxFile::wxFile(const wxChar *szFileName, OpenMode mode)
c801d85f 189{
49d5d881 190 m_fd = fd_invalid;
a62848fd 191 m_error = false;
c801d85f 192
49d5d881 193 Open(szFileName, mode);
c801d85f
KB
194}
195
c801d85f 196// create the file, fail if it already exists and bOverwrite
50920146 197bool wxFile::Create(const wxChar *szFileName, bool bOverwrite, int accessMode)
c801d85f 198{
49d5d881
VZ
199 // if bOverwrite we create a new file or truncate the existing one,
200 // otherwise we only create the new file and fail if it already exists
c4e41ce3 201#if defined(__WXMAC__) && !defined(__UNIX__) && !wxUSE_UNICODE
92980e90 202 // Dominic Mazzoni [dmazzoni+@cs.cmu.edu] reports that open is still broken on the mac, so we replace
a2b77260 203 // int fd = open( szFileName , O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access);
92980e90 204 int fd = creat( szFileName , accessMode);
7c74e7fe 205#else
92980e90
RR
206 int fd = wxOpen( szFileName,
207 O_BINARY | O_WRONLY | O_CREAT |
208 (bOverwrite ? O_TRUNC : O_EXCL)
209 ACCESS(accessMode) );
7c74e7fe 210#endif
92980e90
RR
211 if ( fd == -1 )
212 {
49d5d881 213 wxLogSysError(_("can't create file '%s'"), szFileName);
a62848fd 214 return false;
49d5d881 215 }
769627d7
DS
216
217 Attach(fd);
218 return true;
c801d85f
KB
219}
220
221// open the file
50920146 222bool wxFile::Open(const wxChar *szFileName, OpenMode mode, int accessMode)
c801d85f 223{
49d5d881 224 int flags = O_BINARY;
c801d85f 225
92980e90
RR
226 switch ( mode )
227 {
49d5d881
VZ
228 case read:
229 flags |= O_RDONLY;
230 break;
c801d85f 231
f6bcfd97
BP
232 case write_append:
233 if ( wxFile::Exists(szFileName) )
234 {
235 flags |= O_WRONLY | O_APPEND;
236 break;
237 }
238 //else: fall through as write_append is the same as write if the
239 // file doesn't exist
240
49d5d881
VZ
241 case write:
242 flags |= O_WRONLY | O_CREAT | O_TRUNC;
243 break;
61b02744 244
68164137
RL
245 case write_excl:
246 flags |= O_WRONLY | O_CREAT | O_EXCL;
247 break;
248
49d5d881
VZ
249 case read_write:
250 flags |= O_RDWR;
251 break;
252 }
c801d85f 253
cc8cc54f
VZ
254#ifdef __WINDOWS__
255 // only read/write bits for "all" are supported by this function under
256 // Windows, and VC++ 8 returns EINVAL if any other bits are used in
257 // accessMode, so clear them as they have at best no effect anyhow
258 accessMode &= wxS_IRUSR | wxS_IWUSR;
259#endif // __WINDOWS__
260
92980e90 261 int fd = wxOpen( szFileName, flags ACCESS(accessMode));
6294ac2e 262
92980e90
RR
263 if ( fd == -1 )
264 {
49d5d881 265 wxLogSysError(_("can't open file '%s'"), szFileName);
a62848fd 266 return false;
49d5d881 267 }
769627d7
DS
268
269 Attach(fd);
270 return true;
c801d85f
KB
271}
272
273// close
61b02744 274bool wxFile::Close()
c801d85f 275{
49d5d881 276 if ( IsOpened() ) {
6294ac2e 277 if (wxClose(m_fd) == -1)
1c193821 278 {
49d5d881
VZ
279 wxLogSysError(_("can't close file descriptor %d"), m_fd);
280 m_fd = fd_invalid;
a62848fd 281 return false;
49d5d881
VZ
282 }
283 else
284 m_fd = fd_invalid;
61b02744 285 }
61b02744 286
a62848fd 287 return true;
c801d85f
KB
288}
289
290// ----------------------------------------------------------------------------
291// read/write
292// ----------------------------------------------------------------------------
293
294// read
f8a586e0 295ssize_t wxFile::Read(void *pBuf, size_t nCount)
c801d85f 296{
49d5d881 297 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
c801d85f 298
30984dea 299 ssize_t iRc = wxRead(m_fd, pBuf, nCount);
6294ac2e 300
30984dea 301 if ( iRc == -1 )
02aef13c 302 {
49d5d881 303 wxLogSysError(_("can't read from file descriptor %d"), m_fd);
f8a586e0 304 return wxInvalidOffset;
49d5d881 305 }
02aef13c
VZ
306
307 return iRc;
c801d85f
KB
308}
309
310// write
30984dea 311size_t wxFile::Write(const void *pBuf, size_t nCount)
c801d85f 312{
49d5d881 313 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
c801d85f 314
30984dea 315 ssize_t iRc = wxWrite(m_fd, pBuf, nCount);
6294ac2e 316
30984dea 317 if ( iRc == -1 )
02aef13c 318 {
49d5d881 319 wxLogSysError(_("can't write to file descriptor %d"), m_fd);
a62848fd 320 m_error = true;
02aef13c 321 iRc = 0;
49d5d881 322 }
02aef13c 323
30984dea 324 return iRc;
c801d85f
KB
325}
326
327// flush
328bool wxFile::Flush()
329{
687809e9 330#if defined(__VISUALC__) || defined(HAVE_FSYNC)
608a34bf
VZ
331 // fsync() only works on disk files and returns errors for pipes, don't
332 // call it then
333 if ( IsOpened() && GetKind() == wxFILE_KIND_DISK )
334 {
f6bcfd97 335 if ( wxFsync(m_fd) == -1 )
09914df7
VZ
336 {
337 wxLogSysError(_("can't flush file descriptor %d"), m_fd);
a62848fd 338 return false;
09914df7 339 }
49d5d881 340 }
608a34bf 341#endif // fsync
c801d85f 342
a62848fd 343 return true;
c801d85f
KB
344}
345
346// ----------------------------------------------------------------------------
347// seek
348// ----------------------------------------------------------------------------
349
350// seek
30984dea 351wxFileOffset wxFile::Seek(wxFileOffset ofs, wxSeekMode mode)
c801d85f 352{
686a3ee0
VZ
353 wxASSERT_MSG( IsOpened(), _T("can't seek on closed file") );
354 wxCHECK_MSG( ofs != wxInvalidOffset || mode != wxFromStart,
355 wxInvalidOffset,
356 _T("invalid absolute file offset") );
49d5d881 357
a1b82138 358 int origin;
49d5d881 359 switch ( mode ) {
a1b82138
VZ
360 default:
361 wxFAIL_MSG(_("unknown seek origin"));
362
49d5d881 363 case wxFromStart:
a1b82138 364 origin = SEEK_SET;
49d5d881
VZ
365 break;
366
367 case wxFromCurrent:
a1b82138 368 origin = SEEK_CUR;
49d5d881
VZ
369 break;
370
371 case wxFromEnd:
a1b82138 372 origin = SEEK_END;
49d5d881 373 break;
49d5d881
VZ
374 }
375
30984dea 376 wxFileOffset iRc = wxSeek(m_fd, ofs, origin);
02aef13c
VZ
377 if ( iRc == wxInvalidOffset )
378 {
49d5d881 379 wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
49d5d881 380 }
02aef13c
VZ
381
382 return iRc;
c801d85f
KB
383}
384
02aef13c 385// get current file offset
30984dea 386wxFileOffset wxFile::Tell() const
c801d85f 387{
49d5d881
VZ
388 wxASSERT( IsOpened() );
389
30984dea 390 wxFileOffset iRc = wxTell(m_fd);
02aef13c
VZ
391 if ( iRc == wxInvalidOffset )
392 {
49d5d881 393 wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
49d5d881 394 }
02aef13c
VZ
395
396 return iRc;
c801d85f
KB
397}
398
399// get current file length
30984dea 400wxFileOffset wxFile::Length() const
c801d85f 401{
49d5d881 402 wxASSERT( IsOpened() );
c801d85f 403
30984dea 404 wxFileOffset iRc = Tell();
02aef13c
VZ
405 if ( iRc != wxInvalidOffset ) {
406 // have to use const_cast :-(
30984dea 407 wxFileOffset iLen = ((wxFile *)this)->SeekEnd();
02aef13c 408 if ( iLen != wxInvalidOffset ) {
49d5d881 409 // restore old position
02aef13c 410 if ( ((wxFile *)this)->Seek(iRc) == wxInvalidOffset ) {
49d5d881 411 // error
02aef13c 412 iLen = wxInvalidOffset;
49d5d881 413 }
c801d85f 414 }
c801d85f 415
49d5d881
VZ
416 iRc = iLen;
417 }
49d5d881 418
02aef13c
VZ
419 if ( iRc == wxInvalidOffset )
420 {
49d5d881 421 wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
c801d85f 422 }
02aef13c
VZ
423
424 return iRc;
c801d85f
KB
425}
426
427// is end of file reached?
428bool wxFile::Eof() const
429{
49d5d881 430 wxASSERT( IsOpened() );
c801d85f 431
30984dea 432 wxFileOffset iRc;
61b02744 433
d3b4d710 434#if defined(__DOS__) || defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__)
61b02744 435 // @@ this doesn't work, of course, on unseekable file descriptors
30984dea 436 wxFileOffset ofsCur = Tell(),
49d5d881 437 ofsMax = Length();
1678ad78 438 if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
02aef13c 439 iRc = wxInvalidOffset;
61b02744 440 else
49d5d881
VZ
441 iRc = ofsCur == ofsMax;
442#else // Windows and "native" compiler
6294ac2e 443 iRc = wxEof(m_fd);
49d5d881 444#endif // Windows/Unix
c801d85f 445
b9daf00a
WS
446 if ( iRc == 1)
447 {}
448 else if ( iRc == 0 )
449 return false;
450 else if ( iRc == wxInvalidOffset )
451 wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd);
452 else
453 wxFAIL_MSG(_("invalid eof() return value."));
c801d85f 454
a62848fd 455 return true;
c801d85f
KB
456}
457
458// ============================================================================
459// implementation of wxTempFile
460// ============================================================================
461
462// ----------------------------------------------------------------------------
463// construction
464// ----------------------------------------------------------------------------
44b62d54 465
c801d85f
KB
466wxTempFile::wxTempFile(const wxString& strName)
467{
49d5d881 468 Open(strName);
c801d85f
KB
469}
470
471bool wxTempFile::Open(const wxString& strName)
472{
44b62d54
VZ
473 // we must have an absolute filename because otherwise CreateTempFileName()
474 // would create the temp file in $TMP (i.e. the system standard location
475 // for the temp files) which might be on another volume/drive/mount and
476 // wxRename()ing it later to m_strName from Commit() would then fail
477 //
478 // with the absolute filename, the temp file is created in the same
479 // directory as this one which ensures that wxRename() may work later
480 wxFileName fn(strName);
481 if ( !fn.IsAbsolute() )
482 {
483 fn.Normalize(wxPATH_NORM_ABSOLUTE);
484 }
485
486 m_strName = fn.GetFullPath();
246037e2 487
44b62d54 488 m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file);
ade35f11
VZ
489
490 if ( m_strTemp.empty() )
491 {
492 // CreateTempFileName() failed
a62848fd 493 return false;
ade35f11 494 }
49d5d881 495
49d5d881 496#ifdef __UNIX__
ade35f11
VZ
497 // the temp file should have the same permissions as the original one
498 mode_t mode;
a62848fd 499
f6bcfd97 500 wxStructStat st;
ca11abde 501 if ( stat( (const char*) m_strName.fn_str(), &st) == 0 )
49d5d881 502 {
ade35f11 503 mode = st.st_mode;
49d5d881
VZ
504 }
505 else
506 {
ade35f11 507 // file probably didn't exist, just give it the default mode _using_
68164137 508 // user's umask (new files creation should respect umask)
ade35f11
VZ
509 mode_t mask = umask(0777);
510 mode = 0666 & ~mask;
511 umask(mask);
49d5d881 512 }
49d5d881 513
ca11abde 514 if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 )
fe99e285 515 {
5a3912f2 516#ifndef __OS2__
ade35f11 517 wxLogSysError(_("Failed to set temporary file permissions"));
5a3912f2 518#endif
fe99e285 519 }
49d5d881 520#endif // Unix
246037e2 521
a62848fd 522 return true;
c801d85f
KB
523}
524
525// ----------------------------------------------------------------------------
526// destruction
527// ----------------------------------------------------------------------------
528
529wxTempFile::~wxTempFile()
530{
49d5d881
VZ
531 if ( IsOpened() )
532 Discard();
c801d85f
KB
533}
534
535bool wxTempFile::Commit()
536{
49d5d881 537 m_file.Close();
c801d85f 538
f6bcfd97 539 if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) {
49d5d881 540 wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
a62848fd 541 return false;
49d5d881 542 }
c801d85f 543
f35746ce 544 if ( !wxRenameFile(m_strTemp, m_strName) ) {
49d5d881 545 wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
a62848fd 546 return false;
49d5d881 547 }
c801d85f 548
a62848fd 549 return true;
c801d85f
KB
550}
551
552void wxTempFile::Discard()
553{
49d5d881 554 m_file.Close();
f6bcfd97 555 if ( wxRemove(m_strTemp) != 0 )
49d5d881 556 wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
c801d85f 557}
ce4169a4 558
ade35f11 559#endif // wxUSE_FILE
cc985fac 560