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 const 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);
91 _handle->fp = _filename->raw().t()? fopen(_filename->raw().s(), perms.s()) : NIL;
92 if (_handle->fp == NIL) return false;
96 void byte_filer::close()
99 if (_auto_close && _handle->fp) fclose(_handle->fp);
103 bool byte_filer::good() { return !!_handle->fp; }
105 size_t byte_filer::tell()
107 if (!_handle->fp) return 0;
108 long to_return = ::ftell(_handle->fp);
109 if (to_return == -1) {
110 // if we couldn't get the size, either the file isn't there or the size
111 // is too big for our OS to report.
112 ///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());
113 if (good()) return BTFL_FILE_TELL_LIMIT;
116 return size_t(to_return);
119 void *byte_filer::file_handle() { return _handle->fp; }
121 bool byte_filer::eof() { return !_handle->fp ? true : !!feof(_handle->fp); }
123 int byte_filer::read(abyte *buff, int size)
124 { return !_handle->fp ? 0 : int(::fread((char *)buff, 1, size, _handle->fp)); }
126 int byte_filer::write(const abyte *buff, int size)
127 { return !_handle->fp ? 0 : int(::fwrite((char *)buff, 1, size, _handle->fp)); }
129 int byte_filer::read(byte_array &buff, int desired_size)
131 buff.reset(desired_size);
132 int to_return = read(buff.access(), desired_size);
133 buff.zap(to_return, buff.length() - 1);
137 int byte_filer::write(const byte_array &buff)
138 { return write(buff.observe(), buff.length()); }
140 size_t byte_filer::length()
142 size_t current_posn = tell();
143 seek(0, FROM_END); // jump to end of file.
144 size_t file_size = tell(); // get position.
145 seek(int(current_posn), FROM_START); // jump back to previous place.
149 int byte_filer::read(astring &s, int desired_size)
151 s.pad(desired_size + 2);
152 int found = read((abyte *)s.observe(), desired_size);
153 if (non_negative(found)) s[found] = '\0';
158 int byte_filer::write(const astring &s, bool add_null)
160 int len = s.length();
162 return write((abyte *)s.observe(), len);
165 void byte_filer::flush()
167 if (!_handle->fp) return;
168 ::fflush(_handle->fp);
171 bool byte_filer::truncate()
174 int fnum = fileno(_handle->fp);
176 return SetEndOfFile((HANDLE)_get_osfhandle(fnum));
178 size_t posn = tell();
179 // if we're at the highest point we can be, we no longer trust our
180 // ability to truncate properly.
181 if (posn >= file_size_limit())
183 return !ftruncate(fnum, posn);
187 bool byte_filer::seek(int where, origins origin)
189 if (!_handle->fp) return false;
192 case FROM_START: real_origin = SEEK_SET; break;
193 case FROM_END: real_origin = SEEK_END; break;
194 case FROM_CURRENT: real_origin = SEEK_CUR; break;
195 default: return false; // not a valid choice.
197 int ret = ::fseek(_handle->fp, where, real_origin);
201 int byte_filer::getline(abyte *buff, int desired_size)
203 if (!_handle->fp) return 0;
204 char *ret = ::fgets((char *)buff, desired_size, _handle->fp);
205 return !ret? 0 : int(strlen((char *)buff)) + 1;
208 int byte_filer::getline(byte_array &buff, int desired_size)
210 buff.reset(desired_size + 1);
211 return getline(buff.access(), desired_size);
214 int byte_filer::getline(astring &buff, int desired_size)
216 buff.pad(desired_size + 1);
217 int to_return = getline((abyte *)buff.access(), desired_size);
218 if (non_negative(to_return)) buff[to_return] = '\0';