1 /*
2  * Support.cpp
3  * Copyright (C) 2007 by Bryan Duff <duff0097@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 
28 #include "SDL.h"
29 
30 #include "Support.h"
31 #include "Files.h"
32 #include "Config.h"
33 
34 extern Config config;
35 
Random()36 int Random()
37 {
38 #if RAND_MAX >= 65535
39   return (rand() % 65535) - 32767;
40 #else
41 #error please fix this for your platform
42 #endif
43 }
44 
Microseconds(UnsignedWide * microTickCount)45 void Microseconds(UnsignedWide * microTickCount)
46 {
47   /* NOTE: hi isn't used in BS, so it's not implemented here */
48   /* TODO: does game need microsecond precision? */
49   microTickCount->hi = 0;
50   microTickCount->lo = SDL_GetTicks() * 1000;
51 }
52 
GetMouse(Point * p)53 void GetMouse(Point * p)
54 {
55   int x;
56   int y;
57 
58   SDL_GetMouseState(&x, &y);
59 
60   p->h = x;
61   p->v = y;
62 }
63 
GetMouseRel(Point * p)64 void GetMouseRel(Point * p)
65 {
66   int x;
67   int y;
68 
69   SDL_GetRelativeMouseState(&x, &y);
70 
71   p->h = x;
72   p->v = y;
73 }
74 
75 // Mouse button click: Left 1, right 2
ButtonClick(int button)76 int ButtonClick(int button)
77 {
78   return (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(button));
79 }
80 
InitMouse()81 void InitMouse()
82 {
83 // STUB_FUNCTION;
84 }
85 
MoveMouse(int xcoord,int ycoord,Point * mouseloc)86 void MoveMouse(int xcoord, int ycoord, Point * mouseloc)
87 {
88   /* TODO: mouse warp is annoying when we can just grab the mouse */
89   if(config.fullscreen) {
90     SDL_WarpMouse(xcoord, ycoord);
91     SDL_PumpEvents();
92   }
93   GetMouse(mouseloc);
94 }
95 
DisposeMouse()96 void DisposeMouse()
97 {
98 // STUB_FUNCTION;
99 }
100 
101 #ifndef O_BINARY
102 #define O_BINARY 0
103 #endif
104 
105 #ifndef MAX_PATH
106 #define MAX_PATH 256
107 #endif
108 
find_filename(char * filename)109 static int find_filename(char *filename)
110 {
111   char *ptr;
112   char *cur;
113   char *next;
114   DIR *dir;
115   struct dirent *dirent;
116 
117   if(access(filename, R_OK) == 0) {
118     return 1;
119   }
120 
121   ptr = filename;
122 
123   while(*ptr) {
124     if(ptr == filename || *ptr == '/') {
125       if(*ptr == '/') {
126         cur = ptr + 1;
127       } else {
128         cur = ptr;
129       }
130 
131       if(*cur == 0) {
132         /* hit the end */
133         break;
134       }
135 
136       next = strchr(cur, '/');
137 
138       if(ptr != filename) {
139         *ptr = 0;
140       }
141 
142       if(next) {
143         *next = 0;
144       }
145 
146       if(ptr == filename && *ptr == '/') {
147         dir = opendir("/");
148       } else {
149         dir = opendir(filename);
150       }
151 
152       if(dir == NULL) {
153         if(ptr != filename) {
154           *ptr = '/';
155         }
156 
157         if(next) {
158           *next = 0;
159         }
160 
161         return 0;
162       }
163 
164       while((dirent = readdir(dir)) != NULL) {
165         if(strcasecmp(cur, dirent->d_name) == 0) {
166           strcpy(cur, dirent->d_name);
167           break;
168         }
169       }
170 
171       closedir(dir);
172 
173       if(ptr != filename) {
174         *ptr = '/';
175       }
176 
177       if(next) {
178         *next = '/';
179         ptr = next;
180       } else {
181         ptr++;
182       }
183     } else {
184       ptr++;
185     }
186   }
187 
188   if(access(filename, R_OK) == 0) {
189     return 1;
190   }
191 
192   return 0;
193 }
194 
195 //FIXME: help!
fix_filename(const char * original,char * fixed)196 static void fix_filename(const char *original, char *fixed)
197 {
198   const char *start;
199   int i;
200   int len;
201 
202   start = original;
203   if(original[0] == ':') {
204     start = &original[1];
205   }
206 
207   fixed[MAX_PATH - 1] = 0;
208 
209   strncpy(fixed, start, MAX_PATH);
210 
211   /* check to see if strncpy overwrote the terminator */
212   if(fixed[MAX_PATH - 1] != 0) {
213     fixed[MAX_PATH - 1] = 0;
214 
215     fprintf(stderr, "ERROR: file truncation error: %s -> %s\n",
216             original, fixed);
217   }
218 
219   len = strlen(fixed);
220   for(i = 0; i < len; i++) {
221     if(fixed[i] == ':') {
222       fixed[i] = '/';
223     }
224   }
225 
226   /*
227      here we would try to see if the file is available (game dir),
228      else try another dir
229 
230      really, this function also needs a flag to indicate whether
231      it should only go to local (write) or both (read)
232    */
233 
234   if(find_filename(fixed) == 0) {
235     fprintf(stderr, "find failed: %s\n", fixed);
236   }
237 }
238 
239 /*
240 Convenient Filename Hacks
241 */
cfh_fopen(const char * filename,const char * mode)242 FILE *cfh_fopen(const char *filename, const char *mode)
243 {
244   char filename1[MAX_PATH];
245 
246   fix_filename(filename, filename1);
247 
248   return fopen(filename1, mode);
249 }
250 
OpenFile(Str255 Name)251 int Files::OpenFile(Str255 Name)
252 {
253   char filename1[MAX_PATH];
254 
255   fix_filename((char *)Name, filename1);
256 
257   sFile = open(filename1, O_RDONLY | O_BINARY);
258   return sFile;
259 }
260 
EndLoad()261 void Files::EndLoad()
262 {
263   if(sFile != -1) {
264     FSClose(sFile);
265   }
266 
267   sFile = -1;
268 }
269 
270 #ifdef NOOGG
271 /*
272   Our own special magic version that fixes the filename.
273  */
alutLoadWAVFile_CFH(char * filename,ALenum * format,void ** wave,unsigned int * size,ALsizei * freq)274 void alutLoadWAVFile_CFH(char *filename, ALenum * format, void **wave,
275                          unsigned int *size, ALsizei * freq)
276 {
277   char filename1[MAX_PATH];
278   ALsizei format1, size1, bits1, freq1;
279 
280   fix_filename(filename, filename1);
281 
282   alutLoadWAV(filename1, wave, &format1, &size1, &bits1, &freq1);
283 
284   *format = format1;
285   *size = size1;
286   *freq = freq1;
287 }
288 
alutUnloadWAV_CFH(ALenum format,void * wave,unsigned int size,ALsizei freq)289 void alutUnloadWAV_CFH(ALenum format, void *wave, unsigned int size,
290                        ALsizei freq)
291 {
292   free(wave);
293 }
294 #else
295 #include <vorbis/vorbisfile.h>
296 
297 /*
298 Read the requested OGG file into memory, and extract the information required
299 by OpenAL
300 */
LoadOGG_CFH(char * filename,ALenum * format,void ** wave,unsigned int * size,ALsizei * freq)301 void LoadOGG_CFH(char *filename, ALenum * format, void **wave,
302                  unsigned int *size, ALsizei * freq)
303 {
304   char filename1[MAX_PATH];
305   ALsizei format1, size1, freq1;
306   void *wave1;
307   OggVorbis_File vf;
308   vorbis_info *vi;
309   FILE *fp;
310   int current_section;
311   char *buf;
312   int asize;
313   int err;
314   int eof;
315 
316 #if BYTE_ORDER == BIG_ENDIAN
317   const int endian = 1;
318 #else
319   const int endian = 0;
320 #endif
321 
322   /* try to find the real file (and place it in filename1) */
323   fix_filename(filename, filename1);
324 
325   /* open it for reading */
326   fp = fopen(filename1, "rb");
327   if(fp == NULL) {
328     fprintf(stderr, "ERROR: unable to open %s\n", filename1);
329     exit(EXIT_FAILURE);
330   }
331 
332   /* open it up */
333   err = ov_open(fp, &vf, NULL, 0);
334   if(err < 0) {
335     fprintf(stderr, "ERROR: vorbis error %d opening %s\n", -err, filename1);
336     exit(EXIT_FAILURE);
337   }
338 
339   /* get the ogg information */
340   vi = ov_info(&vf, -1);
341   if(vi == NULL) {
342     fprintf(stderr, "ERROR: vorbis error opening %s (ov_info failed)\n",
343             filename1);
344     exit(EXIT_FAILURE);
345   }
346 
347   /* calculate the byte size */
348   size1 = vi->channels * 2 * ov_pcm_total(&vf, -1);
349 
350   /* hack around some possible ogg vorbis weirdness */
351   asize = ((size1 + 2047) / 2048 + 1) * 2048;
352 
353   /* allocate our buffer */
354   wave1 = malloc(asize);
355 
356   if(wave1 == NULL) {
357     fprintf(stderr, "ERROR: could not allocate %d bytes while loading %s\n",
358             size1, filename1);
359     exit(EXIT_FAILURE);
360   }
361 
362   /* read it in */
363   eof = 0;
364   buf = (char *)wave1;
365 
366   while(!eof) {
367     long ret = ov_read(&vf, buf, 1024, endian, 2, 1,
368                        &current_section);
369 
370     if(ret == 0) {
371       /* end of file */
372       eof = 1;
373     } else if(ret < 0) {
374       /* some sort of error */
375 
376       /* TODO: is this ok to ignore? */
377     } else {
378       buf += ret;
379     }
380   }
381 
382   /* get the rest of the information */
383   if(vi->channels == 1) {
384     format1 = AL_FORMAT_MONO16;
385   } else if(vi->channels == 2) {
386     format1 = AL_FORMAT_STEREO16;
387   } else {
388     fprintf(stderr, "ERROR: ogg %s has %d channels\n", filename1, vi->channels);
389     exit(EXIT_FAILURE);
390   }
391 
392   freq1 = vi->rate;
393 
394   /* we are done with the ogg, so free it */
395   ov_clear(&vf);
396 
397   /* finall, give the values to the caller */
398   *format = format1;
399   *size = size1;
400   *freq = freq1;
401   *wave = wave1;
402 }
403 
404 /*
405 Free the OGG buffer
406 */
FreeOGG(ALenum format,void * wave,unsigned int size,ALsizei freq)407 void FreeOGG(ALenum format, void *wave, unsigned int size, ALsizei freq)
408 {
409   free(wave);
410 }
411 #endif
412