1/////////////////////////////////////////////////////////////////////////////
2// Name:        ffile.cpp
3// Purpose:     wxFFile encapsulates "FILE *" IO stream
4// Author:      Vadim Zeitlin
5// Modified by:
6// Created:     14.07.99
7// RCS-ID:      $Id: ffile.cpp 63300 2010-01-28 21:36:09Z MW $
8// Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24  #pragma hdrstop
25#endif
26
27#if wxUSE_FFILE
28
29#ifndef WX_PRECOMP
30    #include "wx/intl.h"
31    #include "wx/log.h"
32#endif
33
34#ifdef __WINDOWS__
35#include "wx/msw/mslu.h"
36#endif
37
38#include "wx/ffile.h"
39
40// ============================================================================
41// implementation
42// ============================================================================
43
44// ----------------------------------------------------------------------------
45// opening the file
46// ----------------------------------------------------------------------------
47
48wxFFile::wxFFile(const wxChar *filename, const wxChar *mode)
49{
50    Detach();
51
52    (void)Open(filename, mode);
53}
54
55bool wxFFile::Open(const wxChar *filename, const wxChar *mode)
56{
57    wxASSERT_MSG( !m_fp, wxT("should close or detach the old file first") );
58
59    m_fp = wxFopen(filename, mode);
60
61    if ( !m_fp )
62    {
63        wxLogSysError(_("can't open file '%s'"), filename);
64
65        return false;
66    }
67
68    m_name = filename;
69
70    return true;
71}
72
73bool wxFFile::Close()
74{
75    if ( IsOpened() )
76    {
77        if ( fclose(m_fp) != 0 )
78        {
79            wxLogSysError(_("can't close file '%s'"), m_name.c_str());
80
81            return false;
82        }
83
84        Detach();
85    }
86
87    return true;
88}
89
90// ----------------------------------------------------------------------------
91// read/write
92// ----------------------------------------------------------------------------
93
94bool wxFFile::ReadAll(wxString *str, const wxMBConv& conv)
95{
96    wxCHECK_MSG( str, false, wxT("invalid parameter") );
97    wxCHECK_MSG( IsOpened(), false, wxT("can't read from closed file") );
98    wxCHECK_MSG( Length() >= 0, false, wxT("invalid length") );
99    size_t length = wx_truncate_cast(size_t, Length());
100    wxCHECK_MSG( (wxFileOffset)length == Length(), false, wxT("huge file not supported") );
101
102    clearerr(m_fp);
103
104    wxCharBuffer buf(length + 1);
105
106    // note that real length may be less than file length for text files with DOS EOLs
107    // ('\r's get dropped by CRT when reading which means that we have
108    // realLen = fileLen - numOfLinesInTheFile)
109    length = fread(buf.data(), sizeof(char), length, m_fp);
110
111    if ( Error() )
112    {
113        wxLogSysError(_("Read error on file '%s'"), m_name.c_str());
114
115        return false;
116    }
117
118    buf.data()[length] = 0;
119    *str = wxString(buf, conv);
120
121    return true;
122}
123
124size_t wxFFile::Read(void *pBuf, size_t nCount)
125{
126    wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") );
127    wxCHECK_MSG( IsOpened(), 0, wxT("can't read from closed file") );
128
129    size_t nRead = fread(pBuf, 1, nCount, m_fp);
130    if ( (nRead < nCount) && Error() )
131    {
132        wxLogSysError(_("Read error on file '%s'"), m_name.c_str());
133    }
134
135    return nRead;
136}
137
138size_t wxFFile::Write(const void *pBuf, size_t nCount)
139{
140    wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") );
141    wxCHECK_MSG( IsOpened(), 0, wxT("can't write to closed file") );
142
143    size_t nWritten = fwrite(pBuf, 1, nCount, m_fp);
144    if ( nWritten < nCount )
145    {
146        wxLogSysError(_("Write error on file '%s'"), m_name.c_str());
147    }
148
149    return nWritten;
150}
151
152bool wxFFile::Flush()
153{
154    if ( IsOpened() )
155    {
156        // fflush returns non-zero on error
157        //
158        if ( fflush(m_fp) )
159        {
160            wxLogSysError(_("failed to flush the file '%s'"), m_name.c_str());
161
162            return false;
163        }
164    }
165
166    return true;
167}
168
169// ----------------------------------------------------------------------------
170// seeking
171// ----------------------------------------------------------------------------
172
173bool wxFFile::Seek(wxFileOffset ofs, wxSeekMode mode)
174{
175    wxCHECK_MSG( IsOpened(), false, wxT("can't seek on closed file") );
176
177    int origin;
178    switch ( mode )
179    {
180        default:
181            wxFAIL_MSG(wxT("unknown seek mode"));
182            // still fall through
183
184        case wxFromStart:
185            origin = SEEK_SET;
186            break;
187
188        case wxFromCurrent:
189            origin = SEEK_CUR;
190            break;
191
192        case wxFromEnd:
193            origin = SEEK_END;
194            break;
195    }
196
197#ifndef wxHAS_LARGE_FFILES
198    if ((long)ofs != ofs)
199    {
200        wxLogError(_("Seek error on file '%s' (large files not supported by stdio)"), m_name.c_str());
201
202        return false;
203    }
204
205    if ( wxFseek(m_fp, (long)ofs, origin) != 0 )
206#else
207    if ( wxFseek(m_fp, ofs, origin) != 0 )
208#endif
209    {
210        wxLogSysError(_("Seek error on file '%s'"), m_name.c_str());
211
212        return false;
213    }
214
215    return true;
216}
217
218wxFileOffset wxFFile::Tell() const
219{
220    wxCHECK_MSG( IsOpened(), wxInvalidOffset,
221                 _T("wxFFile::Tell(): file is closed!") );
222
223    wxFileOffset rc = wxFtell(m_fp);
224    if ( rc == wxInvalidOffset )
225    {
226        wxLogSysError(_("Can't find current position in file '%s'"),
227                      m_name.c_str());
228    }
229
230    return rc;
231}
232
233wxFileOffset wxFFile::Length() const
234{
235    wxCHECK_MSG( IsOpened(), wxInvalidOffset,
236                 _T("wxFFile::Length(): file is closed!") );
237
238    wxFFile& self = *(wxFFile *)this;   // const_cast
239
240    wxFileOffset posOld = Tell();
241    if ( posOld != wxInvalidOffset )
242    {
243        if ( self.SeekEnd() )
244        {
245            wxFileOffset len = Tell();
246
247            (void)self.Seek(posOld);
248
249            return len;
250        }
251    }
252
253    return wxInvalidOffset;
254}
255
256#endif // wxUSE_FFILE
257