00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <stdarg.h>
00038
00039 #ifndef _MSC_VER
00040 #include <fcntl.h>
00041 #endif
00042
00043 #include "stratagus.h"
00044 #include "iocompat.h"
00045 #include "iolib.h"
00046
00047 CFile::CFile()
00048 {
00049 cl_type = CLF_TYPE_INVALID;
00050 }
00051
00052 CFile::~CFile()
00053 {
00054 if (cl_type != CLF_TYPE_INVALID) {
00055 DebugPrint("File wasn't closed\n");
00056 close();
00057 }
00058 }
00059
00060
00061 #ifndef z_off_t // { ZLIB_VERSION<="1.0.4"
00062
00070 static int gzseek(CFile *file, unsigned offset, int whence)
00071 {
00072 char buf[32];
00073
00074 while (offset > sizeof(buf)) {
00075 gzread(file, buf, sizeof(buf));
00076 offset -= sizeof(buf);
00077 }
00078 return gzread(file, buf, offset);
00079 }
00080
00081 #endif // } ZLIB_VERSION<="1.0.4"
00082
00091 int CFile::open(const char *name, long openflags)
00092 {
00093 char buf[512];
00094 const char *openstring;
00095
00096 if ((openflags & CL_OPEN_READ) && (openflags & CL_OPEN_WRITE)) {
00097 openstring = "rwb";
00098 } else if (openflags &CL_OPEN_READ) {
00099 openstring = "rb";
00100 } else if (openflags & CL_OPEN_WRITE) {
00101 openstring = "wb";
00102 } else {
00103 DebugPrint("Bad CLopen flags");
00104 Assert(0);
00105 return -1;
00106 }
00107
00108 cl_type = CLF_TYPE_INVALID;
00109
00110 if (openflags & CL_OPEN_WRITE) {
00111 if ((openflags & CL_WRITE_GZ) &&
00112 (cl_gz = gzopen(strcat(strcpy(buf, name), ".gz"), openstring))) {
00113 cl_type = CLF_TYPE_GZIP;
00114 } else if ((cl_plain = fopen(name, openstring))) {
00115 cl_type = CLF_TYPE_PLAIN;
00116 }
00117 } else {
00118 if (!(cl_plain = fopen(name, openstring))) {
00119 if ((cl_gz = gzopen(strcat(strcpy(buf, name), ".gz"), "rb"))) {
00120 cl_type = CLF_TYPE_GZIP;
00121 }
00122 } else {
00123 cl_type = CLF_TYPE_PLAIN;
00124
00125 if (fread(buf, 2, 1, cl_plain) == 1) {
00126 if (buf[0] == 0x1f) {
00127 fclose(cl_plain);
00128 if ((cl_gz = gzopen(name, "rb"))) {
00129 cl_type = CLF_TYPE_GZIP;
00130 } else {
00131 if (!(cl_plain = fopen(name, "rb"))) {
00132 cl_type = CLF_TYPE_INVALID;
00133 }
00134 }
00135 }
00136 }
00137 if (cl_type == CLF_TYPE_PLAIN) {
00138 rewind(cl_plain);
00139 }
00140 }
00141 }
00142
00143 if (cl_type == CLF_TYPE_INVALID) {
00144
00145 return -1;
00146 }
00147
00148 return 0;
00149 }
00150
00154 int CFile::close()
00155 {
00156 int tp;
00157 int ret;
00158
00159 ret = EOF;
00160
00161 if ((tp = cl_type) != CLF_TYPE_INVALID) {
00162 if (tp == CLF_TYPE_PLAIN) {
00163 ret = fclose(cl_plain);
00164 }
00165 if (tp == CLF_TYPE_GZIP) {
00166 ret = gzclose(cl_gz);
00167 }
00168 } else {
00169 errno = EBADF;
00170 }
00171 cl_type = CLF_TYPE_INVALID;
00172 return ret;
00173 }
00174
00181 int CFile::read(void *buf, size_t len)
00182 {
00183 int ret;
00184
00185 ret = 0;
00186
00187 if (cl_type != CLF_TYPE_INVALID) {
00188 if (cl_type == CLF_TYPE_PLAIN) {
00189 ret = fread(buf, 1, len, cl_plain);
00190 }
00191 if (cl_type == CLF_TYPE_GZIP) {
00192 ret = gzread(cl_gz, buf, len);
00193 }
00194 } else {
00195 errno = EBADF;
00196 }
00197 return ret;
00198 }
00199
00200 void CFile::flush()
00201 {
00202 if (cl_type != CLF_TYPE_INVALID) {
00203 if (cl_type == CLF_TYPE_PLAIN) {
00204 fflush(cl_plain);
00205 }
00206 if (cl_type == CLF_TYPE_GZIP) {
00207 gzflush(cl_gz, Z_SYNC_FLUSH);
00208 }
00209 } else {
00210 errno = EBADF;
00211 }
00212 }
00213
00214
00221 int CFile::printf(const char *format, ...)
00222 {
00223 int n;
00224 int size;
00225 int ret;
00226 int tp;
00227 char *p;
00228 va_list ap;
00229 char *newp;
00230 int oldsize;
00231
00232 size = 500;
00233 ret = -1;
00234 if ((p = new char[size]) == NULL) {
00235 return -1;
00236 }
00237 while (1) {
00238
00239 va_start(ap, format);
00240 n = vsnprintf(p, size, format, ap);
00241 va_end(ap);
00242
00243 if (n > -1 && n < size) {
00244 break;
00245 }
00246
00247 oldsize = size;
00248 if (n > -1) {
00249 size = n + 1;
00250 } else {
00251 size *= 2;
00252 }
00253 if ((newp = new char[size]) == NULL) {
00254 delete[] p;
00255 return -1;
00256 }
00257 memcpy(newp, p, oldsize);
00258 delete[] p;
00259 p = newp;
00260 }
00261
00262
00263 size = strlen(p);
00264
00265 if ((tp = cl_type) != CLF_TYPE_INVALID) {
00266 if (tp == CLF_TYPE_PLAIN) {
00267 ret = fwrite(p, size, 1, cl_plain);
00268 }
00269 if (tp == CLF_TYPE_GZIP) {
00270 ret = gzwrite(cl_gz, p, size);
00271 }
00272 } else {
00273 errno = EBADF;
00274 }
00275 delete[] p;
00276 return ret;
00277 }
00278
00285 int CFile::seek(long offset, int whence)
00286 {
00287 int tp;
00288 int ret;
00289
00290 ret = -1;
00291
00292 if ((tp = cl_type) != CLF_TYPE_INVALID) {
00293 if (tp == CLF_TYPE_PLAIN) {
00294 ret = fseek(cl_plain, offset, whence);
00295 }
00296 if (tp == CLF_TYPE_GZIP) {
00297 ret = gzseek(cl_gz, offset, whence);
00298 }
00299 } else {
00300 errno = EBADF;
00301 }
00302 return ret;
00303 }
00304
00308 long CFile::tell()
00309 {
00310 int tp;
00311 int ret;
00312
00313 ret = -1;
00314
00315 if ((tp = cl_type) != CLF_TYPE_INVALID) {
00316 if (tp == CLF_TYPE_PLAIN) {
00317 ret = ftell(cl_plain);
00318 }
00319 if (tp == CLF_TYPE_GZIP) {
00320 ret = gztell(cl_gz);
00321 }
00322 } else {
00323 errno = EBADF;
00324 }
00325 return ret;
00326 }
00327
00337 static int FindFileWithExtension(char *file, size_t filesize)
00338 {
00339 char buf[PATH_MAX];
00340
00341 if (!access(file, R_OK)) {
00342 return 1;
00343 }
00344 sprintf_s(buf, sizeof(buf), "%s.gz", file);
00345 if (!access(buf, R_OK)) {
00346 strcpy_s(file, filesize, buf);
00347 return 1;
00348 }
00349
00350 return 0;
00351 }
00352
00364 char *LibraryFileName(const char *file, char *buffer, size_t buffersize)
00365 {
00366
00367 strcpy_s(buffer, buffersize, file);
00368 if (*buffer == '/') {
00369 return buffer;
00370 }
00371 if (FindFileWithExtension(buffer, buffersize)) {
00372 return buffer;
00373 }
00374
00375
00376 sprintf_s(buffer, buffersize, "%s%s", UserDirectory.c_str(), *file == '~' ? file + 1 : file);
00377 if (FindFileWithExtension(buffer, buffersize)) {
00378 return buffer;
00379 }
00380
00381
00382 sprintf_s(buffer, buffersize, "%s/%s", StratagusLibPath.c_str(), file);
00383 if (FindFileWithExtension(buffer, buffersize)) {
00384 return buffer;
00385 }
00386
00387
00388
00389
00390 sprintf_s(buffer, buffersize, "%s/graphics/%s", StratagusLibPath.c_str(), file);
00391 if (FindFileWithExtension(buffer, buffersize)) {
00392 return buffer;
00393 }
00394
00395
00396
00397
00398 sprintf_s(buffer, buffersize, "%s/sounds/%s", StratagusLibPath.c_str(), file);
00399 if (FindFileWithExtension(buffer, buffersize)) {
00400 return buffer;
00401 }
00402
00403 DebugPrint("File `%s' not found\n" _C_ file);
00404 strcpy_s(buffer, buffersize, file);
00405 return buffer;
00406 }
00407
00417 int ReadDataDirectory(const char *dirname, int (*filter)(char *, FileList *),
00418 std::vector<FileList> &fl)
00419 {
00420 #ifndef _MSC_VER
00421 DIR *dirp;
00422 struct dirent *dp;
00423 #endif
00424 struct stat st;
00425 #ifdef _MSC_VER
00426 struct _finddata_t fileinfo;
00427 long hFile;
00428 #endif
00429 int n;
00430 int isdir = 0;
00431 char *np;
00432 char buffer[PATH_MAX];
00433 char *filename;
00434
00435 strcpy_s(buffer, sizeof(buffer), dirname);
00436 n = strlen(buffer);
00437 if (!n || buffer[n - 1] != '/') {
00438 buffer[n++] = '/';
00439 buffer[n] = 0;
00440 }
00441 np = buffer + n;
00442
00443 #ifndef _MSC_VER
00444 dirp = opendir(dirname);
00445 #endif
00446
00447 #ifndef _MSC_VER
00448 if (dirp) {
00449 while ((dp = readdir(dirp)) != NULL) {
00450 filename = dp->d_name;
00451 #else
00452 strcat_s(buffer, sizeof(buffer), "*.*");
00453 hFile = _findfirst(buffer, &fileinfo);
00454 if (hFile != -1L) {
00455 do {
00456 filename = fileinfo.name;
00457 #endif
00458
00459 if (strcmp(filename, ".") == 0) {
00460 continue;
00461 }
00462 if (strcmp(filename, "..") == 0) {
00463 continue;
00464 }
00465
00466 strcpy_s(np, sizeof(buffer) - (np - buffer), filename);
00467 if (stat(buffer, &st) == 0) {
00468 isdir = S_ISDIR(st.st_mode);
00469 if (isdir || S_ISREG(st.st_mode)) {
00470 FileList nfl;
00471 int i;
00472 if (isdir) {
00473 nfl.name = new_strdup(np);
00474 } else {
00475 nfl.type = -1;
00476 if (filter == NULL) {
00477 nfl.name = new_strdup(np);
00478 nfl.type = 1;
00479 } else if ((*filter)(buffer, &nfl) == 0) {
00480 continue;
00481 }
00482 }
00483 for (i = 0; i < (int)fl.size(); ++i) {
00484 if (nfl.type == fl[i].type) {
00485 if (strcmp(nfl.name, fl[i].name) < 0) {
00486 break;
00487 }
00488 } else {
00489 if (fl[i].type - nfl.type > 0) {
00490 break;
00491 }
00492 }
00493 }
00494 fl.insert(fl.begin() + i, nfl);
00495 }
00496 }
00497 #ifndef _MSC_VER
00498 }
00499 closedir(dirp);
00500 #else
00501 } while (_findnext(hFile, &fileinfo) == 0);
00502 _findclose(hFile);
00503 #endif
00504 }
00505 return fl.size();
00506 }
00507
00508
00509
00510 void FileWriter::printf(const char *format, ...)
00511 {
00512 char static_buf[1024];
00513 char *buf = static_buf;
00514 int ret;
00515 int buf_size = sizeof(static_buf);
00516
00517 va_list ap;
00518 va_start(ap, format);
00519 buf[buf_size - 1] = '\0';
00520 ret = vsnprintf(buf, buf_size - 1, format, ap);
00521 while (ret == -1 || ret >= buf_size - 1) {
00522 if (buf != static_buf) {
00523 delete[] buf;
00524 }
00525 buf_size <<= 1;
00526 buf = new char[buf_size];
00527 if (!buf) {
00528 fprintf(stderr, "Out of memory\n");
00529 ExitFatal(-1);
00530 }
00531 buf[buf_size - 1] = '\0';
00532 ret = vsnprintf(buf, buf_size - 1, format, ap);
00533 }
00534 va_end(ap);
00535 write(buf, strlen(buf));
00536
00537 if (buf != static_buf) {
00538 delete[] buf;
00539 }
00540 }
00541
00542
00543 class RawFileWriter : public FileWriter
00544 {
00545 FILE *file;
00546
00547 public:
00548 RawFileWriter(const std::string &filename) {
00549 file = fopen(filename.c_str(), "wb");
00550 if (!file) {
00551 fprintf(stderr,"Can't open file '%s' for writing\n", filename.c_str());
00552 throw FileException();
00553 }
00554 }
00555
00556 virtual ~RawFileWriter() {
00557 fclose(file);
00558 }
00559
00560 virtual int write(const char *data, unsigned int size)
00561 {
00562 return fwrite(data, size, 1, file);
00563 }
00564 };
00565
00566 class GzFileWriter : public FileWriter
00567 {
00568 gzFile file;
00569
00570 public:
00571 GzFileWriter(const std::string &filename) {
00572 file = gzopen(filename.c_str(), "wb9");
00573 if (!file) {
00574 fprintf(stderr,"Can't open file '%s' for writing\n", filename.c_str());
00575 throw FileException();
00576 }
00577 }
00578
00579 virtual ~GzFileWriter() {
00580 gzclose(file);
00581 }
00582
00583 virtual int write(const char *data, unsigned int size)
00584 {
00585 return gzwrite(file, data, size);
00586 }
00587 };
00588
00592 FileWriter *CreateFileWriter(const std::string &filename)
00593 {
00594 if (strcasestr(filename.c_str(), ".gz")) {
00595 return new GzFileWriter(filename);
00596 } else {
00597 return new RawFileWriter(filename);
00598 }
00599 }
00600