2 Copyright (c) 2004-2007, 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.
27 /*! \file KM_fileio.cpp
29 \brief portable file i/o
32 #include <KM_fileio.h>
43 typedef struct _stati64 fstat_t;
47 // win32 has WriteFileGather() and ReadFileScatter() but they
48 // demand page alignment and page sizing, making them unsuitable
49 // for use with arbitrary buffer sizes.
51 char* iov_base; // stupid iovec uses char*
56 typedef struct stat fstat_t;
61 split(const std::string& str, char separator, std::list<std::string>& components)
63 const char* pstr = str.c_str();
64 const char* r = strchr(pstr, separator);
72 tmp_str.assign(pstr, (r - pstr));
73 components.push_back(tmp_str);
77 r = strchr(pstr, separator);
80 if( strlen(pstr) > 0 )
81 components.push_back(std::string(pstr));
87 do_stat(const char* path, fstat_t* stat_info)
89 KM_TEST_NULL_STR_L(path);
90 KM_TEST_NULL_L(stat_info);
92 Kumu::Result_t result = Kumu::RESULT_OK;
95 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
97 if ( _stati64(path, stat_info) == (__int64)-1 )
98 result = Kumu::RESULT_FILEOPEN;
100 ::SetErrorMode( prev );
102 if ( stat(path, stat_info) == -1L )
103 result = Kumu::RESULT_FILEOPEN;
105 if ( (stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR)) == 0 )
106 result = Kumu::RESULT_FILEOPEN;
115 static Kumu::Result_t
116 do_fstat(HANDLE handle, fstat_t* stat_info)
118 KM_TEST_NULL_L(stat_info);
120 Kumu::Result_t result = Kumu::RESULT_OK;
122 if ( fstat(handle, stat_info) == -1L )
123 result = Kumu::RESULT_FILEOPEN;
125 if ( (stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR)) == 0 )
126 result = Kumu::RESULT_FILEOPEN;
136 Kumu::PathExists(const std::string& pathname)
138 if ( pathname.empty() )
143 if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
151 Kumu::PathIsFile(const std::string& pathname)
153 if ( pathname.empty() )
158 if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
160 if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
170 Kumu::PathIsDirectory(const std::string& pathname)
172 if ( pathname.empty() )
177 if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
179 if ( info.st_mode & S_IFDIR )
188 Kumu::FileSize(const std::string& pathname)
190 if ( pathname.empty() )
195 if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
197 if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
198 return(info.st_size);
205 static PathCompList_t&
206 s_PathMakeCanonical(PathCompList_t& CList, char separator, bool is_absolute)
208 PathCompList_t::iterator ci, ri; // component and removal iterators
210 for ( ci = CList.begin(); ci != CList.end(); ci++ )
212 if ( *ci == "." && ( CList.size() > 1 || is_absolute ) )
217 else if ( *ci == ".." && ci != CList.begin() )
236 Kumu::PathMakeCanonical(const std::string& Path, char separator)
238 PathCompList_t CList;
239 bool is_absolute = PathIsAbsolute(Path, separator);
240 s_PathMakeCanonical(PathToComponents(Path, CList, separator), separator, is_absolute);
243 return ComponentsToAbsolutePath(CList, separator);
245 return ComponentsToPath(CList, separator);
250 Kumu::PathsAreEquivalent(const std::string& lhs, const std::string& rhs)
252 return PathMakeCanonical(lhs) == PathMakeCanonical(rhs);
256 Kumu::PathCompList_t&
257 Kumu::PathToComponents(const std::string& Path, PathCompList_t& CList, char separator)
259 split(Path, separator, CList);
265 Kumu::ComponentsToPath(const PathCompList_t& CList, char separator)
270 PathCompList_t::const_iterator ci = CList.begin();
271 std::string out_path = *ci;
273 for ( ci++; ci != CList.end(); ci++ )
274 out_path += separator + *ci;
281 Kumu::ComponentsToAbsolutePath(const PathCompList_t& CList, char separator)
283 std::string out_path;
286 out_path = separator;
289 PathCompList_t::const_iterator ci;
291 for ( ci = CList.begin(); ci != CList.end(); ci++ )
292 out_path += separator + *ci;
300 Kumu::PathHasComponents(const std::string& Path, char separator)
302 if ( strchr(Path.c_str(), separator) == 0 )
310 Kumu::PathIsAbsolute(const std::string& Path, char separator)
315 if ( Path[0] == separator)
323 Kumu::PathMakeAbsolute(const std::string& Path, char separator)
327 std::string out_path;
328 out_path = separator;
332 if ( PathIsAbsolute(Path, separator) )
335 char cwd_buf [MaxFilePath];
336 if ( getcwd(cwd_buf, MaxFilePath) == 0 )
338 DefaultLogSink().Error("Error retrieving current working directory.");
342 PathCompList_t CList;
343 CList.push_back(cwd_buf);
344 CList.push_back(Path);
346 return ComponentsToAbsolutePath(s_PathMakeCanonical(CList, separator, true), separator);
351 Kumu::PathMakeLocal(const std::string& Path, const std::string& Parent)
353 size_t pos = Path.find(Parent);
355 if ( pos == 0 ) // Parent found at offset 0
356 return Path.substr(Parent.size()+1);
363 Kumu::PathBasename(const std::string& Path, char separator)
365 PathCompList_t CList;
366 PathToComponents(Path, CList, separator);
376 Kumu::PathDirname(const std::string& Path, char separator)
378 PathCompList_t CList;
379 bool is_absolute = PathIsAbsolute(Path, separator);
380 PathToComponents(Path, CList, separator);
383 return is_absolute ? "/" : "";
388 return ComponentsToAbsolutePath(CList, separator);
390 return ComponentsToPath(CList, separator);
395 Kumu::PathGetExtension(const std::string& Path)
397 std::string Basename = PathBasename(Path);
398 const char* p = strrchr(Basename.c_str(), '.');
408 Kumu::PathSetExtension(const std::string& Path, const std::string& Extension) // empty extension removes
410 std::string Basename = PathBasename(Path);
411 const char* p = strrchr(Basename.c_str(), '.');
414 Basename = Basename.substr(0, p - Basename.c_str());
416 if ( Extension.empty() )
419 return Basename + "." + Extension;
424 Kumu::FindInPaths(const IPathMatch& Pattern, const Kumu::PathList_t& SearchPaths,
425 Kumu::PathList_t& FoundPaths, bool one_shot, char separator)
427 PathList_t::const_iterator si;
428 for ( si = SearchPaths.begin(); si != SearchPaths.end(); si++ )
430 FindInPath(Pattern, *si, FoundPaths, one_shot, separator);
432 if ( one_shot && ! FoundPaths.empty() )
441 Kumu::FindInPath(const IPathMatch& Pattern, const std::string& SearchDir,
442 Kumu::PathList_t& FoundPaths, bool one_shot, char separator)
444 char name_buf[MaxFilePath];
447 if ( KM_SUCCESS(Dir.Open(SearchDir.c_str())) )
449 while ( KM_SUCCESS(Dir.GetNext(name_buf)) )
451 if ( name_buf[0] == '.' ) continue; // no hidden files
452 std::string tmp_path = SearchDir + separator + name_buf;
454 if ( PathIsDirectory(tmp_path.c_str()) )
455 FindInPath(Pattern, tmp_path, FoundPaths, one_shot, separator);
457 else if ( Pattern.Match(name_buf) )
459 FoundPaths.push_back(SearchDir + separator + name_buf);
473 Kumu::PathMatchRegex::PathMatchRegex(const std::string& s)
475 int result = regcomp(&m_regex, s.c_str(), REG_NOSUB); // (REG_EXTENDED|REG_NOSUB|REG_NEWLINE));
480 regerror(result, &m_regex, buf, 128);
481 DefaultLogSink().Error("PathMatchRegex: %s\n", buf);
486 Kumu::PathMatchRegex::PathMatchRegex(const PathMatchRegex& rhs) : IPathMatch() {
487 m_regex = rhs.m_regex;
490 Kumu::PathMatchRegex::~PathMatchRegex() {
495 Kumu::PathMatchRegex::Match(const std::string& s) const {
496 return ( regexec(&m_regex, s.c_str(), 0, 0, 0) == 0 );
502 Kumu::PathMatchGlob::PathMatchGlob(const std::string& glob)
504 std::string regex; // convert glob to regex
506 for ( const char* p = glob.c_str(); *p != 0; p++ )
510 case '.': regex += "\\."; break;
511 case '*': regex += ".*"; break;
512 case '?': regex += ".?"; break;
513 default: regex += *p;
518 int result = regcomp(&m_regex, regex.c_str(), REG_NOSUB);
523 regerror(result, &m_regex, buf, 128);
524 DefaultLogSink().Error("PathMatchRegex: %s\n", buf);
529 Kumu::PathMatchGlob::PathMatchGlob(const PathMatchGlob& rhs) : IPathMatch() {
530 m_regex = rhs.m_regex;
533 Kumu::PathMatchGlob::~PathMatchGlob() {
538 Kumu::PathMatchGlob::Match(const std::string& s) const {
539 return ( regexec(&m_regex, s.c_str(), 0, 0, 0) == 0 );
544 //------------------------------------------------------------------------------------------
545 // portable aspects of the file classes
547 const int IOVecMaxEntries = 32; // we never use more that 3, but that number seems somehow small...
550 class Kumu::FileWriter::h__iovec
554 struct iovec m_iovec[IOVecMaxEntries];
555 h__iovec() : m_Count(0) {}
562 Kumu::FileReader::Size() const
565 return FileSize(m_Filename.c_str());
569 if ( KM_SUCCESS(do_fstat(m_Handle, &info)) )
571 if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
572 return(info.st_size);
579 // these are declared here instead of in the header file
580 // because we have a mem_ptr that is managing a hidden class
581 Kumu::FileWriter::FileWriter() {}
582 Kumu::FileWriter::~FileWriter() {}
586 Kumu::FileWriter::Writev(const byte_t* buf, ui32_t buf_len)
588 assert( ! m_IOVec.empty() );
589 register h__iovec* iov = m_IOVec;
592 if ( iov->m_Count >= IOVecMaxEntries )
594 DefaultLogSink().Error("The iovec is full! Only %u entries allowed before a flush.\n",
596 return RESULT_WRITEFAIL;
599 iov->m_iovec[iov->m_Count].iov_base = (char*)buf; // stupid iovec uses char*
600 iov->m_iovec[iov->m_Count].iov_len = buf_len;
608 //------------------------------------------------------------------------------------------
612 Kumu::FileReader::OpenRead(const char* filename) const
614 KM_TEST_NULL_STR_L(filename);
615 const_cast<FileReader*>(this)->m_Filename = filename;
617 // suppress popup window on error
618 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
620 const_cast<FileReader*>(this)->m_Handle = ::CreateFile(filename,
621 (GENERIC_READ), // open for reading
622 FILE_SHARE_READ, // share for reading
624 OPEN_EXISTING, // read
625 FILE_ATTRIBUTE_NORMAL, // normal file
626 NULL // no template file
629 ::SetErrorMode(prev);
631 return ( m_Handle == INVALID_HANDLE_VALUE ) ?
632 Kumu::RESULT_FILEOPEN : Kumu::RESULT_OK;
637 Kumu::FileReader::Close() const
639 if ( m_Handle == INVALID_HANDLE_VALUE )
640 return Kumu::RESULT_FILEOPEN;
642 // suppress popup window on error
643 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
644 BOOL result = ::CloseHandle(m_Handle);
645 ::SetErrorMode(prev);
646 const_cast<FileReader*>(this)->m_Handle = INVALID_HANDLE_VALUE;
648 return ( result == 0 ) ? Kumu::RESULT_FAIL : Kumu::RESULT_OK;
653 Kumu::FileReader::Seek(Kumu::fpos_t position, SeekPos_t whence) const
655 if ( m_Handle == INVALID_HANDLE_VALUE )
656 return Kumu::RESULT_STATE;
659 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
660 in.QuadPart = position;
661 in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, whence);
662 HRESULT LastError = GetLastError();
663 ::SetErrorMode(prev);
665 if ( (LastError != NO_ERROR
666 && (in.LowPart == INVALID_SET_FILE_POINTER
667 || in.LowPart == ERROR_NEGATIVE_SEEK )) )
668 return Kumu::RESULT_READFAIL;
670 return Kumu::RESULT_OK;
675 Kumu::FileReader::Tell(Kumu::fpos_t* pos) const
679 if ( m_Handle == (HANDLE)-1L )
680 return Kumu::RESULT_FILEOPEN;
683 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
684 in.QuadPart = (__int64)0;
685 in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, FILE_CURRENT);
686 HRESULT LastError = GetLastError();
687 ::SetErrorMode(prev);
689 if ( (LastError != NO_ERROR
690 && (in.LowPart == INVALID_SET_FILE_POINTER
691 || in.LowPart == ERROR_NEGATIVE_SEEK )) )
692 return Kumu::RESULT_READFAIL;
694 *pos = (Kumu::fpos_t)in.QuadPart;
695 return Kumu::RESULT_OK;
700 Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const
703 Result_t result = Kumu::RESULT_OK;
707 if ( read_count == 0 )
708 read_count = &tmp_int;
712 if ( m_Handle == INVALID_HANDLE_VALUE )
713 return Kumu::RESULT_FILEOPEN;
715 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
716 if ( ::ReadFile(m_Handle, buf, buf_len, &tmp_count, NULL) == 0 )
717 result = Kumu::RESULT_READFAIL;
719 ::SetErrorMode(prev);
721 if ( tmp_count == 0 ) /* EOF */
722 result = Kumu::RESULT_ENDOFFILE;
724 if ( KM_SUCCESS(result) )
725 *read_count = tmp_count;
732 //------------------------------------------------------------------------------------------
737 Kumu::FileWriter::OpenWrite(const char* filename)
739 KM_TEST_NULL_STR_L(filename);
740 m_Filename = filename;
742 // suppress popup window on error
743 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
745 m_Handle = ::CreateFile(filename,
746 (GENERIC_WRITE|GENERIC_READ), // open for reading
747 FILE_SHARE_READ, // share for reading
749 CREATE_ALWAYS, // overwrite (beware!)
750 FILE_ATTRIBUTE_NORMAL, // normal file
751 NULL // no template file
754 ::SetErrorMode(prev);
756 if ( m_Handle == INVALID_HANDLE_VALUE )
757 return Kumu::RESULT_FILEOPEN;
759 m_IOVec = new h__iovec;
760 return Kumu::RESULT_OK;
765 Kumu::FileWriter::Writev(ui32_t* bytes_written)
767 assert( ! m_IOVec.empty() );
768 register h__iovec* iov = m_IOVec;
771 if ( bytes_written == 0 )
772 bytes_written = &tmp_int;
774 if ( m_Handle == INVALID_HANDLE_VALUE )
775 return Kumu::RESULT_STATE;
778 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
779 Result_t result = Kumu::RESULT_OK;
781 // AFAIK, there is no writev() equivalent in the win32 API
782 for ( register int i = 0; i < iov->m_Count; i++ )
784 ui32_t tmp_count = 0;
785 BOOL wr_result = ::WriteFile(m_Handle,
786 iov->m_iovec[i].iov_base,
787 iov->m_iovec[i].iov_len,
791 if ( wr_result == 0 || tmp_count != iov->m_iovec[i].iov_len)
793 result = Kumu::RESULT_WRITEFAIL;
797 *bytes_written += tmp_count;
800 ::SetErrorMode(prev);
801 iov->m_Count = 0; // error nor not, all is lost
808 Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written)
813 if ( bytes_written == 0 )
814 bytes_written = &tmp_int;
816 if ( m_Handle == INVALID_HANDLE_VALUE )
817 return Kumu::RESULT_STATE;
819 // suppress popup window on error
820 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
821 BOOL result = ::WriteFile(m_Handle, buf, buf_len, (DWORD*)bytes_written, NULL);
822 ::SetErrorMode(prev);
824 if ( result == 0 || *bytes_written != buf_len )
825 return Kumu::RESULT_WRITEFAIL;
827 return Kumu::RESULT_OK;
831 //------------------------------------------------------------------------------------------
836 Kumu::FileReader::OpenRead(const char* filename) const
838 KM_TEST_NULL_STR_L(filename);
839 const_cast<FileReader*>(this)->m_Filename = filename;
840 const_cast<FileReader*>(this)->m_Handle = open(filename, O_RDONLY, 0);
841 return ( m_Handle == -1L ) ? RESULT_FILEOPEN : RESULT_OK;
846 Kumu::FileReader::Close() const
848 if ( m_Handle == -1L )
849 return RESULT_FILEOPEN;
852 const_cast<FileReader*>(this)->m_Handle = -1L;
858 Kumu::FileReader::Seek(Kumu::fpos_t position, SeekPos_t whence) const
860 if ( m_Handle == -1L )
861 return RESULT_FILEOPEN;
863 if ( lseek(m_Handle, position, whence) == -1L )
864 return RESULT_BADSEEK;
871 Kumu::FileReader::Tell(Kumu::fpos_t* pos) const
875 if ( m_Handle == -1L )
876 return RESULT_FILEOPEN;
878 Kumu::fpos_t tmp_pos;
880 if ( (tmp_pos = lseek(m_Handle, 0, SEEK_CUR)) == -1 )
881 return RESULT_READFAIL;
889 Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const
895 if ( read_count == 0 )
896 read_count = &tmp_int;
900 if ( m_Handle == -1L )
901 return RESULT_FILEOPEN;
903 if ( (tmp_count = read(m_Handle, buf, buf_len)) == -1L )
904 return RESULT_READFAIL;
906 *read_count = tmp_count;
907 return (tmp_count == 0 ? RESULT_ENDOFFILE : RESULT_OK);
911 //------------------------------------------------------------------------------------------
916 Kumu::FileWriter::OpenWrite(const char* filename)
918 KM_TEST_NULL_STR_L(filename);
919 m_Filename = filename;
920 m_Handle = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0664);
922 if ( m_Handle == -1L )
924 DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno));
925 return RESULT_FILEOPEN;
928 m_IOVec = new h__iovec;
934 Kumu::FileWriter::OpenModify(const char* filename)
936 KM_TEST_NULL_STR_L(filename);
937 m_Filename = filename;
938 m_Handle = open(filename, O_RDWR|O_CREAT, 0664);
940 if ( m_Handle == -1L )
942 DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno));
943 return RESULT_FILEOPEN;
946 m_IOVec = new h__iovec;
952 Kumu::FileWriter::Writev(ui32_t* bytes_written)
954 assert( ! m_IOVec.empty() );
955 register h__iovec* iov = m_IOVec;
958 if ( bytes_written == 0 )
959 bytes_written = &tmp_int;
961 if ( m_Handle == -1L )
965 for ( int i = 0; i < iov->m_Count; i++ )
966 total_size += iov->m_iovec[i].iov_len;
968 int write_size = writev(m_Handle, iov->m_iovec, iov->m_Count);
970 if ( write_size == -1L || write_size != total_size )
971 return RESULT_WRITEFAIL;
974 *bytes_written = write_size;
980 Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written)
985 if ( bytes_written == 0 )
986 bytes_written = &tmp_int;
988 if ( m_Handle == -1L )
991 int write_size = write(m_Handle, buf, buf_len);
993 if ( write_size == -1L || (ui32_t)write_size != buf_len )
994 return RESULT_WRITEFAIL;
996 *bytes_written = write_size;
1003 //------------------------------------------------------------------------------------------
1008 Kumu::ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size)
1011 ui32_t read_size = 0;
1015 KM_TEST_NULL_STR_L(filename);
1017 Result_t result = File.OpenRead(filename);
1019 if ( KM_SUCCESS(result) )
1021 fsize = File.Size();
1023 if ( fsize > (Kumu::fpos_t)max_size )
1025 DefaultLogSink().Error("%s: exceeds available buffer size (%u)\n", filename, max_size);
1026 return RESULT_ALLOC;
1031 DefaultLogSink().Error("%s: zero file size\n", filename);
1032 return RESULT_READFAIL;
1035 result = ReadBuf.Capacity((ui32_t)fsize);
1038 if ( KM_SUCCESS(result) )
1039 result = File.Read(ReadBuf.Data(), ReadBuf.Capacity(), &read_size);
1041 if ( KM_SUCCESS(result) )
1042 outString.assign((const char*)ReadBuf.RoData(), read_size);
1050 Kumu::WriteStringIntoFile(const char* filename, const std::string& inString)
1053 ui32_t write_count = 0;
1054 KM_TEST_NULL_STR_L(filename);
1056 Result_t result = File.OpenWrite(filename);
1058 if ( KM_SUCCESS(result) )
1059 result = File.Write((byte_t*)inString.c_str(), inString.length(), &write_count);
1064 //------------------------------------------------------------------------------------------
1069 Kumu::ReadFileIntoObject(const std::string& Filename, Kumu::IArchive& Object, ui32_t max_size)
1072 ui32_t file_size = FileSize(Filename);
1073 Result_t result = Buffer.Capacity(file_size);
1075 if ( KM_SUCCESS(result) )
1077 ui32_t read_count = 0;
1080 result = Reader.OpenRead(Filename.c_str());
1082 if ( KM_SUCCESS(result) )
1083 result = Reader.Read(Buffer.Data(), file_size, &read_count);
1085 if ( KM_SUCCESS(result) )
1087 assert(file_size == read_count);
1088 Buffer.Length(read_count);
1089 MemIOReader MemReader(&Buffer);
1090 result = Object.Unarchive(&MemReader) ? RESULT_OK : RESULT_READFAIL;
1099 Kumu::WriteObjectIntoFile(const Kumu::IArchive& Object, const std::string& Filename)
1102 Result_t result = Buffer.Capacity(Object.ArchiveLength());
1104 if ( KM_SUCCESS(result) )
1106 ui32_t write_count = 0;
1108 MemIOWriter MemWriter(&Buffer);
1110 result = Object.Archive(&MemWriter) ? RESULT_OK : RESULT_WRITEFAIL;
1112 if ( KM_SUCCESS(result) )
1114 Buffer.Length(MemWriter.Length());
1115 result = Writer.OpenWrite(Filename.c_str());
1118 if ( KM_SUCCESS(result) )
1119 result = Writer.Write(Buffer.RoData(), Buffer.Length(), &write_count);
1125 //------------------------------------------------------------------------------------------
1128 // Win32 directory scanner
1135 Kumu::DirScanner::Open(const char* filename)
1137 KM_TEST_NULL_STR_L(filename);
1139 // we need to append a '*' to read the entire directory
1140 ui32_t fn_len = strlen(filename);
1141 char* tmp_file = (char*)malloc(fn_len + 8);
1143 if ( tmp_file == 0 )
1144 return RESULT_ALLOC;
1146 strcpy(tmp_file, filename);
1147 char* p = &tmp_file[fn_len] - 1;
1149 if ( *p != '/' && *p != '\\' )
1159 m_Handle = _findfirsti64(tmp_file, &m_FileInfo);
1160 Result_t result = RESULT_OK;
1162 if ( m_Handle == -1 )
1163 result = RESULT_NOT_FOUND;
1172 Kumu::DirScanner::Close()
1174 if ( m_Handle == -1 )
1175 return RESULT_FILEOPEN;
1177 if ( _findclose((long)m_Handle) == -1 )
1185 // This sets filename param to the same per-instance buffer every time, so
1186 // the value will change on the next call
1188 Kumu::DirScanner::GetNext(char* filename)
1190 KM_TEST_NULL_L(filename);
1192 if ( m_Handle == -1 )
1193 return RESULT_FILEOPEN;
1195 if ( m_FileInfo.name[0] == '\0' )
1196 return RESULT_ENDOFFILE;
1198 strncpy(filename, m_FileInfo.name, MaxFilePath);
1199 Result_t result = RESULT_OK;
1201 if ( _findnexti64((long)m_Handle, &m_FileInfo) == -1 )
1203 m_FileInfo.name[0] = '\0';
1205 if ( errno != ENOENT )
1206 result = RESULT_FAIL;
1215 // POSIX directory scanner
1219 Kumu::DirScanner::Open(const char* filename)
1221 KM_TEST_NULL_STR_L(filename);
1223 Result_t result = RESULT_OK;
1225 if ( ( m_Handle = opendir(filename) ) == NULL )
1227 if ( errno == ENOENT )
1228 result = RESULT_ENDOFFILE;
1231 result = RESULT_FAIL;
1240 Kumu::DirScanner::Close()
1242 if ( m_Handle == NULL )
1243 return RESULT_FILEOPEN;
1245 if ( closedir(m_Handle) == -1 )
1255 Kumu::DirScanner::GetNext(char* filename)
1257 KM_TEST_NULL_L(filename);
1259 if ( m_Handle == NULL )
1260 return RESULT_FILEOPEN;
1262 struct dirent* entry;
1266 if ( ( entry = readdir(m_Handle)) == NULL )
1267 return RESULT_ENDOFFILE;
1272 strncpy(filename, entry->d_name, MaxFilePath);
1282 // end KM_fileio.cpp