1 /*****************************************************************************\
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 2000-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
15 #include "byte_filer.h"
17 #include <application/windoze_helper.h>
18 #include <basis/astring.h>
19 #include <basis/byte_array.h>
20 #include <basis/functions.h>
21 #include <basis/utf_conversion.h>
32 //#define DEBUG_BYTE_FILER
33 // uncomment for noisy version of class.
35 using namespace basis;
37 namespace filesystem {
39 const size_t BTFL_FILE_TELL_LIMIT = size_t(2) * size_t(GIGABYTE);
40 // the largest a long integer can represent in the tell system call.
45 FILE *fp; // the real file pointer.
47 file_hider() : fp(NIL) {}
52 byte_filer::byte_filer()
53 : _handle(new file_hider),
54 _filename(new filename),
58 byte_filer::byte_filer(const astring &fname, const astring &perms)
59 : _handle(new file_hider),
60 _filename(new filename),
62 { open(fname, perms); }
64 byte_filer::byte_filer(const char *fname, const char *perms)
65 : _handle(new file_hider),
66 _filename(new filename),
68 { open(fname, perms); }
70 byte_filer::byte_filer(bool auto_close, void *handle)
71 : _handle(new file_hider),
72 _filename(new filename),
73 _auto_close(auto_close)
76 _handle->fp = (FILE *)handle;
80 byte_filer::~byte_filer() { close(); WHACK(_handle); WHACK(_filename); }
82 astring byte_filer::name() const { return _filename->raw(); }
84 size_t byte_filer::file_size_limit() { return BTFL_FILE_TELL_LIMIT; }
86 bool byte_filer::open(const astring &fname, const astring &perms)
89 _auto_close = true; // reset since we know we're opening this.
90 _filename->reset(fname);
92 _handle->fp = _filename->raw().t()? fopen(_filename->raw().s(), perms.s()) : NIL;
94 _handle->fp = _filename->raw().t()? _wfopen((wchar_t *)(UTF16 *)transcode_to_utf16(_filename->raw()),
95 (wchar_t *)(UTF16 *)transcode_to_utf16(perms)) : NIL;
97 #ifdef DEBUG_BYTE_FILER
99 wprintf((wchar_t *)(UTF16 *)transcode_to_utf16("could not open: %ls\n"),
100 (wchar_t *)(UTF16 *)transcode_to_utf16(_filename->raw()));
107 void byte_filer::close()
109 _filename->reset("");
110 if (_auto_close && _handle->fp) fclose(_handle->fp);
114 bool byte_filer::good() { return !!_handle->fp; }
116 size_t byte_filer::tell()
118 if (!_handle->fp) return 0;
119 long to_return = ::ftell(_handle->fp);
120 if (to_return == -1) {
121 // if we couldn't get the size, either the file isn't there or the size
122 // is too big for our OS to report.
123 ///printf(a_sprintf("failed to tell size, calling it %.0f, and one plus that is %.0f\n", double(BTFL_FILE_TELL_LIMIT), double(long(long(BTFL_FILE_TELL_LIMIT) + 1))).s());
124 if (good()) return BTFL_FILE_TELL_LIMIT;
127 return size_t(to_return);
130 void *byte_filer::file_handle() { return _handle->fp; }
132 bool byte_filer::eof() { return !_handle->fp ? true : !!feof(_handle->fp); }
134 int byte_filer::read(abyte *buff, int size)
135 { return !_handle->fp ? 0 : int(::fread((char *)buff, 1, size, _handle->fp)); }
137 int byte_filer::write(const abyte *buff, int size)
138 { return !_handle->fp ? 0 : int(::fwrite((char *)buff, 1, size, _handle->fp)); }
140 int byte_filer::read(byte_array &buff, int desired_size)
142 buff.reset(desired_size);
143 int to_return = read(buff.access(), desired_size);
144 buff.zap(to_return, buff.length() - 1);
148 int byte_filer::write(const byte_array &buff)
149 { return write(buff.observe(), buff.length()); }
151 size_t byte_filer::length()
153 size_t current_posn = tell();
154 seek(0, FROM_END); // jump to end of file.
155 size_t file_size = tell(); // get position.
156 seek(int(current_posn), FROM_START); // jump back to previous place.
160 int byte_filer::read(astring &s, int desired_size)
162 s.pad(desired_size + 2);
163 int found = read((abyte *)s.observe(), desired_size);
164 if (non_negative(found)) s[found] = '\0';
169 int byte_filer::write(const astring &s, bool add_null)
171 int len = s.length();
173 return write((abyte *)s.observe(), len);
176 void byte_filer::flush()
178 if (!_handle->fp) return;
179 ::fflush(_handle->fp);
182 bool byte_filer::truncate()
185 int fnum = fileno(_handle->fp);
187 return SetEndOfFile((HANDLE)_get_osfhandle(fnum));
189 size_t posn = tell();
190 // if we're at the highest point we can be, we no longer trust our
191 // ability to truncate properly.
192 if (posn >= file_size_limit())
194 return !ftruncate(fnum, posn);
198 bool byte_filer::seek(int where, origins origin)
200 if (!_handle->fp) return false;
203 case FROM_START: real_origin = SEEK_SET; break;
204 case FROM_END: real_origin = SEEK_END; break;
205 case FROM_CURRENT: real_origin = SEEK_CUR; break;
206 default: return false; // not a valid choice.
208 int ret = ::fseek(_handle->fp, where, real_origin);
212 int byte_filer::getline(abyte *buff, int desired_size)
214 if (!_handle->fp) return 0;
215 char *ret = ::fgets((char *)buff, desired_size, _handle->fp);
216 return !ret? 0 : int(strlen((char *)buff)) + 1;
219 int byte_filer::getline(byte_array &buff, int desired_size)
221 buff.reset(desired_size + 1);
222 return getline(buff.access(), desired_size);
225 int byte_filer::getline(astring &buff, int desired_size)
227 buff.pad(desired_size + 1);
228 int to_return = getline((abyte *)buff.access(), desired_size);
229 if (non_negative(to_return)) buff[to_return] = '\0';