Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

relfile.cc

Go to the documentation of this file.
00001 /* 
00002  *      HT Editor
00003  *      relfile.cc
00004  *
00005  *      Copyright (C) 1999-2002 Stefan Weyergraf (stefan@weyergraf.de)
00006  *
00007  *      This program is free software; you can redistribute it and/or modify
00008  *      it under the terms of the GNU General Public License version 2 as
00009  *      published by the Free Software Foundation.
00010  *
00011  *      This program is distributed in the hope that it will be useful,
00012  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *      GNU General Public License for more details.
00015  *
00016  *      You should have received a copy of the GNU General Public License
00017  *      along with this program; if not, write to the Free Software
00018  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  */
00020 
00021 #include <string.h>
00022 
00023 #include "relfile.h"
00024 #include "tools.h"
00025 
00026 #define MAX_RELOC_ITEM_LEN 8
00027 
00028 /*
00029  *      ht_reloc_file
00030  */
00031 void ht_reloc_file::init(ht_streamfile *s, bool os)
00032 {
00033         ht_layer_streamfile::init(s, os);
00034         relocs = new ht_stree();
00035 //      ((ht_stree*)relocs)->init(compare_keys_uint_delinear);
00036         ((ht_stree*)relocs)->init(compare_keys_uint);
00037         enabled = true;
00038 }
00039 
00040 void ht_reloc_file::done()
00041 {
00042         relocs->destroy();
00043         delete relocs;
00044         ht_layer_streamfile::done();
00045 }
00046 
00047 void ht_reloc_file::finalize()
00048 {
00049 //      relocs->set_compare_keys(compare_keys_uint);
00050 }
00051 
00052 int ht_reloc_file::vcntl(UINT cmd, va_list vargs)
00053 {
00054         switch (cmd) {
00055                 case FCNTL_GET_RELOC: {
00056                         bool *e = va_arg(vargs, bool*);
00057                         *e = enabled;
00058                         return 0;
00059                 }
00060                 case FCNTL_SET_RELOC: {
00061                         enabled = (bool)(va_arg(vargs, int));
00062                         return 0;
00063                 }
00064         }
00065         return ht_layer_streamfile::vcntl(cmd, vargs);
00066 }
00067 
00068 void ht_reloc_file::insert_reloc(FILEOFS o, Object *reloc)
00069 {
00070         relocs->insert(new ht_data_uint(o), reloc);
00071 }
00072 
00073 UINT ht_reloc_file::read(void *buf, UINT size)
00074 {
00075         FILEOFS o = tell();
00076         /* read fine data. */
00077         UINT ret = ht_layer_streamfile::read(buf, size), c = ret;
00078         if (enabled) {
00079                 ht_data_uint q;
00080                 Object *r;
00081                 ht_data_uint *k = &q;
00082                 if ((MAX_RELOC_ITEM_LEN+1) <= o)
00083                         k->value = o - (MAX_RELOC_ITEM_LEN+1);
00084                 else
00085                         k = NULL;
00086 
00087                 /* enum through 'relocs' - the tree that contains all our
00088                  * dear relocations - starting some bytes before the current
00089                  * (stream) offset to get all the relocation items that may
00090                  * intersect with our fine read data. */
00091                 while ((k = (ht_data_uint*)relocs->enum_next(&r, k))) {
00092                         /* buffer to apply relocation to */
00093                         byte b[MAX_RELOC_ITEM_LEN];
00094                         /* stop if the item is "behind" the area this function
00095                          * should work on. */
00096                         if (k->value >= o+c) break;
00097 
00098                         /* if relocation item intersects with the beginning of
00099                          * this read, copy buf to b+s */
00100                         UINT s = (k->value < o) ? o - k->value : 0;
00101                         /* if relocation item intersects with the end of
00102                          * this read, copy buf+e to b */
00103                         UINT e = (k->value > o) ? k->value - o : 0;
00104 
00105                         /* complicated calculation to get the size of the
00106                          * intended intersection (=: mm) of the read and b. */
00107                         UINT l = (k->value + sizeof b > o+c) ?
00108                                 k->value + sizeof b - o - c : 0;
00109                         UINT mm = MIN(sizeof b - l, sizeof b - s);
00110 
00111                         /* probably cleaner to clear it all before we start
00112                          * because if the read is smaller then the reloc item
00113                          * we'd have some undefined bytes in b. */
00114                         memset(b, 0, sizeof b);
00115 
00116                         /* never memmove beyond bounds of b. (maybe you didn't call finalize() ?) */
00117                         assert(mm+s <= sizeof b);
00118 
00119                         /* move read data to b as good as we can. */
00120                         memmove(b+s, ((byte*)buf)+e, mm);
00121                         /* apply complete relocation item. */
00122                         reloc_apply(r, b);
00123                         /* overwrite read with relocated/read data as good as we can. */
00124                         memmove(((byte*)buf)+e, b+s, mm);
00125                 }
00126         }
00127         return ret;
00128 }
00129 
00130 UINT ht_reloc_file::write(const void *buf, UINT size)
00131 {
00132         /* documentation: see read(). */
00133         FILEOFS o;
00134         if (enabled) {
00135                 o = tell();
00136                 UINT c = size;
00137                 ht_data_uint q;
00138                 Object *r;
00139                 ht_data_uint *k = &q;
00140                 if ((MAX_RELOC_ITEM_LEN+1) <= o)
00141                         k->value = o - (MAX_RELOC_ITEM_LEN+1);
00142                 else
00143                         k = NULL;
00144 
00145                 while ((k = (ht_data_uint*)relocs->enum_next(&r, k))) {
00146                         byte b[MAX_RELOC_ITEM_LEN];
00147                         if (k->value >= o+c) break;
00148 
00149                         UINT s = (k->value < o) ? o - k->value : 0;
00150                         UINT e = (k->value > o) ? k->value - o : 0;
00151 
00152                         UINT l = (k->value+sizeof b > o+c) ?
00153                                 k->value + sizeof b - o - c : 0;
00154 
00155                         memset(b, 0, sizeof b);
00156                         UINT mm = MIN(sizeof b - l, sizeof b - s);
00157 
00158                         assert(mm+s <= sizeof b);
00159                         memmove(b+s, ((byte*)buf)+e, mm);
00160                         // FIXME: return here ???
00161                         if (!reloc_unapply(r, b)) /*return 0*/;
00162                         // FIXME: violation of function declaration "const void *buf"
00163                         memmove(((byte*)buf)+e, b+s, mm);
00164                 }
00165         }
00166         return ht_layer_streamfile::write(buf, size);
00167 }

Generated on Fri May 7 21:15:43 2004 by doxygen 1.3.5