home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / programs / qeu03 / q_files.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-02  |  9.2 KB  |  424 lines

  1. /*
  2.  * Copyright (C) 1996 by Raphael Quinet.  All rights reserved.
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and
  5.  * its documentation for any purpose and without fee is hereby
  6.  * granted, provided that the above copyright notice appear in all
  7.  * copies and that both that copyright notice and this permission
  8.  * notice appear in supporting documentation.  If more than a few
  9.  * lines of this code are used in a program which displays a copyright
  10.  * notice or credit notice, the following acknowledgment must also be
  11.  * displayed on the same screen: "This product includes software
  12.  * developed by Raphael Quinet for use in the Quake Editing Utilities
  13.  * project."  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR
  14.  * IMPLIED WARRANTY.
  15.  *
  16.  * More information about the QEU project can be found on the WWW:
  17.  * "http://www.montefiore.ulg.ac.be/~quinet/games/editing.html" or by
  18.  * mail: Raphael Quinet, 9 rue des Martyrs, B-4550 Nandrin, Belgium.
  19.  */
  20.  
  21. /*
  22.  * Q_FILES.C - Basic file loading and saving routines.
  23.  *
  24.  * This file was derived from D_WADS.C (Doom Editing Utilities 5.3),
  25.  * written by the DEU Team: Raphael Quinet, Brandon Wyber, Ted
  26.  * Vessenes and others.
  27.  */
  28.  
  29. #include "qeu.h"
  30. #include "q_misc.h"
  31. #ifdef QEU_UNIX
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #else
  35. #include <dos.h>
  36. #endif
  37. #include "q_files.h"
  38.  
  39.  
  40. /*
  41.  * Check if a file exists and is readable.
  42.  */
  43. Bool Exists(char *filename)
  44. {
  45.   FILE *test;
  46.  
  47.   if ((test = fopen(filename, "rb")) == NULL)
  48.     return FALSE;
  49.   fclose(test);
  50.   return TRUE;
  51. }
  52.  
  53.  
  54. /*
  55.  * Create the directories so that a file can be created with a full path name.
  56.  * Ignore the errors in mkdir (errors will be detected when file is created).
  57.  */
  58. void CreatePathToFile(char *filename)
  59. {
  60.   char *cp;
  61.   char *path;
  62.   
  63.   path = QStrDup(filename);
  64.   for (cp = path; *cp; cp++)
  65.     if (*cp == '/' || *cp == '\\')
  66.       {
  67.     *cp = '\0';
  68. #ifdef QEU_UNIX
  69.     if (cp != path)
  70.       mkdir(path, 0755);
  71.     *cp = '/';
  72. #else
  73.     if (cp != path)
  74.       mkdir(path);
  75.     *cp = '\\';
  76. #endif
  77.       }
  78.   QFree(path);
  79. }
  80.  
  81.  
  82. /*
  83.  * Convert a full path name so that it contains "\" for directories
  84.  * under DOS and "/" under other systems.
  85.  * The conversion is done in the string itself.
  86.  */
  87. char *ConvertFilePath(char *filename)
  88. {
  89.   char *cp;
  90.   
  91.   if (filename == NULL)
  92.     ProgError("BUG: cannot convert a NULL pathname");
  93.   for (cp = filename; *cp; cp++)
  94.     if (*cp == '/' || *cp == '\\')
  95.       {
  96. #ifdef QEU_DOS
  97.     *cp = '\\';
  98. #else
  99.     *cp = '/';
  100. #endif
  101.       }
  102.   return filename;
  103. }
  104.  
  105.  
  106. /*
  107.  * Convert a full path name so that it contains only "/" for directories.
  108.  * The conversion is done in the string itself.
  109.  */
  110. char *UNIXifyFilePath(char *filename)
  111. {
  112.   char *cp;
  113.   
  114.   if (filename == NULL)
  115.     ProgError("BUG: cannot convert a NULL pathname");
  116.   for (cp = filename; *cp; cp++)
  117.     if (*cp == '\\')
  118.       *cp = '/';
  119.   return filename;
  120. }
  121.  
  122.  
  123. /*
  124.  * Return a pointer to the first character of the name of a file,
  125.  * skipping all leading directories.
  126.  */
  127. char *GetBaseName(char *filename)
  128. {
  129.   char *p;
  130.  
  131.   if (filename == NULL)
  132.     return NULL;
  133.   for (p = filename; *p; p++)
  134.     if (*p == '/' || *p == '\\')
  135.       filename = p + 1;
  136.   return filename;
  137. }
  138.  
  139.  
  140. /*
  141.  * Return a pointer to the first character of the file extension, or NULL
  142.  * if the file name contains no dot (or if there are more than three
  143.  * characters after the dot).
  144.  */
  145. char *GetFileExtension(char *filename)
  146. {
  147.   char *extp;
  148.   char *p;
  149.  
  150.   if (filename == NULL)
  151.     return NULL;
  152.   extp = NULL;
  153.   for (p = filename; *p; p++)
  154.     {
  155.       if (*p == '.')
  156.         extp = p + 1;
  157. #ifdef QEU_DOS
  158.       else if (*p == '\\')
  159.         extp = NULL;
  160. #else
  161.       else if (*p == '/')
  162.         extp = NULL;
  163. #endif
  164.       if (extp != NULL && p == extp + 3)
  165.         extp = NULL;
  166.     }
  167.   return extp;
  168. }
  169.  
  170.  
  171. /*
  172.  * Return a newly allocated string containing the original file name with
  173.  * a new extension.  If oldext is not NULL, the old extension of the file
  174.  * is compared against oldext.  If they differ, this function returns NULL.
  175.  * If oldext is NULL, no check is performed.
  176.  */
  177. char *ChangeFileExtension(char *filename, char *oldext, char *newext)
  178. {
  179.   char *extp;
  180.   int   len;
  181.   char *newname;
  182.  
  183.   if (filename == NULL || newext == NULL)
  184.     return NULL;
  185.   extp = GetFileExtension(filename);
  186.   if (oldext != NULL && (extp == NULL || stricmp(extp, oldext)))
  187.     return NULL;
  188.   if (extp != NULL)
  189.     len = (int)(extp - filename);
  190.   else
  191.     len = strlen(filename) + 1;
  192.   newname = (char *)QMalloc(len + strlen(newext) + 1);
  193.   if (extp != NULL)
  194.     strncpy(newname, filename, len);
  195.   else
  196.     {
  197.       strcpy(newname, filename);
  198.       strcat(newname, ".");
  199.     }
  200.   strcat(newname, newext);
  201.   return newname;
  202. }
  203.  
  204.  
  205. /*
  206.  * Return the size of a file, or -1 if an error occurs.
  207.  * The current position is reset to the beginning of the file.
  208.  */
  209. Int32 GetFileSize(FILE *file)
  210. {
  211.   Int32 size;
  212.  
  213.   if (file == NULL)
  214.     return 0L;
  215.   if (fseek(file, 0L, SEEK_END) < 0)
  216.     return -1;
  217.   size = ftell(file);
  218.   if (size < 0)
  219.     return -1;
  220.   if (fseek(file, 0L, SEEK_SET) < 0)
  221.     return -1;
  222.   return size;
  223. }
  224.  
  225.  
  226. /*
  227.  * Read bytes from a file with error checking.  Read 32K chunks so that
  228.  * we don't have problems with old DOS.
  229.  * Returns FALSE if some error occured.
  230.  */
  231. Bool ReadBytes(FILE *file, void huge *addr, UInt32 size)
  232. {
  233.   while (size > 0x8000)
  234.     {
  235.       if (fread(addr, 1, 0x8000, file) != 0x8000)
  236.     return FALSE;
  237.       addr = (char huge *)addr + 0x8000;
  238.       size -= 0x8000;
  239.     }
  240.   if (fread(addr, 1, size, file) != size)
  241.     return FALSE;
  242.   return TRUE;
  243. }
  244.  
  245.  
  246. /*
  247.  * Output bytes to a binary file with error checking.  Write 32K chunks so
  248.  * that we don't have problems with old DOS.
  249.  * Returns FALSE if some error occured.
  250.  */
  251. Bool WriteBytes(FILE *file, void huge *addr, UInt32 size)
  252. {
  253.   while (size > 0x8000)
  254.     {
  255.       if (fwrite(addr, 1, 0x8000, file) != 0x8000)
  256.     return FALSE;
  257.       addr = (char huge *)addr + 0x8000;
  258.       size -= 0x8000;
  259.     }
  260.   if (fwrite(addr, 1, size, file) != size)
  261.     return FALSE;
  262.   return TRUE;
  263. }
  264.  
  265.  
  266. /*
  267.  * Copy bytes from a binary file to another with error checking.
  268.  * Returns FALSE if some error occured.
  269.  */
  270. Bool CopyBytes(FILE *dest, FILE *source, UInt32 size)
  271. {
  272.   void huge *data;
  273.  
  274.   data = QMalloc(0x8000 + 2);
  275.   while (size > 0x8000)
  276.     {
  277.       if (fread(data, 1, 0x8000, source) != 0x8000)
  278.     return FALSE;
  279.       if (fwrite(data, 1, 0x8000, dest) != 0x8000)
  280.     return FALSE;
  281.       size -= 0x8000;
  282.     }
  283.   if (fread(data, 1, size, source) != size)
  284.     return FALSE;
  285.   if (fwrite(data, 1, size, dest) != size)
  286.     return FALSE;
  287.   QFree(data);
  288.   return TRUE;
  289. }
  290.  
  291.  
  292. /*
  293.  * Get the type of a file from its magic number (first 4 bytes).  The
  294.  * file must be open and the current position is modified.  Note that
  295.  * some file formats have a magic number which is only 2 bytes, so it
  296.  * will be necessary to go back in the stream if such a file is read
  297.  * with this routine.
  298.  */
  299. int ReadMagic(FILE *file)
  300. {
  301.   UInt8 buf[4];
  302.  
  303.   if (ReadBytes(file, buf, 4) == FALSE)
  304.     return FTYPE_ERROR;
  305.   if (!strncmp(buf, "IWAD", 4))
  306.     return FTYPE_IWAD;
  307.   if (!strncmp(buf, "PWAD", 4))
  308.     return FTYPE_PWAD;
  309.   if (!strncmp(buf, "PACK", 4))
  310.     return FTYPE_PACK;
  311.   if (!strncmp(buf, "WAD2", 4))
  312.     return FTYPE_WAD2;
  313.   if (buf[0] == 0x17 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
  314.     return FTYPE_BSP;
  315.   if (!strncmp(buf, "IDPO", 4))
  316.     return FTYPE_MODEL;
  317.   if (!strncmp(buf, "IDSP", 4))
  318.     return FTYPE_SPRITE;
  319.   if (!strncmp(buf, "RIFF", 4))
  320.     return FTYPE_WAV;
  321.   if (!strncmp(buf, ".snd", 4))
  322.     return FTYPE_AU;
  323.   if (buf[0] == 'P')
  324.     {
  325.       if (buf[1] == '1')
  326.     return FTYPE_PBM_ASC;
  327.       if (buf[1] == '2')
  328.     return FTYPE_PGM_ASC;
  329.       if (buf[1] == '3')
  330.     return FTYPE_PPM_ASC;
  331.       if (buf[1] == '4')
  332.     return FTYPE_PBM_RAW;
  333.       if (buf[1] == '5')
  334.     return FTYPE_PGM_RAW;
  335.       if (buf[1] == '6')
  336.     return FTYPE_PPM_RAW;
  337.     }
  338.   if (buf[0] == 'B' && buf[1] == 'M')
  339.     return FTYPE_BMP;
  340.   if (!strncmp(buf, "GIF8", 4))
  341.     return FTYPE_GIF;
  342.   if (buf[0] == 0x0a && buf[1] == 0x05 && buf[2] == 0x01 && buf[3] == 0x08)
  343.     return FTYPE_PCX;
  344.   return FTYPE_UNKNOWN;
  345. }
  346.  
  347.  
  348. /*
  349.  * Open a file and get its type from the magic number (first 4 bytes).
  350.  * The type of the file is returned in *ftype_r, see symbols in q_files.h.
  351.  * Returns NULL if the file cannot be opened or read.
  352.  */
  353. FILE *OpenFileReadMagic(char *filename, int *ftype_r)
  354. {
  355.   FILE *f;
  356.  
  357.   *ftype_r = FTYPE_ERROR;
  358.   if ((f = fopen(filename, "rb")) == NULL)
  359.     return NULL;
  360.   *ftype_r = ReadMagic(f);
  361.   if (*ftype_r == FTYPE_ERROR)
  362.     {
  363.       fclose(f);
  364.       return NULL;
  365.     }
  366.   return f;
  367. }
  368.  
  369.  
  370. /*
  371.  * Read and write short and long integers with endianness conversion.
  372.  */
  373. #ifdef FAT_ENDIAN
  374. Bool ReadInt16(FILE *file, UInt16 huge *x)
  375. {
  376.   if (ReadBytes(file, x, 2L) == FALSE)
  377.     return FALSE;
  378.   *x = SwapInt16(*x);
  379.   return TRUE;
  380. }
  381.  
  382. Bool ReadInt32(FILE *file, UInt32 huge *x)
  383. {
  384.   if (ReadBytes(file, x, 4L) == FALSE)
  385.     return FALSE;
  386.   *x = SwapInt32(*x);
  387.   return TRUE;
  388. }
  389.  
  390. Bool ReadFloat32(FILE *file, Float32 huge *x)
  391. {
  392.   if (ReadBytes(file, x, 4L) == FALSE)
  393.     return FALSE;
  394.   *x = SwapFloat32(*x);
  395.   return TRUE;
  396. }
  397.  
  398. Bool WriteInt16(FILE *file, UInt16 huge *x)
  399. {
  400.   UInt16 n;
  401.  
  402.   n = SwapInt16(*x);
  403.   return WriteBytes(file, &n, 2L);
  404. }
  405.  
  406. Bool WriteInt32(FILE *file, UInt32 huge *x)
  407. {
  408.   UInt32 n;
  409.  
  410.   n = SwapInt32(*x);
  411.   return WriteBytes(file, &n, 4L);
  412. }
  413.  
  414. Bool WriteFloat32(FILE *file, Float32 huge *x)
  415. {
  416.   Float32 n;
  417.  
  418.   n = SwapFloat32(*x);
  419.   return WriteBytes(file, &n, 4L);
  420. }
  421. #endif /* FAT_ENDIAN */
  422.  
  423. /* end of file */
  424.