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