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 
wxFFile(const wxChar * filename,const wxChar * mode)48 wxFFile::wxFFile(const wxChar *filename, const wxChar *mode)
49 {
50     Detach();
51 
52     (void)Open(filename, mode);
53 }
54 
Open(const wxChar * filename,const wxChar * mode)55 bool 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 
Close()73 bool 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 
ReadAll(wxString * str,const wxMBConv & conv)94 bool 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 
Read(void * pBuf,size_t nCount)124 size_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 
Write(const void * pBuf,size_t nCount)138 size_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 
Flush()152 bool 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 
Seek(wxFileOffset ofs,wxSeekMode mode)173 bool 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 
Tell() const218 wxFileOffset 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 
Length() const233 wxFileOffset 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