00001 #ifndef BYTE_FILER_IMPLEMENTATION_FILE
00002 #define BYTE_FILER_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "byte_filer.h"
00019
00020 #include <basis/byte_array.h>
00021 #include <basis/convert_utf.h>
00022 #include <basis/function.h>
00023 #include <basis/istring.h>
00024 #include <basis/portable.h>
00025
00026 #include <stdio.h>
00027 #include <string.h>
00028 #ifdef __UNIX__
00029 #include <unistd.h>
00030 #endif
00031 #ifdef __WIN32__
00032 #include <io.h>
00033 #endif
00034
00035
00036
00037
00038 const size_t BTFL_FILE_TELL_LIMIT = size_t(2) * size_t(GIGABYTE);
00039
00040
00041 class file_hider
00042 {
00043 public:
00044 FILE *fp;
00045
00046 file_hider() : fp(NIL) {}
00047 };
00048
00050
00051 byte_filer::byte_filer()
00052 : _handle(new file_hider),
00053 _filename(new istring),
00054 _auto_close(true)
00055 {}
00056
00057 byte_filer::byte_filer(const istring &filename, const istring &perms)
00058 : _handle(new file_hider),
00059 _filename(new istring),
00060 _auto_close(true)
00061 { open(filename, perms); }
00062
00063 byte_filer::byte_filer(const char *filename, const char *perms)
00064 : _handle(new file_hider),
00065 _filename(new istring),
00066 _auto_close(true)
00067 { open(filename, perms); }
00068
00069 byte_filer::byte_filer(bool auto_close, void *handle)
00070 : _handle(new file_hider),
00071 _filename(new istring),
00072 _auto_close(auto_close)
00073 {
00074 if (handle) {
00075 _handle->fp = (FILE *)handle;
00076 }
00077 }
00078
00079 byte_filer::~byte_filer() { close(); WHACK(_handle); WHACK(_filename); }
00080
00081 istring byte_filer::filename() const { return *_filename; }
00082
00083 size_t byte_filer::file_size_limit() { return BTFL_FILE_TELL_LIMIT; }
00084
00085 bool byte_filer::open(const istring &filename, const istring &perms)
00086 {
00087 close();
00088 _auto_close = true;
00089 *_filename = filename;
00090 #ifndef __WIN32__
00091 _handle->fp = filename.t()? fopen(filename.s(), perms.s()) : NIL;
00092 #else
00093 _handle->fp = filename.t()? _wfopen((wchar_t *)(UTF16 *)transcode_to_utf16(filename),
00094 (wchar_t *)(UTF16 *)transcode_to_utf16(perms)) : NIL;
00095
00096 #ifdef DEBUG_BYTE_FILER
00097 if (!_handle->fp)
00098 wprintf((wchar_t *)(UTF16 *)transcode_to_utf16("could not open: %ls\n"),
00099 (wchar_t *)(UTF16 *)transcode_to_utf16(filename));
00100 #endif
00101
00102 #endif
00103 return good();
00104 }
00105
00106 void byte_filer::close()
00107 {
00108 *_filename = "";
00109 if (_auto_close && _handle->fp) fclose(_handle->fp);
00110 _handle->fp = NIL;
00111 }
00112
00113 bool byte_filer::good() { return !!_handle->fp; }
00114
00115 size_t byte_filer::tell()
00116 {
00117 if (!_handle->fp) return 0;
00118 long to_return = ::ftell(_handle->fp);
00119 if (to_return == -1) {
00120
00121
00123 if (good()) return BTFL_FILE_TELL_LIMIT;
00124 else return 0;
00125 }
00126 return size_t(to_return);
00127 }
00128
00129 void *byte_filer::file_handle() { return _handle->fp; }
00130
00131 bool byte_filer::eof() { return !_handle->fp ? true : !!feof(_handle->fp); }
00132
00133 int byte_filer::read(byte *buff, int size)
00134 { return !_handle->fp ? 0 : int(::fread((char *)buff, 1, size, _handle->fp)); }
00135
00136 int byte_filer::write(const byte *buff, int size)
00137 { return !_handle->fp ? 0 : int(::fwrite((char *)buff, 1, size, _handle->fp)); }
00138
00139 int byte_filer::read(byte_array &buff, int desired_size)
00140 {
00141 buff.reset(desired_size);
00142 int to_return = read(buff.access(), desired_size);
00143 buff.zap(to_return, buff.length() - 1);
00144 return to_return;
00145 }
00146
00147 int byte_filer::write(const byte_array &buff)
00148 { return write(buff.observe(), buff.length()); }
00149
00150 size_t byte_filer::length()
00151 {
00152 size_t current_posn = tell();
00153 seek(0, FROM_END);
00154 size_t file_size = tell();
00155 seek(int(current_posn), FROM_START);
00156 return file_size;
00157 }
00158
00159 int byte_filer::read(istring &s, int desired_size)
00160 {
00161 s.pad(desired_size + 2);
00162 int found = read((byte *)s.observe(), desired_size);
00163 if (non_negative(found)) s[found] = '\0';
00164 s.shrink();
00165 return found;
00166 }
00167
00168 int byte_filer::write(const istring &s, bool add_null)
00169 {
00170 int len = s.length();
00171 if (add_null) len++;
00172 return write((byte *)s.observe(), len);
00173 }
00174
00175 void byte_filer::flush()
00176 {
00177 if (!_handle->fp) return;
00178 ::fflush(_handle->fp);
00179 }
00180
00181 bool byte_filer::truncate()
00182 {
00183 flush();
00184 int fnum = fileno(_handle->fp);
00185 #ifdef __WIN32__
00186 return SetEndOfFile((HANDLE)_get_osfhandle(fnum));
00187 #else
00188 size_t posn = tell();
00189
00190
00191 if (posn >= file_size_limit())
00192 return false;
00193 return !ftruncate(fnum, posn);
00194 #endif
00195 }
00196
00197 bool byte_filer::seek(int where, origins origin)
00198 {
00199 if (!_handle->fp) return false;
00200 int real_origin;
00201 switch (origin) {
00202 case FROM_START: real_origin = SEEK_SET; break;
00203 case FROM_END: real_origin = SEEK_END; break;
00204 case FROM_CURRENT: real_origin = SEEK_CUR; break;
00205 default: return false;
00206 }
00207 int ret = ::fseek(_handle->fp, where, real_origin);
00208 return !ret;
00209 }
00210
00211 int byte_filer::getline(byte *buff, int desired_size)
00212 {
00213 if (!_handle->fp) return 0;
00214 char *ret = ::fgets((char *)buff, desired_size, _handle->fp);
00215 return !ret? 0 : int(strlen((char *)buff)) + 1;
00216 }
00217
00218 int byte_filer::getline(byte_array &buff, int desired_size)
00219 {
00220 buff.reset(desired_size + 1);
00221 return getline(buff.access(), desired_size);
00222 }
00223
00224 int byte_filer::getline(istring &buff, int desired_size)
00225 {
00226 buff.pad(desired_size + 1);
00227 int to_return = getline((byte *)buff.access(), desired_size);
00228 if (non_negative(to_return)) buff[to_return] = '\0';
00229 buff.shrink();
00230 return to_return;
00231 }
00232
00233
00234 #endif //BYTE_FILER_IMPLEMENTATION_FILE
00235