Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages | Examples

vos/metaobjects/property/fileproperty.cc

Go to the documentation of this file.
00001 /*
00002     This file is part of the Virtual Object System of
00003     the Interreality project (http://interreality.org).
00004 
00005     Copyright (C) 2001, 2002 Peter Amstutz
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Lesser General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Lesser General Public License for more details.
00016 
00017     You should have received a copy of the GNU Lesser General Public
00018     License along with this library; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00020 
00021     Peter Amstutz <tetron@interreality.org>
00022     Additions by Reed Hedges <reed@zerohour.net> marked with initials "rh" and date.
00023 */
00024 #include <stdio.h>
00025 #include <errno.h>
00026 #include <assert.h>
00027 
00028 #include "fileproperty.hh"
00029 
00030 #ifndef S_ISREG
00031 #define S_ISREG(x) (x & _S_IFREG)
00032 #endif
00033 
00034 
00035 FileProperty::FileProperty(MetaObject* superobject)
00036     : MetaObject(superobject), Property(superobject), LocalProperty(superobject), filehandle(0)
00037 {
00038 }
00039 
00040 FileProperty::FileProperty(MetaObject* superobject, const string& file_name, const string& datatype)
00041     : MetaObject(superobject), Property(superobject), LocalProperty(superobject, "", datatype), filehandle(0), filename(file_name)
00042 {
00043     setFileBackend(file_name);
00044 }
00045 
00046 FileProperty::~FileProperty()
00047 {
00048     if(filehandle) fclose(filehandle);
00049 }
00050 
00051 void FileProperty::registerExtenders()
00052 {
00053     static bool done = false;
00054     if(! done) {
00055     LocalSite::addLocalObjectExtension(typeid(FileProperty).name(),
00056                                          &FileProperty::new_FileProperty);
00057     LocalSite::addLocalObjectExtension("property:property.file",
00058                                        &FileProperty::new_FileProperty);
00059     done = true;
00060     }
00061 }
00062 
00063 
00064 MetaObject* FileProperty::new_FileProperty(MetaObject* superobject, const string& type)
00065 {
00066     return new FileProperty(superobject);
00067 }
00068 
00069 void FileProperty::checkOpenFile() throw (FileAccessError)
00070 {
00071     if(! filehandle) {
00072         if(! (filehandle=fopen(filename.c_str(), "r+b"))) {
00073             if(errno == EACCES) {
00074                 if(! (filehandle=fopen(filename.c_str(), "rb"))) {
00075                     throw FileAccessError(string(strerror(errno)) + " " + filename);
00076                 }
00077                 readonly = true;
00078             } else throw FileAccessError(string(strerror(errno)) + " " + filename);
00079         } else readonly = false;
00080         fstat(fileno(filehandle), &status);
00081     }
00082     struct stat curstat;
00083 
00084     fstat(fileno(filehandle), &curstat);
00085 
00086     // check if file has changed since opening it
00087     if(curstat.st_mtime > status.st_mtime) {
00088         fclose(filehandle);
00089         filehandle = 0;
00090         if(! (filehandle=fopen(filename.c_str(), "r+b"))) {
00091             throw FileAccessError(string(strerror(errno)) + " " + filename);
00092         }
00093         fstat(fileno(filehandle), &status); // now file status is up to date (and will not infitely recurse on call to getRawLength(), below)
00094         string s;
00095         readRaw(s, 0, getRawLength());
00096 
00097         vRef<PropertyEvent> event = new PropertyEvent(
00098             PropertyEvent::PropertyReplace,
00099             *this, *this,
00100             s, getDataType(), 
00101             false);
00102 
00103         for(PropertyListenerMap::iterator i = propertyListeners.begin();
00104             i != propertyListeners.end();
00105             i++) {
00106             (*i).second->notifyPropertyChange(*event);
00107         }
00108 
00109     }
00110 }
00111 
00112 void FileProperty::setFileBackend(const string& file_name, const string& data_type) throw(FileAccessError)
00113 {
00114     if(filehandle) fclose(filehandle);
00115     filehandle=0;
00116     filename = file_name;
00117     raw_datatype = data_type;
00118 
00119     struct stat curstat;
00120     if(stat(file_name.c_str(), &curstat) != 0
00121         || ! S_ISREG(curstat.st_mode))
00122     {
00123         throw FileAccessError("No such file " + file_name);
00124     }
00125 }
00126 
00127 string FileProperty::getFileBackend()
00128 {
00129     return filename;
00130 }
00131 
00132 int FileProperty::getRawLength() throw(FileAccessError)
00133 {
00134     checkOpenFile();
00135     fseek(filehandle, 0, SEEK_END);
00136     return ftell(filehandle);
00137 }
00138 
00139 void FileProperty::readRaw(string& target, int start, int length) throw(FileAccessError)
00140 {
00141     checkOpenFile();
00142     if(length < 0)
00143         length = getRawLength() - (0 - (length + 1));
00144     if(start < 0) start = getRawLength() + start + 1;
00145     if(start > getRawLength()) { target = ""; return; }
00146     char* b = (char*)malloc(length);
00147     fseek(filehandle, start, SEEK_SET);
00148     length = fread(b, 1, length, filehandle);
00149     target = string(b, length);
00150     free(b);
00151 }
00152 
00153 void FileProperty::read(string& target, int start, int length) throw(FileAccessError)
00154 {
00155 /* XXX NOT DONE */
00156     /* fileproperty is never "decoded" in memory (never stored in memory), always decode */
00157     readRaw(target, start, length);
00158     datatype = TypeChain::decode(target, getRawDataType());
00159     data_length = target.size();
00160 }
00161 
00162 
00163 
00164 
00165 void FileProperty::write(int start, const string& newdata) throw(FileAccessError)
00166 {
00167     checkOpenFile();
00168     if(! readonly) {
00169         fseek(filehandle, start, SEEK_SET);
00170         fwrite(newdata.c_str(), newdata.size(), 1, filehandle);
00171         fstat(fileno(filehandle), &status);
00172         LocalProperty::write(0, "");
00173     } else {
00174         LOG("fileproperty", 2, "Tried to write to a read-only file " << filename);
00175     }
00176 }
00177 
00178 void FileProperty::replace(const string& newdata, const string& newtype) throw(FileAccessError)
00179 {
00180     if(filehandle) fclose(filehandle);
00181     filehandle=0;
00182 
00183     if(! (filehandle=fopen(filename.c_str(), "w+b"))) {
00184         if(errno == EACCES) {
00185             if(! (filehandle=fopen(filename.c_str(), "rb"))) {
00186                 throw FileAccessError(string(strerror(errno)) + " " + filename);
00187             }
00188             readonly = true;
00189             LOG("fileproperty", 2, "Tried to replace a read-only file " << filename);
00190         }
00191     } else readonly = false;
00192     if(! readonly) {
00193         fstat(fileno(filehandle), &status);
00194         write(0, newdata);
00195 
00196         Property::replace("", newtype);
00197 
00198         vRef<PropertyEvent> event = new PropertyEvent(
00199             PropertyEvent::PropertyReplace,
00200             *this, *this,
00201             newdata, newtype,
00202             false);
00203 
00204         for(PropertyListenerMap::iterator i = propertyListeners.begin(); i != propertyListeners.end(); i++) {
00205             (*i).second->notifyPropertyChange(*event);
00206         }
00207     }
00208 }
00209 

Generated on Tue Aug 12 03:55:45 2003 for Interreality Project - VOS by doxygen 1.3.2