1 /*
2 * OpenTyrian: A modern cross-platform port of Tyrian
3 * Copyright (C) 2007-2009 The OpenTyrian Development Team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19 #include "file.h"
20 #include "opentyr.h"
21
22 #include "SDL.h"
23 #include <errno.h>
24
25 const char *custom_data_dir = "/usr/local/share/tyrian";
26
27 // finds the Tyrian data directory
data_dir(void)28 const char *data_dir( void )
29 {
30 const char *dirs[] =
31 {
32 custom_data_dir,
33 "data",
34 #ifdef TARGET_MACOSX
35 tyrian_game_folder(),
36 #endif
37 "/usr/share/opentyrian/data"
38 };
39
40 static const char *dir = NULL;
41
42 if (dir != NULL)
43 return dir;
44
45 for (uint i = 0; i < COUNTOF(dirs); ++i)
46 {
47 FILE *f = dir_fopen(dirs[i], "tyrian1.lvl", "rb");
48 if (f)
49 {
50 fclose(f);
51
52 dir = dirs[i];
53 break;
54 }
55 }
56
57 if (dir == NULL) // data not found
58 dir = "";
59
60 return dir;
61 }
62
63 // prepend directory and fopen
dir_fopen(const char * dir,const char * file,const char * mode)64 FILE *dir_fopen( const char *dir, const char *file, const char *mode )
65 {
66 char *path = malloc(strlen(dir) + 1 + strlen(file) + 1);
67 sprintf(path, "%s/%s", dir, file);
68
69 FILE *f = fopen(path, mode);
70
71 free(path);
72
73 return f;
74 }
75
76 // warn when dir_fopen fails
dir_fopen_warn(const char * dir,const char * file,const char * mode)77 FILE *dir_fopen_warn( const char *dir, const char *file, const char *mode )
78 {
79 FILE *f = dir_fopen(dir, file, mode);
80
81 if (f == NULL)
82 fprintf(stderr, "warning: failed to open '%s': %s\n", file, strerror(errno));
83
84 return f;
85 }
86
87 // die when dir_fopen fails
dir_fopen_die(const char * dir,const char * file,const char * mode)88 FILE *dir_fopen_die( const char *dir, const char *file, const char *mode )
89 {
90 FILE *f = dir_fopen(dir, file, mode);
91
92 if (f == NULL)
93 {
94 fprintf(stderr, "error: failed to open '%s': %s\n", file, strerror(errno));
95 fprintf(stderr, "error: One or more of the required Tyrian " TYRIAN_VERSION " data files could not be found.\n"
96 " Please read the README file.\n");
97 exit(1);
98 }
99
100 return f;
101 }
102
103 // check if file can be opened for reading
dir_file_exists(const char * dir,const char * file)104 bool dir_file_exists( const char *dir, const char *file )
105 {
106 FILE *f = dir_fopen(dir, file, "rb");
107 if (f != NULL)
108 fclose(f);
109 return (f != NULL);
110 }
111
112 // returns end-of-file position
ftell_eof(FILE * f)113 long ftell_eof( FILE *f )
114 {
115 long pos = ftell(f);
116
117 fseek(f, 0, SEEK_END);
118 long size = ftell(f);
119
120 fseek(f, pos, SEEK_SET);
121
122 return size;
123 }
124
125 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
126 // endian-swapping fread
efread(void * buffer,size_t size,size_t num,FILE * stream)127 size_t efread( void *buffer, size_t size, size_t num, FILE *stream )
128 {
129 size_t f = fread(buffer, size, num, stream);
130
131 switch (size)
132 {
133 case 2:
134 for (size_t i = 0; i < num; i++)
135 ((Uint16 *)buffer)[i] = SDL_Swap16(((Uint16 *)buffer)[i]);
136 break;
137 case 4:
138 for (size_t i = 0; i < num; i++)
139 ((Uint32 *)buffer)[i] = SDL_Swap32(((Uint32 *)buffer)[i]);
140 break;
141 case 8:
142 for (size_t i = 0; i < num; i++)
143 ((Uint64 *)buffer)[i] = SDL_Swap64(((Uint64 *)buffer)[i]);
144 break;
145 default:
146 break;
147 }
148
149 return f;
150 }
151
152 // endian-swapping fwrite
efwrite(void * buffer,size_t size,size_t num,FILE * stream)153 size_t efwrite( void *buffer, size_t size, size_t num, FILE *stream )
154 {
155 void *swap_buffer;
156
157 switch (size)
158 {
159 case 2:
160 swap_buffer = malloc(size * num);
161 for (size_t i = 0; i < num; i++)
162 ((Uint16 *)swap_buffer)[i] = SDL_SwapLE16(((Uint16 *)buffer)[i]);
163 break;
164 case 4:
165 swap_buffer = malloc(size * num);
166 for (size_t i = 0; i < num; i++)
167 ((Uint32 *)swap_buffer)[i] = SDL_SwapLE32(((Uint32 *)buffer)[i]);
168 break;
169 case 8:
170 swap_buffer = malloc(size * num);
171 for (size_t i = 0; i < num; i++)
172 ((Uint64 *)swap_buffer)[i] = SDL_SwapLE64(((Uint64 *)buffer)[i]);
173 break;
174 default:
175 swap_buffer = buffer;
176 break;
177 }
178
179 size_t f = fwrite(swap_buffer, size, num, stream);
180
181 if (swap_buffer != buffer)
182 free(swap_buffer);
183
184 return f;
185 }
186 #endif
187