2 Copyright (c) 2003-2005, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \brief Cross-platform, simple file accessors
38 typedef struct _stati64 fstat_t;
40 // AFAIK, there is no iovec equivalent in the win32 API
42 char* iov_base; // stupid iovec uses char*
47 typedef struct stat fstat_t;
52 static ASDCP::Result_t
53 do_stat(const char* path, fstat_t* stat_info)
55 ASDCP_TEST_NULL_STR(path);
56 ASDCP_TEST_NULL(stat_info);
58 ASDCP::Result_t result = ASDCP::RESULT_OK;
61 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
63 if ( _stati64(path, stat_info) == (__int64)-1 )
64 result = ASDCP::RESULT_FILEOPEN;
66 ::SetErrorMode( prev );
68 if ( stat(path, stat_info) == -1L )
69 result = ASDCP::RESULT_FILEOPEN;
71 if ( stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR) == 0 )
72 result = ASDCP::RESULT_FILEOPEN;
82 ASDCP::PathIsFile(const char* pathname)
87 if ( ASDCP_SUCCESS(do_stat(pathname, &info)) )
89 if ( info.st_mode & S_IFREG )
99 ASDCP::PathIsDirectory(const char* pathname)
104 if ( ASDCP_SUCCESS(do_stat(pathname, &info)) )
106 if ( info.st_mode & S_IFDIR )
116 ASDCP::FileSize(const char* pathname)
121 if ( ASDCP_SUCCESS(do_stat(pathname, &info)) )
123 if ( info.st_mode & S_IFREG )
124 return(info.st_size);
130 //------------------------------------------------------------------------------------------
131 // portable aspects of the file classes
133 const int IOVecMaxEntries = 32; // we never use more that 3, but that number seems somehow small...
136 class ASDCP::FileWriter::h__iovec
140 struct iovec m_iovec[IOVecMaxEntries];
141 h__iovec() : m_Count(0) {}
148 ASDCP::FileReader::Size() const
150 return ASDCP::FileSize(m_Filename.c_str());
153 // these are declared here instead of in the header file
154 // because we have a mem_ptr that is managing a hidden class
155 ASDCP::FileWriter::FileWriter() {}
156 ASDCP::FileWriter::~FileWriter() {}
160 ASDCP::FileWriter::Writev(const byte_t* buf, ui32_t buf_len)
162 assert( ! m_IOVec.empty() );
163 register h__iovec* iov = m_IOVec;
164 ASDCP_TEST_NULL(buf);
166 if ( iov->m_Count >= IOVecMaxEntries )
168 DefaultLogSink().Error("The iovec is full! Only %lu entries allowed before a flush.\n",
173 iov->m_iovec[iov->m_Count].iov_base = (char*)buf; // stupid iovec uses char*
174 iov->m_iovec[iov->m_Count].iov_len = buf_len;
182 //------------------------------------------------------------------------------------------
186 ASDCP::FileReader::OpenRead(const char* filename) const
188 ASDCP_TEST_NULL_STR(filename);
189 const_cast<FileReader*>(this)->m_Filename = filename;
191 // suppress popup window on error
192 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
194 const_cast<FileReader*>(this)->m_Handle = ::CreateFile(filename,
195 (GENERIC_READ), // open for reading
196 FILE_SHARE_READ, // share for reading
198 OPEN_EXISTING, // read
199 FILE_ATTRIBUTE_NORMAL, // normal file
200 NULL // no template file
203 ::SetErrorMode(prev);
205 return ( m_Handle == INVALID_HANDLE_VALUE ) ?
206 ASDCP::RESULT_FILEOPEN : ASDCP::RESULT_OK;
211 ASDCP::FileReader::Close() const
213 if ( m_Handle == INVALID_HANDLE_VALUE )
214 return ASDCP::RESULT_FILEOPEN;
216 // suppress popup window on error
217 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
218 BOOL result = ::CloseHandle(m_Handle);
219 ::SetErrorMode(prev);
220 const_cast<FileReader*>(this)->m_Handle = INVALID_HANDLE_VALUE;
222 return ( result == 0 ) ? ASDCP::RESULT_FAIL : ASDCP::RESULT_OK;
227 ASDCP::FileReader::Seek(ASDCP::fpos_t position, SeekPos_t whence) const
229 if ( m_Handle == INVALID_HANDLE_VALUE )
230 return ASDCP::RESULT_STATE;
233 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
234 in.QuadPart = position;
235 in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, whence);
236 HRESULT LastError = GetLastError();
237 ::SetErrorMode(prev);
239 if ( (LastError != NO_ERROR
240 && (in.LowPart == INVALID_SET_FILE_POINTER
241 || in.LowPart == ERROR_NEGATIVE_SEEK )) )
242 return ASDCP::RESULT_READFAIL;
244 return ASDCP::RESULT_OK;
249 ASDCP::FileReader::Tell(ASDCP::fpos_t* pos) const
251 ASDCP_TEST_NULL(pos);
253 if ( m_Handle == (HANDLE)-1L )
254 return ASDCP::RESULT_FILEOPEN;
257 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
258 in.QuadPart = (__int64)0;
259 in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, FILE_CURRENT);
260 HRESULT LastError = GetLastError();
261 ::SetErrorMode(prev);
263 if ( (LastError != NO_ERROR
264 && (in.LowPart == INVALID_SET_FILE_POINTER
265 || in.LowPart == ERROR_NEGATIVE_SEEK )) )
266 return ASDCP::RESULT_READFAIL;
268 *pos = (ASDCP::fpos_t)in.QuadPart;
269 return ASDCP::RESULT_OK;
274 ASDCP::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const
276 ASDCP_TEST_NULL(buf);
277 Result_t result = ASDCP::RESULT_OK;
281 if ( read_count == 0 )
282 read_count = &tmp_int;
286 if ( m_Handle == INVALID_HANDLE_VALUE )
287 return ASDCP::RESULT_FILEOPEN;
289 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
290 if ( ::ReadFile(m_Handle, buf, buf_len, &tmp_count, NULL) == 0 )
291 result = ASDCP::RESULT_READFAIL;
293 ::SetErrorMode(prev);
295 if ( tmp_count == 0 ) /* EOF */
296 result = ASDCP::RESULT_ENDOFFILE;
298 if ( ASDCP_SUCCESS(result) )
299 *read_count = tmp_count;
306 //------------------------------------------------------------------------------------------
311 ASDCP::FileWriter::OpenWrite(const char* filename)
313 ASDCP_TEST_NULL_STR(filename);
314 m_Filename = filename;
316 // suppress popup window on error
317 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
319 m_Handle = ::CreateFile(filename,
320 (GENERIC_WRITE|GENERIC_READ), // open for reading
321 FILE_SHARE_READ, // share for reading
323 CREATE_ALWAYS, // overwrite (beware!)
324 FILE_ATTRIBUTE_NORMAL, // normal file
325 NULL // no template file
328 ::SetErrorMode(prev);
330 if ( m_Handle == INVALID_HANDLE_VALUE )
331 return ASDCP::RESULT_FILEOPEN;
333 m_IOVec = new h__iovec;
334 return ASDCP::RESULT_OK;
339 ASDCP::FileWriter::Writev(ui32_t* bytes_written)
341 assert( ! m_IOVec.empty() );
342 register h__iovec* iov = m_IOVec;
345 if ( bytes_written == 0 )
346 bytes_written = &tmp_int;
348 if ( m_Handle == INVALID_HANDLE_VALUE )
349 return ASDCP::RESULT_STATE;
352 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
353 Result_t result = ASDCP::RESULT_OK;
355 // AFAIK, there is no writev() equivalent in the win32 API
356 for ( register int i = 0; i < iov->m_Count; i++ )
358 ui32_t tmp_count = 0;
359 BOOL wr_result = ::WriteFile(m_Handle,
360 iov->m_iovec[i].iov_base,
361 iov->m_iovec[i].iov_len,
365 if ( wr_result == 0 )
367 result = ASDCP::RESULT_WRITEFAIL;
371 assert(iov->m_iovec[i].iov_len == tmp_count);
372 *bytes_written += tmp_count;
375 ::SetErrorMode(prev);
376 iov->m_Count = 0; // error nor not, all is lost
383 ASDCP::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written)
385 ASDCP_TEST_NULL(buf);
388 if ( bytes_written == 0 )
389 bytes_written = &tmp_int;
391 if ( m_Handle == INVALID_HANDLE_VALUE )
392 return ASDCP::RESULT_STATE;
394 // suppress popup window on error
395 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
396 BOOL result = ::WriteFile(m_Handle, buf, buf_len, (DWORD*)bytes_written, NULL);
397 ::SetErrorMode(prev);
399 return ( result == 0 ) ? ASDCP::RESULT_WRITEFAIL : ASDCP::RESULT_OK;
403 //------------------------------------------------------------------------------------------
408 ASDCP::FileReader::OpenRead(const char* filename) const
410 ASDCP_TEST_NULL_STR(filename);
411 const_cast<FileReader*>(this)->m_Filename = filename;
412 const_cast<FileReader*>(this)->m_Handle = open(filename, O_RDONLY, 0);
413 return ( m_Handle == -1L ) ? RESULT_FILEOPEN : RESULT_OK;
418 ASDCP::FileReader::Close() const
420 if ( m_Handle == -1L )
421 return RESULT_FILEOPEN;
424 const_cast<FileReader*>(this)->m_Handle = -1L;
430 ASDCP::FileReader::Seek(ASDCP::fpos_t position, SeekPos_t whence) const
432 if ( m_Handle == -1L )
433 return RESULT_FILEOPEN;
435 if ( lseek(m_Handle, position, whence) == -1L )
436 return RESULT_BADSEEK;
443 ASDCP::FileReader::Tell(ASDCP::fpos_t* pos) const
445 ASDCP_TEST_NULL(pos);
447 if ( m_Handle == -1L )
448 return RESULT_FILEOPEN;
450 ASDCP::fpos_t tmp_pos;
452 if ( (tmp_pos = lseek(m_Handle, 0, SEEK_CUR)) == -1 )
453 return RESULT_READFAIL;
461 ASDCP::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const
463 ASDCP_TEST_NULL(buf);
467 if ( read_count == 0 )
468 read_count = &tmp_int;
472 if ( m_Handle == -1L )
473 return RESULT_FILEOPEN;
475 if ( (tmp_count = read(m_Handle, buf, buf_len)) == -1L )
476 return RESULT_READFAIL;
478 *read_count = tmp_count;
479 return (tmp_count == 0 ? RESULT_ENDOFFILE : RESULT_OK);
483 //------------------------------------------------------------------------------------------
488 ASDCP::FileWriter::OpenWrite(const char* filename)
490 ASDCP_TEST_NULL_STR(filename);
491 m_Filename = filename;
492 m_Handle = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644);
494 if ( m_Handle == -1L )
497 return RESULT_FILEOPEN;
500 m_IOVec = new h__iovec;
506 ASDCP::FileWriter::Writev(ui32_t* bytes_written)
508 assert( ! m_IOVec.empty() );
509 register h__iovec* iov = m_IOVec;
512 if ( bytes_written == 0 )
513 bytes_written = &tmp_int;
515 if ( m_Handle == -1L )
518 int read_size = writev(m_Handle, iov->m_iovec, iov->m_Count);
520 if ( read_size == -1L )
521 return RESULT_WRITEFAIL;
524 *bytes_written = read_size;
530 ASDCP::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written)
532 ASDCP_TEST_NULL(buf);
535 if ( bytes_written == 0 )
536 bytes_written = &tmp_int;
538 if ( m_Handle == -1L )
541 int read_size = write(m_Handle, buf, buf_len);
543 if ( read_size == -1L )
544 return RESULT_WRITEFAIL;
546 *bytes_written = read_size;