| | 1 | /* |
| | 2 | * Copyright (c) 2002 by Michael J. Roberts. All Rights Reserved. |
| | 3 | * |
| | 4 | * Please see the accompanying license file, LICENSE.TXT, for information |
| | 5 | * on using and copying this software. |
| | 6 | */ |
| | 7 | /* |
| | 8 | Name |
| | 9 | vmhosttx.cpp - text-only host interface implementation |
| | 10 | Function |
| | 11 | Provides a base class for the T3 VM Host Interface for implementing |
| | 12 | text-only applications. |
| | 13 | Notes |
| | 14 | |
| | 15 | Modified |
| | 16 | 06/16/02 MJRoberts - Creation |
| | 17 | */ |
| | 18 | |
| | 19 | #include "os.h" |
| | 20 | #include "t3std.h" |
| | 21 | #include "vmhash.h" |
| | 22 | #include "vmhost.h" |
| | 23 | #include "vmhosttx.h" |
| | 24 | |
| | 25 | /* ------------------------------------------------------------------------ */ |
| | 26 | /* |
| | 27 | * Hash table entry for a resource descriptor |
| | 28 | */ |
| | 29 | class CResEntry: public CVmHashEntryCI |
| | 30 | { |
| | 31 | public: |
| | 32 | CResEntry(const char *resname, size_t resnamelen, int copy, |
| | 33 | unsigned long ofs, unsigned long siz, int fileno) |
| | 34 | : CVmHashEntryCI(resname, resnamelen, copy) |
| | 35 | { |
| | 36 | /* remember the file locator information */ |
| | 37 | fileno_ = fileno; |
| | 38 | ofs_ = ofs; |
| | 39 | siz_ = siz; |
| | 40 | link_ = 0; |
| | 41 | } |
| | 42 | |
| | 43 | CResEntry(const char *resname, size_t resnamelen, int copy, |
| | 44 | const char *fname, size_t fnamelen) |
| | 45 | : CVmHashEntryCI(resname, resnamelen, copy) |
| | 46 | { |
| | 47 | /* save the local filename */ |
| | 48 | link_ = lib_copy_str(fname, fnamelen); |
| | 49 | |
| | 50 | /* it's not in a resource file */ |
| | 51 | fileno_ = 0; |
| | 52 | ofs_ = 0; |
| | 53 | siz_ = 0; |
| | 54 | } |
| | 55 | |
| | 56 | ~CResEntry() |
| | 57 | { |
| | 58 | lib_free_str(link_); |
| | 59 | } |
| | 60 | |
| | 61 | /* file number (this is an index in the hostifc's ext_ array) */ |
| | 62 | int fileno_; |
| | 63 | |
| | 64 | /* byte offset of the start of the resource data in the file */ |
| | 65 | unsigned long ofs_; |
| | 66 | |
| | 67 | /* byte size of the resource data */ |
| | 68 | unsigned long siz_; |
| | 69 | |
| | 70 | /* local filename, for a resource link (rather than a stored resource) */ |
| | 71 | char *link_; |
| | 72 | }; |
| | 73 | |
| | 74 | /* ------------------------------------------------------------------------ */ |
| | 75 | /* |
| | 76 | * construction |
| | 77 | */ |
| | 78 | CVmHostIfcText::CVmHostIfcText() |
| | 79 | { |
| | 80 | /* create our hash table */ |
| | 81 | restab_ = new CVmHashTable(128, new CVmHashFuncCI(), TRUE); |
| | 82 | |
| | 83 | /* allocate an initial set of external resource filename entries */ |
| | 84 | ext_max_ = 10; |
| | 85 | ext_ = (char **)t3malloc(ext_max_ * sizeof(ext_[0])); |
| | 86 | |
| | 87 | /* we use slot zero for the image filename, which we don't know yet */ |
| | 88 | ext_cnt_ = 1; |
| | 89 | ext_[0] = 0; |
| | 90 | |
| | 91 | /* no resource directory specified yet */ |
| | 92 | res_dir_ = 0; |
| | 93 | } |
| | 94 | |
| | 95 | /* |
| | 96 | * deletion |
| | 97 | */ |
| | 98 | CVmHostIfcText::~CVmHostIfcText() |
| | 99 | { |
| | 100 | size_t i; |
| | 101 | |
| | 102 | /* delete our hash table */ |
| | 103 | delete restab_; |
| | 104 | |
| | 105 | /* delete our external filenames */ |
| | 106 | for (i = 0 ; i < ext_cnt_ ; ++i) |
| | 107 | lib_free_str(ext_[i]); |
| | 108 | |
| | 109 | /* delete our array of external filename entries */ |
| | 110 | t3free(ext_); |
| | 111 | |
| | 112 | /* delete our resource directory path */ |
| | 113 | lib_free_str(res_dir_); |
| | 114 | } |
| | 115 | |
| | 116 | /* |
| | 117 | * set the image file name - we always use resource file slot zero to |
| | 118 | * store the image file |
| | 119 | */ |
| | 120 | void CVmHostIfcText::set_image_name(const char *fname) |
| | 121 | { |
| | 122 | /* free any old name string */ |
| | 123 | lib_free_str(ext_[0]); |
| | 124 | |
| | 125 | /* remember the new name */ |
| | 126 | ext_[0] = lib_copy_str(fname); |
| | 127 | } |
| | 128 | |
| | 129 | /* |
| | 130 | * set the resource directory |
| | 131 | */ |
| | 132 | void CVmHostIfcText::set_res_dir(const char *dir) |
| | 133 | { |
| | 134 | /* forget any previous setting, and remember the new path */ |
| | 135 | lib_free_str(res_dir_); |
| | 136 | res_dir_ = lib_copy_str(dir); |
| | 137 | } |
| | 138 | |
| | 139 | /* |
| | 140 | * add a resource file |
| | 141 | */ |
| | 142 | int CVmHostIfcText::add_resfile(const char *fname) |
| | 143 | { |
| | 144 | /* expand the resource file list if necessary */ |
| | 145 | if (ext_cnt_ == ext_max_) |
| | 146 | { |
| | 147 | /* bump up the maximum a bit */ |
| | 148 | ext_max_ += 10; |
| | 149 | |
| | 150 | /* reallocate the entry pointer array */ |
| | 151 | ext_ = (char **)t3realloc(ext_, ext_max_ * sizeof(ext_[0])); |
| | 152 | } |
| | 153 | |
| | 154 | /* store the new entry */ |
| | 155 | ext_[ext_cnt_++] = lib_copy_str(fname); |
| | 156 | |
| | 157 | /* |
| | 158 | * return the new entry's file number (we've already bumped the index, |
| | 159 | * so it's the current count minus one) |
| | 160 | */ |
| | 161 | return ext_cnt_ - 1; |
| | 162 | } |
| | 163 | |
| | 164 | /* |
| | 165 | * add a resource |
| | 166 | */ |
| | 167 | void CVmHostIfcText::add_resource(unsigned long ofs, unsigned long siz, |
| | 168 | const char *resname, size_t resnamelen, |
| | 169 | int fileno) |
| | 170 | { |
| | 171 | CResEntry *entry; |
| | 172 | |
| | 173 | /* create a new entry desribing the resource */ |
| | 174 | entry = new CResEntry(resname, resnamelen, TRUE, ofs, siz, fileno); |
| | 175 | |
| | 176 | /* add it to the table */ |
| | 177 | restab_->add(entry); |
| | 178 | } |
| | 179 | |
| | 180 | /* |
| | 181 | * add a resource |
| | 182 | */ |
| | 183 | void CVmHostIfcText::add_resource(const char *fname, size_t fnamelen, |
| | 184 | const char *resname, size_t resnamelen) |
| | 185 | { |
| | 186 | CResEntry *entry; |
| | 187 | |
| | 188 | /* create a new entry desribing the resource */ |
| | 189 | entry = new CResEntry(resname, resnamelen, TRUE, fname, fnamelen); |
| | 190 | |
| | 191 | /* add it to the table */ |
| | 192 | restab_->add(entry); |
| | 193 | } |
| | 194 | |
| | 195 | /* |
| | 196 | * find a resource |
| | 197 | */ |
| | 198 | osfildef *CVmHostIfcText::find_resource(const char *resname, |
| | 199 | size_t resnamelen, |
| | 200 | unsigned long *res_size) |
| | 201 | { |
| | 202 | CResEntry *entry; |
| | 203 | osfildef *fp; |
| | 204 | char buf[OSFNMAX]; |
| | 205 | char *fname; |
| | 206 | char fname_buf[OSFNMAX]; |
| | 207 | char path[OSFNMAX]; |
| | 208 | |
| | 209 | /* try finding an entry in the resource map */ |
| | 210 | entry = (CResEntry *)restab_->find(resname, resnamelen); |
| | 211 | if (entry != 0) |
| | 212 | { |
| | 213 | /* found it - check the type */ |
| | 214 | if (entry->link_ == 0) |
| | 215 | { |
| | 216 | /* it's a stored binary resource - load it */ |
| | 217 | fp = osfoprb(ext_[entry->fileno_], OSFTBIN); |
| | 218 | |
| | 219 | /* if that succeeded, seek to the start of the resource */ |
| | 220 | if (fp != 0) |
| | 221 | osfseek(fp, entry->ofs_, OSFSK_SET); |
| | 222 | |
| | 223 | /* tell the caller the size of the resource */ |
| | 224 | *res_size = entry->siz_; |
| | 225 | |
| | 226 | /* return the file handle */ |
| | 227 | return fp; |
| | 228 | } |
| | 229 | else |
| | 230 | { |
| | 231 | /* it's a link to a a local file */ |
| | 232 | fname = entry->link_; |
| | 233 | } |
| | 234 | } |
| | 235 | else |
| | 236 | { |
| | 237 | /* |
| | 238 | * There's no entry in the resource map, so convert the resource |
| | 239 | * name from the URL notation to local file system conventions, |
| | 240 | * and look for a file with the given name. |
| | 241 | * |
| | 242 | * First, make a null-terminated copy of the resource name, |
| | 243 | * limiting the copy to our buffer size. |
| | 244 | */ |
| | 245 | if (resnamelen > sizeof(buf) - 1) |
| | 246 | resnamelen = sizeof(buf) - 1; |
| | 247 | memcpy(buf, resname, resnamelen); |
| | 248 | buf[resnamelen] = '\0'; |
| | 249 | |
| | 250 | /* convert the resource name to a URL */ |
| | 251 | os_cvt_url_dir(fname_buf, sizeof(fname_buf), buf, FALSE); |
| | 252 | fname = fname_buf; |
| | 253 | } |
| | 254 | |
| | 255 | /* |
| | 256 | * If we get this far, it's because we have a local file name in |
| | 257 | * 'fname' that we need to loo up. |
| | 258 | */ |
| | 259 | |
| | 260 | /* |
| | 261 | * external resources are relative to the image file, so make sure we |
| | 262 | * have an image file name |
| | 263 | */ |
| | 264 | if (ext_[0] == 0) |
| | 265 | return 0; |
| | 266 | |
| | 267 | /* get the path to the image file */ |
| | 268 | os_get_path_name(path, sizeof(path), ext_[0]); |
| | 269 | |
| | 270 | /* |
| | 271 | * build the full path name by combining the image file path with the |
| | 272 | * relative path we got from the resource name URL, as converted local |
| | 273 | * file system conventions |
| | 274 | */ |
| | 275 | os_build_full_path(buf, sizeof(buf), path, fname); |
| | 276 | |
| | 277 | /* try opening the file */ |
| | 278 | fp = osfoprb(buf, OSFTBIN); |
| | 279 | |
| | 280 | /* return failure if we couldn't find the file */ |
| | 281 | if (fp == 0) |
| | 282 | return 0; |
| | 283 | |
| | 284 | /* |
| | 285 | * the entire file is the resource data, so figure out how big the file |
| | 286 | * is, and tell the caller that the resource size is the file size |
| | 287 | */ |
| | 288 | osfseek(fp, 0, OSFSK_END); |
| | 289 | *res_size = osfpos(fp); |
| | 290 | |
| | 291 | /* |
| | 292 | * seek back to the start of the resource data (which is simply the |
| | 293 | * start of the file, since the entire file is the resource data) |
| | 294 | */ |
| | 295 | osfseek(fp, 0, OSFSK_SET); |
| | 296 | |
| | 297 | /* return the file handle */ |
| | 298 | return fp; |
| | 299 | } |
| | 300 | |
| | 301 | /* |
| | 302 | * determine if a resource exists |
| | 303 | */ |
| | 304 | int CVmHostIfcText::resfile_exists(const char *resname, size_t resnamelen) |
| | 305 | { |
| | 306 | osfildef *fp; |
| | 307 | unsigned long res_size; |
| | 308 | |
| | 309 | /* try opening the resource file */ |
| | 310 | fp = find_resource(resname, resnamelen, &res_size); |
| | 311 | |
| | 312 | /* check to see if we successfully opened the resource */ |
| | 313 | if (fp != 0) |
| | 314 | { |
| | 315 | /* found it - close the file and return success */ |
| | 316 | osfcls(fp); |
| | 317 | return TRUE; |
| | 318 | } |
| | 319 | else |
| | 320 | { |
| | 321 | /* couldn't find it - indicate failure */ |
| | 322 | return FALSE; |
| | 323 | } |
| | 324 | } |
| | 325 | |