1 /**
2  * @file tools.c
3  * @brief handle memory allocation and file access
4  * @created 1999-08-19
5  * @date 2011-02-17
6  */
7 /*
8  * copyright (c) 1998-2015 TLK Games all rights reserved
9  * $Id: tools.c,v 1.53 2012/08/26 15:44:26 gurumeditation Exp $
10  *
11  * Powermanga is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * Powermanga is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24  * MA  02110-1301, USA.
25  */
26 #include "config.h"
27 #include "powermanga.h"
28 #include "log_recorder.h"
29 #include "tools.h"
30 #include "config_file.h"
31 #include <stdio.h>
32 
33 #if defined (USE_MALLOC_WRAPPER)
34 /**
35  * memory-block description structure
36  */
37 typedef struct
38 {
39   /** Pointer to memory zone */
40   char *addr;
41   /** Size of memory zone in bytes */
42   Sint32 size;
43 }
44 mem_struct;
45 mem_struct *memory_list_base = NULL;
46 mem_struct *memory_list = NULL;
47 /** Size of memory table */
48 static Uint32 memory_list_size;
49 /** Maximum number of memory zones being able to be allocated */
50 static Uint32 mem_maxnumof_zones;
51 /** Number of currently memory zones */
52 Uint32 mem_numof_zones;
53 /** Total memory size currently allocated */
54 Uint32 mem_total_size;
55 /** Maximum number of memory zones reached */
56 static Uint32 mem_maxreached_zones;
57 #endif
58 Uint32 loops_counter;
59 #ifdef POWERMANGA_SDL
60 static Uint32 time_begin;
61 static Uint32 ticks_previous;
62 #else
63 static struct timeval time_begin;
64 static struct timeval ticks_previous;
65 #endif
66 static Uint16 little_endian_to_ushort (Uint16 * _pMem);
67 /** Prefixe where the data files are localised */
68 static const char prefix_dir[] = PREFIX;
69 float *precalc_sin = NULL;
70 float *precalc_cos = NULL;
71 float *precalc_sin128 = NULL;
72 float *precalc_cos128 = NULL;
73 /** Table used for displacement of the guided missile */
74 float depix[13][32];
75 /** Table used for displacement of the guided missile */
76 float depiy[13][32];
77 #if defined(_WIN32_WCE)
78 /** The fully-qualified path for the directory that contains
79  * the Powermanga executable on Windows Mobile */
80 static char *wince_module_pathname = NULL;
81 #endif
82 
83 /**
84  * Initialize the memory table for our malloc() wrapper
85  * @param numofzones Maximum number of memory zones
86  * @return Boolean value on success or failure
87  */
88 #if defined (USE_MALLOC_WRAPPER)
89 bool
memory_init(Uint32 numofzones)90 memory_init (Uint32 numofzones)
91 {
92   Uint32 i;
93   mem_struct *memlst = memory_list_base;
94   /* clear number of memory zones reserved */
95   mem_numof_zones = 0;
96   /* maximum number of memory zones being able to be allocated */
97   mem_maxnumof_zones = numofzones;
98   mem_maxreached_zones = 0;
99   memory_list_size = mem_maxnumof_zones * sizeof (mem_struct);
100   mem_total_size = memory_list_size;
101   memory_list_base = (mem_struct *) malloc (memory_list_size);
102   if (memory_list_base == NULL)
103     {
104       LOG_ERR ("malloc() failed");
105       return FALSE;
106     }
107   memory_list = memory_list_base;
108 
109   /* clear memory table */
110   memlst = memory_list_base;
111   for (i = 0; i < mem_maxnumof_zones; i++, memlst++)
112     {
113       memlst->addr = NULL;
114       memlst->size = 0;
115     }
116   return TRUE;
117 }
118 #endif
119 
120 /**
121  * Allocate memory, malloc() wrapper
122  * @param memsize Size in bytes to alloc
123  * @return Pointer to the allocated memory or NULL if an error occurred
124  */
125 char *
memory_allocation(Uint32 memsize)126 memory_allocation (Uint32 memsize)
127 {
128   char *addr = NULL;
129 #if defined (USE_MALLOC_WRAPPER)
130   if (mem_numof_zones >= mem_maxnumof_zones)
131     {
132       LOG_ERR (" table overflow; size request %i bytes;"
133                " total allocate: %i in %i zones",
134                memsize, mem_total_size, mem_numof_zones);
135       return NULL;
136     }
137 #endif
138   addr = (char *) malloc (memsize);
139   if (addr == NULL)
140     {
141 #if defined (USE_MALLOC_WRAPPER)
142       LOG_ERR ("malloc() return NULL; size request %i bytes;"
143                " total allocate: %i in %i zones",
144                memsize, mem_total_size, mem_numof_zones);
145 #else
146       LOG_ERR ("malloc() return NULL; size request %i bytes", memsize);
147 #endif
148       return NULL;
149     }
150   memset (addr, 0, sizeof (char) * memsize);
151 #if defined (USE_MALLOC_WRAPPER)
152   mem_total_size += memsize;
153   memory_list->addr = addr;
154   memory_list->size = memsize;
155   memory_list += 1;
156   mem_numof_zones++;
157   if (mem_numof_zones > mem_maxreached_zones)
158     {
159       mem_maxreached_zones = mem_numof_zones;
160     }
161 #endif
162   return addr;
163 }
164 
165 /**
166  * Deallocates the memory, free() wrapper
167  * @param addr Pointer to memory
168  */
169 void
free_memory(char * addr)170 free_memory (char *addr)
171 {
172 #if defined (USE_MALLOC_WRAPPER)
173   mem_struct *memlist;
174   mem_struct *memlist_src;
175   Uint32 i;
176 #endif
177   if (addr == NULL)
178     {
179       LOG_ERR ("try to release a null address!");
180       return;
181     }
182 #if defined (USE_MALLOC_WRAPPER)
183   memlist = memory_list_base;
184   for (i = 0; i < mem_numof_zones; i++, memlist++)
185     {
186       /* search address */
187       if (memlist->addr == addr)
188         {
189           free (addr);
190           memlist_src = memlist + 1;
191           mem_total_size -= memlist->size;
192           mem_numof_zones--;
193           memory_list--;
194           while (i < mem_numof_zones)
195             {
196               memlist->addr = memlist_src->addr;
197               memlist->size = memlist_src->size;
198               i++;
199               memlist++;
200               memlist_src++;
201             }
202           memlist->addr = NULL;
203           memlist->size = 0;
204           addr = NULL;
205           break;
206         }
207     }
208   if (addr != NULL)
209     {
210       LOG_ERR ("can't release the address %p", addr);
211     }
212 #else
213   free (addr);
214 #endif
215 }
216 
217 /**
218  * Releases all memory allocated
219  * @param verbose Verbose level
220  */
221 #if defined (USE_MALLOC_WRAPPER)
222 void
memory_releases_all(void)223 memory_releases_all (void)
224 {
225   Uint32 i;
226   char *addr;
227   mem_struct *memlist = memory_list_base;
228   LOG_INF ("maximum of memory which were allocated during the game: %i",
229            mem_maxreached_zones);
230   if (mem_numof_zones > 0)
231     {
232       LOG_WARN ("%i zones were not released", mem_numof_zones);
233       for (i = 0; i < mem_numof_zones; i++, memlist++)
234         {
235           addr = memlist->addr;
236           if (addr != NULL)
237             {
238               LOG_WARN ("-> free(%p); size=%i", memlist->addr, memlist->size);
239               free (addr);
240               memlist->addr = NULL;
241               memlist->size = 0;
242             }
243         }
244     }
245   if (memory_list_base != NULL)
246     {
247       free (memory_list_base);
248       memory_list_base = NULL;
249     }
250   mem_numof_zones = 0;
251 }
252 #endif
253 
254 /**
255  * Load and decompress a PCX file
256  * @param filename Filename specified by path
257  * @return Pointer to a bitmap_desc structure or null if an error occurred
258  */
259 bitmap_desc *
load_pcx(const char * filename)260 load_pcx (const char *filename)
261 {
262   Uint32 width, height, depth, size, ptr;
263   Uint16 *ptr16;
264   unsigned char numof_bytes;
265   unsigned char val;
266   Uint32 i, j, total;
267   unsigned char *filedata, *pixel;
268   bitmap_desc *bmp;
269   filedata = (unsigned char *) loadfile (filename, &size);
270   if (filedata == NULL)
271     {
272       return NULL;
273     }
274   ptr16 = (Uint16 *) filedata;
275   width = (little_endian_to_ushort (ptr16 + 4)
276            - little_endian_to_ushort (ptr16 + 2)) + 1;
277   height = (little_endian_to_ushort (ptr16 + 5)
278             - little_endian_to_ushort (ptr16 + 3)) + 1;
279   /* bits per pixel */
280   depth = filedata[3];
281 
282   /* allocate bitmap description structure memory */
283   bmp = (bitmap_desc *) memory_allocation (sizeof (bitmap_desc));
284   if (bmp == NULL)
285     {
286       LOG_ERR ("not enough memory to allocate 'bmp'");
287       return NULL;
288     }
289   bmp->width = width;
290   bmp->height = height;
291   bmp->depth = depth;
292   bmp->size = width * height * (depth >> 3);
293   /* allocate bitmap memory */
294   bmp->pixel = memory_allocation (bmp->size);
295   if (bmp->pixel == NULL)
296     {
297       LOG_ERR ("height=%i / width=%i", filename, width, height);
298       LOG_ERR ("not enough memory to allocate %i bytes", bmp->size);
299       free_memory ((char *) bmp);
300       return NULL;
301     }
302   /* decompress rle */
303   pixel = (unsigned char *) bmp->pixel;
304   total = 0;
305   i = size - 768;
306   ptr = 128;
307   while (ptr < i)
308     {
309       if ((filedata[ptr] & 0xC0) == 0xC0)
310         {
311           numof_bytes = filedata[ptr] & 0x3F;
312           ptr++;
313         }
314       else
315         {
316           numof_bytes = 1;
317         }
318       val = filedata[ptr];
319       /* bug fixed by Samuel Hocevar */
320       total += numof_bytes;
321       if (total >= bmp->size)
322         {
323           break;
324         }
325       for (j = 0; j < numof_bytes; j++)
326         {
327           *pixel = val;
328           pixel++;
329         }
330       ptr++;
331     }
332   free_memory ((char *) filedata);
333   LOG_DBG ("filename: \"%s\"; height:%i; width:%i; size:%i bytes", filename,
334            width, height, bmp->size);
335   return bmp;
336 }
337 
338 /**
339  * Read a little-endian 16-bit signed short
340  * @param pointer to a 16-bit signed short
341  * @return the big or little endian 16-bit signed short value
342  */
343 Sint16
little_endian_to_short(Sint16 * addr)344 little_endian_to_short (Sint16 * addr)
345 {
346   /* value be extracted byte by byte,
347    * do not cast odd addresses to a pointer.
348    * Long word read on odd address is illegal on ARM architecture */
349   Sint16 value;
350   unsigned char *mem = (unsigned char *) addr;
351   value = mem[1];
352   value <<= 8;
353   value = (Sint16) (value | mem[0]);
354   return value;
355 }
356 
357 /**
358  * Read a little-endian 16-bit unsigned short
359  * @param pointer to a 16-bit unsigned short
360  * @return the big or little endian 16-bit unsigned short value
361  */
362 static Uint16
little_endian_to_ushort(Uint16 * addr)363 little_endian_to_ushort (Uint16 * addr)
364 {
365 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
366   Sint16 val = 0;
367   unsigned char *ptr = (unsigned char *) addr;
368   val = ptr[1];
369   val <<= 8;
370   val += ptr[0];
371   return val;
372 #else
373   return *addr;
374 #endif
375 }
376 
377 /**
378  * Read a little-endian 32-bit signed long
379  * @param pointer to a 32-bit signed long
380  * @return the big or little endian 32-bit signed long value
381  */
382 Sint32
little_endian_to_int(Sint32 * addr)383 little_endian_to_int (Sint32 * addr)
384 {
385   /* value be extracted byte by byte,
386    * do not cast odd addresses to a pointer.
387    * Long word read on odd address is illegal on ARM architecture */
388   Sint32 value;
389   unsigned char *mem = (unsigned char *) addr;
390   value = mem[3];
391   value <<= 8;
392   value += mem[2];
393   value <<= 8;
394   value += mem[1];
395   value <<= 8;
396   value += mem[0];
397   return value;
398 }
399 
400 /**
401  * Write a little-endian 32-bit signed long
402  * @param pointer to a 32-bit signed long
403  * @return the big or little endian 32-bit signed long value
404  */
405 void
int_to_little_endian(Sint32 value,Sint32 * addr)406 int_to_little_endian (Sint32 value, Sint32 * addr)
407 {
408   /* value be writed byte by byte,
409    * do not cast odd addresses to a pointer.
410    * Long word read on odd address is illegal on ARM architecture */
411   unsigned char *mem = (unsigned char *) addr;
412   mem[0] = (unsigned char) (value & 0xff);
413   value >>= 8;
414   mem[1] = (unsigned char) (value & 0xff);
415   value >>= 8;
416   mem[2] = (unsigned char) (value & 0xff);
417   value >>= 8;
418   mem[3] = (unsigned char) (value & 0xff);
419 }
420 
421 /**
422  * Convert a 32-bit zone memory
423  * @param pointer to a 4 bytes in memory
424  */
425 void
convert32bits_2bigendian(unsigned char * memory)426 convert32bits_2bigendian (unsigned char *memory)
427 {
428   unsigned char b0, b1, b2, b3;
429   b0 = memory[1];
430   b1 = memory[0];
431   b2 = memory[3];
432   b3 = memory[2];
433   memory[0] = b2;
434   memory[1] = b3;
435   memory[2] = b0;
436   memory[3] = b1;
437 }
438 
439 /**
440  * Creates a string representing an integer number
441  * @param value the integer value to be converted
442  * @param padding length of the string
443  * @param str the string representation of the number
444  */
445 void
integer_to_ascii(Sint32 value,Uint32 padding,char * str)446 integer_to_ascii (Sint32 value, Uint32 padding, char *str)
447 {
448   char *ptr = str + padding - 1;
449   bool neg = (value < 0);
450   if (neg)
451     {
452       value = -value;
453       --padding;
454     }
455   do
456     {
457       *ptr-- = (char) (value % 10) + '0';
458       value /= 10;
459       --padding;
460     }
461   while (value && padding > 0);
462   for (; padding > 0; --padding)
463     {
464       *ptr-- = '0';
465     }
466   if (neg)
467     {
468       *ptr-- = '-';
469     }
470 }
471 
472 /**
473  * Frees the memory used for the full pathname of Powermagane directory
474  */
475 #if defined(_WIN32_WCE)
476 void
free_wince_module_pathname(void)477 free_wince_module_pathname (void)
478 {
479   if (wince_module_pathname != NULL)
480     {
481       free_memory (wince_module_pathname);
482       wince_module_pathname = NULL;
483     }
484 }
485 
486 /**
487  * Convert a wide-character string to a new character string
488  * @param source Pointer to the wide-chars string to be converted
489  * @param length The number of wide-chars in the source string
490  * @param code_page The code page used to perform the conversion
491  * @return Pointer to the buffer to receive the translated string or
492  *         NULL upon failure. This buffer must be released once it is
493  *         not needed anymore
494  */
495 char *
wide_char_to_bytes(wchar_t * source,Uint32 length,Uint32 code_page)496 wide_char_to_bytes (wchar_t * source, Uint32 length, Uint32 code_page)
497 {
498   Sint32 size;
499   char *dest;
500   if (source == NULL)
501     {
502       return NULL;
503     }
504   if (length == 0)
505     {
506       length = wcslen (source) + 1;
507     }
508   size = WideCharToMultiByte (code_page, 0, source, length,
509                               NULL, 0, NULL, NULL);
510   if (size == 0)
511     {
512       LOG_ERR ("WideCharToMultiByte() failed!");
513       return NULL;
514     }
515   dest = memory_allocation (size);
516   if (dest == NULL)
517     {
518       LOG_ERR ("not enough memory to allocate %i bytes", size);
519     }
520   size = WideCharToMultiByte (code_page, 0, source, length,
521                               dest, size, NULL, NULL);
522   if (size == 0)
523     {
524       LOG_ERR ("WideCharToMultiByte() failed!");
525       free_memory (dest);
526       return NULL;
527     }
528   dest[size] = 0;
529   return dest;
530 }
531 #endif
532 
533 /** Directory list to locate a file */
534 static const char *data_directories[] = {
535   /* normally unused, except when running from the source directory... */
536   ".",
537   /* special value meaning "$(PREFIX)/share/powermanga/" */
538   /* also marks end of list */
539   0
540 };
541 
542 /**
543  * Locate a file under one of the data directories
544  * @param name Name of file relative to data directory
545  * @return Pointer to a malloc'd buffer containing the name under which the
546  * file was found (free()-ing the buffer is the responsibility of the caller.)
547  * or NULL if could not locate file (not found, or not enough memory, or the
548  * name given was absolute)
549  * @author Andre Majorel
550  */
551 char *
locate_data_file(const char * const name)552 locate_data_file (const char *const name)
553 {
554 #if defined(_WIN32_WCE)
555   wchar_t *filename;
556   char *pathname;
557   char c;
558   Uint32 i, j;
559   Uint32 len;
560   if (wince_module_pathname == NULL)
561     {
562       len = MAX_PATH * sizeof (wchar_t);
563       filename = (wchar_t *) memory_allocation (len);
564       if (filename == NULL)
565         {
566           LOG_ERR ("not enough memory to allocate %i bytes", len);
567           return NULL;
568         }
569       if (GetModuleFileName (NULL, filename, MAX_PATH) == 0)
570         {
571           LOG_ERR ("GetModuleFileName () failed!");
572           free_memory ((char *) filename);
573           return NULL;
574         }
575       /* removes the application name in the pathname */
576       i = wcslen (filename) - 1;
577       while (filename[i] != L'\\')
578         {
579           i--;
580         }
581       filename[i + 1] = 0;
582       wince_module_pathname = wide_char_to_bytes (filename, 0, CP_ACP);
583       if (wince_module_pathname == NULL)
584         {
585           LOG_ERR ("wide_char_to_bytes () failed!");
586           free_memory ((char *) filename);
587           return NULL;
588         }
589       free_memory ((char *) filename);
590     }
591   len = strlen (wince_module_pathname) + strlen (name) + 1;
592   pathname = memory_allocation (len);
593   if (pathname == NULL)
594     {
595       LOG_ERR ("not enough memory to allocate %i bytes", len);
596       return NULL;
597     }
598   strcpy (pathname, wince_module_pathname);
599   j = strlen (pathname);
600   for (i = 0; i < strlen (name); i++, j++)
601     {
602       c = name[i];
603       if (c == '/')
604         {
605           pathname[j] = '\\';
606         }
607       else
608         {
609           pathname[j] = c;
610         }
611     }
612   pathname[j] = 0;
613   return pathname;
614 
615 #else
616   static const char bogus = '\0';
617   static const char *home_dir;
618   const char **p;
619   char *pathname;
620 #ifdef WIN32
621   struct _stat s;
622 #else
623   struct stat s;
624 #endif
625   const char *subdir = "/share/powermanga/";
626 
627   if (name == NULL)
628     {
629       LOG_ERR ("NULL pointer was passed as an argument!");
630       return NULL;
631     }
632   /* if absolute path, return a pointer to a duplicate string */
633   if (*name == '/')
634     {
635       return string_duplicate (name);
636     }
637   /* process each folder of the list */
638   for (p = data_directories;; p++)
639     {
640       if (*p == 0)
641         {
642           pathname =
643             memory_allocation (strlen (prefix_dir) + strlen (subdir) +
644                                strlen (name) + 1);
645           if (pathname == NULL)
646             {
647               fflush (stdout);
648               LOG_ERR ("not enough memory");
649               return NULL;
650             }
651           strcpy (pathname, prefix_dir);
652           strcat (pathname, subdir);
653           strcat (pathname, name);
654         }
655       /* not user anymore */
656       else if (**p == '~')
657         {
658           home_dir = &bogus;
659           if (home_dir == &bogus)
660             {
661               home_dir = getenv ("HOME");
662             }
663           if (home_dir == 0)
664             {
665               /* $HOME not set. Skip this directory */
666               continue;
667             }
668           pathname = memory_allocation (strlen (home_dir)
669                                         + 1 + strlen (*p + 1) + 1 +
670                                         strlen (name) + 1);
671           if (pathname == NULL)
672             {
673               fflush (stdout);
674               LOG_ERR ("not enough memory");
675               return NULL;
676             }
677           strcpy (pathname, home_dir);
678           strcat (pathname, *p + 1);
679           strcat (pathname, "/");
680           strcat (pathname, name);
681         }
682       else
683         {
684           /* check if the file is located in current directory */
685           pathname = memory_allocation (strlen (*p) + 1 + strlen (name) + 1);
686           if (pathname == NULL)
687             {
688               fflush (stdout);
689               LOG_ERR ("not enough memory");
690               return NULL;
691             }
692           strcpy (pathname, *p);
693           strcat (pathname, "/");
694           strcat (pathname, name);
695         }
696 #ifdef WIN32
697       if (_stat (pathname, &s) == 0 && !(s.st_mode & _S_IFDIR))
698         {
699           return pathname;
700         }
701 
702 #else
703       if (stat (pathname, &s) == 0 && !S_ISDIR (s.st_mode))
704         {
705           return pathname;
706         }
707 #endif
708       free_memory (pathname);
709       if (*p == 0)
710         {
711           break;
712         }
713     }
714   /* not found */
715   return NULL;
716 #endif
717 }
718 
719 
720 /**
721  * Allocate memory and load a file
722  * @param filename Filename specified by path
723  * @return File data buffer pointer
724  */
725 char *
load_file(const char * const filename)726 load_file (const char *const filename)
727 {
728   Uint32 filesize;
729   return loadfile (filename, &filesize);
730 }
731 
732 /**
733  * Allocate memory and load a file (filename with a language code)
734  * @param filename Filename specified by path
735  * @param fsize Pointer on the size of file which will be loaded
736  * @return Pointer to the file data
737  */
738 char *
loadfile_with_lang(const char * const filename,Uint32 * const fsize)739 loadfile_with_lang (const char *const filename, Uint32 * const fsize)
740 {
741   const char *lang;
742   char *data, *fname;
743   if (filename == NULL || strlen (filename) == 0)
744     {
745       LOG_ERR ("filename is a NULL string");
746       return NULL;
747     }
748 
749   fname = memory_allocation (strlen (filename) + 1);
750   if (fname == NULL)
751     {
752       LOG_ERR ("filename: \"%s\" not enough memory"
753                " to allocate %i bytes", filename,
754                (Uint32) (strlen (filename) + 1));
755       return NULL;
756     }
757   strcpy (fname, filename);
758   lang = configfile_get_lang ();
759   sprintf (fname, filename, lang);
760   LOG_DBG ("file \"%s\" was loaded in memory", fname);
761   data = loadfile (fname, fsize);
762   free_memory (fname);
763   return data;
764 }
765 
766 /**
767  * Allocate memory and load a file (filename with a number)
768  * @param filename Filename specified by path
769  * @param num Interger to convert in string
770  * @return Pointer to the file data
771  */
772 char *
loadfile_num(const char * const filename,Sint32 num)773 loadfile_num (const char *const filename, Sint32 num)
774 {
775   char *data, *fname;
776 
777   if (filename == NULL || strlen (filename) == 0)
778     {
779       LOG_ERR ("filename is a NULL string");
780       return NULL;
781     }
782 
783   fname = memory_allocation (strlen (filename) + 1);
784   if (fname == NULL)
785     {
786       LOG_ERR ("filename: \"%s\"; num: %i; "
787                "not enough memory to allocate %i bytes",
788                filename, num, (Uint32) (strlen (filename) + 1));
789       return NULL;
790     }
791   sprintf (fname, filename, num);
792   LOG_DBG ("file \"%s\" was loaded in memory", fname);
793   data = load_file (fname);
794   free_memory (fname);
795   return data;
796 }
797 
798 /**
799  * Allocate memory and load a file there
800  * @param filename the file which should be loaded
801  * @param fsize pointer on the size of file which will be loaded
802  * @return file data buffer pointer
803  */
804 char *
loadfile(const char * const filename,Uint32 * const fsize)805 loadfile (const char *const filename, Uint32 * const fsize)
806 {
807   char *buffer;
808   char *pathname = locate_data_file (filename);
809   if (pathname == NULL)
810     {
811       LOG_ERR ("can't locate file %s", filename);
812       return NULL;
813     }
814   buffer = load_absolute_file (pathname, fsize);
815   if (buffer == NULL)
816     {
817       free_memory (pathname);
818       return NULL;
819     }
820   free_memory (pathname);
821   return buffer;
822 }
823 
824 
825 /**
826  * Getting size of a file
827  * @param fstream Pointer to a FILE object that identifies the stream
828  * @retrun Size of file in bytes or zero if an error occurred
829  */
830 size_t
get_file_size(FILE * fstream)831 get_file_size (FILE * fstream)
832 {
833   size_t fsize;
834 #if defined(_WIN32_WCE)
835   if (fseek (fstream, 0, SEEK_END) != 0)
836     {
837       LOG_ERR ("fseek() failed");
838       return 0;
839     }
840   fsize = ftell (fstream);
841   if (fsize == -1)
842     {
843       LOG_ERR ("fread() failed");
844       return 0;
845     }
846   if (fseek (fstream, 0, SEEK_SET) != 0)
847     {
848       LOG_ERR ("fseek() failed");
849     }
850 #else
851   struct stat sb;
852   if (fstat (fileno (fstream), &sb))
853     {
854       LOG_ERR ("fstat() failed: %s", strerror (errno));
855       return 0;
856     }
857   fsize = sb.st_size;
858 #endif
859   return fsize;
860 }
861 
862 /**
863  * Allocate memory and load a file there
864  * @param filename the file which should be loaded
865  * @param fsize pointer on the size of file which will be loaded
866  * @return file data buffer pointer
867  */
868 char *
load_absolute_file(const char * const filename,Uint32 * const filesize)869 load_absolute_file (const char *const filename, Uint32 * const filesize)
870 {
871   size_t fsize;
872   FILE *fstream;
873   char *buffer;
874 #ifdef WIN32
875   fstream = fopen (filename, "rb");
876 #else
877   fstream = fopen (filename, "r");
878 #endif
879   if (fstream == NULL)
880     {
881 #if defined(_WIN32_WCE)
882       LOG_ERR ("can't open file  %s", filename);
883 #else
884       LOG_ERR ("can't open file  %s (%s)", filename, strerror (errno));
885 #endif
886       return NULL;
887     }
888   fsize = get_file_size (fstream);
889   (*filesize) = fsize;
890   if (fsize == 0)
891     {
892       fclose (fstream);
893       LOG_ERR ("file %s is empty!", filename);
894       return NULL;
895     }
896   buffer = memory_allocation (fsize);
897   if (buffer == NULL)
898     {
899       LOG_ERR ("not enough memory to allocate %i bytes!",
900                filename, (Sint32) fsize);
901       fclose (fstream);
902       return NULL;
903     }
904   if (fread (buffer, sizeof (char), fsize, fstream) != fsize)
905     {
906       free_memory (buffer);
907 #if defined(_WIN32_WCE)
908       LOG_ERR ("can't read file \"%s\"", filename);
909 #else
910       LOG_ERR ("can't read file \"%s\" (%s)", filename, strerror (errno));
911 #endif
912       fclose (fstream);
913       return NULL;
914     }
915   fclose (fstream);
916   LOG_DBG ("file \"%s\" was loaded in memory", filename);
917   return buffer;
918 }
919 
920 /**
921  * Load a file in memory buffer already allocated
922  * @param filename the file which should be loaded
923  * @param buffer pointer to the buffer where data are stored
924  * @return boolean value on success or failure
925  */
926 bool
loadfile_into_buffer(const char * const filename,char * const buffer)927 loadfile_into_buffer (const char *const filename, char *const buffer)
928 {
929   size_t fsize;
930   FILE *fstream;
931   char *pathname = locate_data_file (filename);
932   if (pathname == NULL)
933     {
934       LOG_ERR ("can't locate file: '%s'", filename);
935       return FALSE;
936     }
937 #ifdef WIN32
938   fstream = fopen (pathname, "rb");
939 #else
940   fstream = fopen (pathname, "r");
941 #endif
942   if (fstream == NULL)
943     {
944 #if defined(_WIN32_WCE)
945       LOG_ERR ("can't open \"%s\" file", pathname);
946 #else
947       LOG_ERR ("can't open \"%s\" file (%s)", pathname, strerror (errno));
948 #endif
949       free_memory (pathname);
950       return FALSE;
951     }
952   fsize = get_file_size (fstream);
953   if (fsize == 0)
954     {
955       fclose (fstream);
956       LOG_ERR ("file \"%s\" is empty!", filename);
957       return FALSE;
958     }
959   if (fread (buffer, sizeof (char), fsize, fstream) != fsize)
960     {
961 #if defined(_WIN32_WCE)
962       LOG_ERR ("can't read \"%s\" file", pathname);
963 #else
964       LOG_ERR ("can't read \"%s\" file (%s)", pathname, strerror (errno));
965 #endif
966       fclose (fstream);
967       free_memory (pathname);
968       return FALSE;
969     }
970   fclose (fstream);
971   LOG_DBG ("\"%s\" file was loaded in memory", pathname);
972   free_memory (pathname);
973   return TRUE;
974 }
975 
976 
977 bool
file_write(const char * filename,const char * filedata,const size_t filesize)978 file_write (const char *filename, const char *filedata, const size_t filesize)
979 {
980   FILE *fstream;
981 
982   /* set umask so that files are group-writable */
983 #if !defined(_WIN32_WCE)
984 #ifdef WIN32
985   _umask (0002);
986 #else
987   umask (0002);
988 #endif
989 #endif
990 
991   fstream = fopen (filename, "wb");
992   if (fstream == NULL)
993     {
994 #if defined(_WIN32_WCE)
995       LOG_ERR ("fopen (%s) failed", filename);
996 #else
997       LOG_ERR ("fopen (%s) return: %s", filename, strerror (errno));
998 #endif
999       return FALSE;
1000     }
1001 
1002   if (fwrite (filedata, sizeof (char), filesize, fstream) != filesize)
1003     {
1004 #if defined(_WIN32_WCE)
1005       LOG_ERR ("fwrite (%s) failed", filename);
1006 #else
1007       LOG_ERR ("fwrite (%s) return: %s", filename, strerror (errno));
1008 #endif
1009       fclose (fstream);
1010       return FALSE;
1011     }
1012   if (fclose (fstream) != 0)
1013     {
1014 #if defined(_WIN32_WCE)
1015       LOG_ERR ("close (%s) failed", filename);
1016 #else
1017       LOG_ERR ("close (%s) return: %s", filename, strerror (errno));
1018 #endif
1019       return FALSE;
1020     }
1021   return TRUE;
1022 }
1023 
1024 /**
1025  * Initialize ticks counters
1026  */
1027 void
fps_init(void)1028 fps_init (void)
1029 {
1030 #ifdef POWERMANGA_SDL
1031   time_begin = SDL_GetTicks ();
1032   ticks_previous = SDL_GetTicks ();
1033 #else
1034   gettimeofday (&time_begin, NULL);
1035   gettimeofday (&ticks_previous, NULL);
1036 #endif
1037   loops_counter = 0;
1038 }
1039 
1040 /**
1041  * Draw informations on framerate and Linux system
1042  */
1043 void
fps_print(void)1044 fps_print (void)
1045 {
1046 #ifdef POWERMANGA_SDL
1047   double fps;
1048   unsigned long duration;
1049   Sint32 time_end;
1050   time_end = SDL_GetTicks ();
1051   duration = time_end - time_begin;
1052   fps = (1000.0 * loops_counter) / duration;
1053   LOG_INF ("number of loops: %i; running time: %li; frames per seconde: %g",
1054            loops_counter, duration, fps);
1055 #else
1056   struct utsname kernel;
1057   struct stat statmem;
1058   unsigned long duration;
1059   double fps;
1060   double mem;
1061   char os_name[32];
1062   char os_vers[32];
1063   char cpu[64];
1064   char freq[32];
1065   FILE *cpuinfo;
1066   char txt[256];
1067   static struct timeval time_end;
1068 
1069   /* total time of execution */
1070   gettimeofday (&time_end, NULL);
1071   duration =
1072     (time_end.tv_sec - time_begin.tv_sec) * 1000 + (time_end.tv_usec -
1073                                                     time_begin.tv_usec) /
1074     1000;
1075   fps = (1000.0 * loops_counter) / duration;
1076 
1077   /* Linux kernel version */
1078   if (uname (&kernel) < 0)
1079     {
1080       strcpy (os_name, "?");
1081       strcpy (os_vers, "");
1082     }
1083   else
1084     {
1085       strncpy (os_name, kernel.sysname, 32);
1086       strncpy (os_vers, kernel.release, 32);
1087     }
1088   /* CPU and physic memory */
1089   stat ("/proc/kcore", &statmem);
1090   mem = ((float) statmem.st_size) / 1024 / 1024;
1091   strcpy (cpu, "Unknown");
1092   strcpy (freq, "Unknown");
1093   cpuinfo = fopen ("/proc/cpuinfo", "r");
1094   if (cpuinfo != NULL)
1095     {
1096       while (fgets (txt, 255, cpuinfo))
1097         {
1098           if (!strncmp (txt, "model", 5))
1099             {
1100               int i = 0;
1101               while (txt[i] != ':')
1102                 i++;
1103               i += 2;
1104               for (int j = 0; j < 64;)
1105                 {
1106                   if (txt[i++] != '\n')
1107                     cpu[j++] = txt[i - 1];
1108                 }
1109             }
1110           if (!strncmp (txt, "cpu MHz", 7))
1111             {
1112               int i = 0;
1113               while (txt[i] != ':')
1114                 i++;
1115               i += 2;
1116               sprintf (freq, "%d", atoi (txt + i));
1117             }
1118         }
1119     }
1120   LOG_INF ("operating system : %s %s", os_name, os_vers);
1121   LOG_INF ("processor        : %s at %s Mhz with %.0f RAM", cpu, freq, mem);
1122   LOG_INF ("number of loops  : %i", loops_counter);
1123   LOG_INF ("running time     : %li", duration);
1124   LOG_INF ("frames per second: %g", fps);
1125 #endif
1126 }
1127 
1128 /**
1129  * Sleep for a time interval
1130  * @input delay
1131  * @return
1132  */
1133 Sint32
wait_next_frame(Sint32 delay,Sint32 max)1134 wait_next_frame (Sint32 delay, Sint32 max)
1135 {
1136 #ifdef POWERMANGA_SDL
1137   if (delay > max)
1138     {
1139       delay = max;
1140     }
1141   if (delay > 0)
1142     {
1143       SDL_Delay (delay);
1144     }
1145   return (delay > 0 ? delay : 0);
1146 #else
1147   struct timeval temps;
1148   if (delay > max)
1149     {
1150       delay = max;
1151     }
1152   if (delay > 0)
1153     {
1154       temps.tv_usec = delay % (unsigned long) 1000000;
1155       temps.tv_sec = delay / (unsigned long) 1000000;
1156       select (0, NULL, NULL, NULL, &temps);
1157     }
1158   return (delay > 0 ? delay : 0);
1159 #endif
1160 }
1161 
1162 #ifdef POWERMANGA_SDL
1163 /**
1164  * Calculate diffence between 2 times
1165  * @return difference
1166  */
1167 Sint32
get_time_difference()1168 get_time_difference ()
1169 {
1170   Sint32 diff;
1171   Uint32 current_ticks;
1172   current_ticks = SDL_GetTicks ();
1173   diff = current_ticks - ticks_previous;
1174   ticks_previous = current_ticks;
1175   return diff;
1176 }
1177 #else
1178 /**
1179  * Calculate diffence between 2 times
1180  * @return difference
1181  */
1182 Sint32
get_time_difference()1183 get_time_difference ()
1184 {
1185   struct timeval current_ticks;
1186   Sint32 diff;
1187   gettimeofday (&current_ticks, NULL);
1188   diff =
1189     (1000000 * (current_ticks.tv_sec - ticks_previous.tv_sec)) +
1190     (current_ticks.tv_usec - ticks_previous.tv_usec);
1191   ticks_previous = current_ticks;
1192   return diff;
1193 }
1194 #endif
1195 
1196 /**
1197  * Check if a value is null, signed or unsigned
1198  * @return 0 if value is null, -1 if signed, or 1 otherwise
1199  */
1200 Sint16
sign(float val)1201 sign (float val)
1202 {
1203   if (val == 0)
1204     {
1205       return 0;
1206     }
1207   if (val < 0)
1208     {
1209       return -1;
1210     }
1211   return 1;
1212 }
1213 
1214 /**
1215  * Calculate a shot angle from two points
1216  * @param pxs X coordinate of the source
1217  * @param pys Y coordinate of the source
1218  * @param pxd X coordinate of the destination
1219  * @param pyd Y coordinate of the destination
1220  * @return angle
1221  */
1222 float
calc_target_angle(Sint16 pxs,Sint16 pys,Sint16 pxd,Sint16 pyd)1223 calc_target_angle (Sint16 pxs, Sint16 pys, Sint16 pxd, Sint16 pyd)
1224 {
1225   double length, result, dx, dy, angle;
1226   /* calculate distance between source and destination */
1227   dx = pxd - pxs;
1228   dy = pyd - pys;
1229   result = (dx * dx) + (dy * dy);
1230   length = sqrt (result);
1231   if (length == 0)
1232     {
1233       /* avoid division by zero */
1234       return 0.0;
1235     }
1236   result = dx / length;
1237   angle = acos (result);
1238   result = dy / length;
1239   if (asin (result) < 0)
1240     {
1241       angle = -angle;
1242     }
1243   return (float) angle;
1244 }
1245 
1246 /**
1247  * Calculate a new angle from another angle and some deftness
1248  * @param old_angle
1249  * @param new_angle
1250  * @param deftness
1251  * @return New angle
1252  */
1253 float
get_new_angle(float old_angle,float new_angle,float deftness)1254 get_new_angle (float old_angle, float new_angle, float deftness)
1255 {
1256   float delta_angle;
1257   delta_angle = old_angle - new_angle;
1258   if (((delta_angle < 0) && (delta_angle > -3.14)) || (delta_angle > 3.14))
1259     {
1260       old_angle = old_angle + deftness;
1261       if (old_angle > 3.14)
1262         {
1263           old_angle = old_angle - 6.28f;
1264         }
1265     }
1266   if (((delta_angle > 0) && (delta_angle < 3.14)) || (delta_angle < -3.14))
1267     {
1268       old_angle = old_angle - deftness;
1269       if (old_angle < -3.14)
1270         {
1271           old_angle = old_angle + 6.28f;
1272         }
1273     }
1274   return old_angle;
1275 }
1276 
1277 /**
1278  * Allocates memory and coopies into it the string addressed
1279  * @param Null-terminated string to duplicate.
1280  * @return Pointer to a newly allocated copy of the string or NULL
1281  */
1282 char *
string_duplicate(register const char * str)1283 string_duplicate (register const char *str)
1284 {
1285   register char *new_str;
1286   register Uint32 size;
1287   size = strlen (str) + 1;
1288   new_str = memory_allocation (size);
1289   if (new_str == NULL)
1290     {
1291       LOG_ERR ("not enough memory to allocate %i bytes", size);
1292       return NULL;
1293     }
1294   memcpy (new_str, str, size);
1295   return new_str;
1296 }
1297 
1298 /**
1299  * Allocate and precalculate sinus and cosinus curves
1300  * @return TRUE if it completed successfully or FALSE otherwise
1301  */
1302 bool
alloc_precalulate_sinus(void)1303 alloc_precalulate_sinus (void)
1304 {
1305   Uint32 i;
1306   double a, step, pi;
1307 
1308   if (precalc_sin128 == NULL)
1309     {
1310       i = 128 * sizeof (float) * 2;
1311       precalc_sin128 = (float *) memory_allocation (i);
1312       if (precalc_sin128 == NULL)
1313         {
1314           LOG_ERR ("not enough memory to allocate %i bytes", i);
1315           return FALSE;
1316         }
1317       precalc_cos128 = precalc_sin128 + 128;
1318     }
1319   pi = 4 * atan (1.0);
1320   a = 0.0;
1321   step = (pi * 2) / 128;
1322   for (i = 0; i < 128; i++)
1323     {
1324       precalc_sin128[i] = (float) sin (a);
1325       precalc_cos128[i] = (float) cos (a);
1326       a += step;
1327     }
1328   if (precalc_sin == NULL)
1329     {
1330       i = 32 * sizeof (float) * 2;
1331       precalc_sin = (float *) memory_allocation (i);
1332       if (precalc_sin == NULL)
1333         {
1334           LOG_ERR ("not enough memory to allocate %i bytes", i);
1335           return FALSE;
1336         }
1337       precalc_cos = precalc_sin + 32;
1338     }
1339 
1340   step = (pi * 2) / 32;
1341   a = 0.0;
1342   for (i = 0; i < 32; i++)
1343     {
1344       precalc_sin[i] = (float) sin (a);
1345       precalc_cos[i] = (float) cos (a);
1346       a += step;
1347     }
1348   /* table user for guided missile */
1349   for (i = 0; i < 32; i++)
1350     {
1351       depix[0][i] = precalc_cos[i] * 0.5f;
1352       depix[1][i] = precalc_cos[i] * 1.0f;
1353       depix[2][i] = precalc_cos[i] * 1.5f;
1354       depix[3][i] = precalc_cos[i] * 2.0f;
1355       depix[4][i] = precalc_cos[i] * 2.5f;
1356       depix[5][i] = precalc_cos[i] * 3.0f;
1357       depix[6][i] = precalc_cos[i] * 3.5f;
1358       depix[7][i] = precalc_cos[i] * 4.0f;
1359       depix[8][i] = precalc_cos[i] * 4.5f;
1360       depix[9][i] = precalc_cos[i] * 5.0f;
1361       depix[10][i] = precalc_cos[i] * 5.5f;
1362       depix[11][i] = precalc_cos[i] * 6.0f;
1363       depix[12][i] = precalc_cos[i] * 6.5f;
1364       depiy[0][i] = precalc_sin[i] * 0.5f;
1365       depiy[1][i] = precalc_sin[i] * 1.0f;
1366       depiy[2][i] = precalc_sin[i] * 1.5f;
1367       depiy[3][i] = precalc_sin[i] * 2.0f;
1368       depiy[4][i] = precalc_sin[i] * 2.5f;
1369       depiy[5][i] = precalc_sin[i] * 3.0f;
1370       depiy[6][i] = precalc_sin[i] * 3.5f;
1371       depiy[7][i] = precalc_sin[i] * 4.0f;
1372       depiy[8][i] = precalc_sin[i] * 4.5f;
1373       depiy[9][i] = precalc_sin[i] * 5.0f;
1374       depiy[10][i] = precalc_sin[i] * 5.5f;
1375       depiy[11][i] = precalc_sin[i] * 6.0f;
1376       depiy[12][i] = precalc_sin[i] * 6.5f;
1377     }
1378   return TRUE;
1379 }
1380 
1381 /**
1382  * Release precalculded sinus and cosinus curves
1383  */
1384 void
free_precalulate_sinus(void)1385 free_precalulate_sinus (void)
1386 {
1387   if (precalc_sin != NULL)
1388     {
1389       free_memory ((char *) precalc_sin);
1390       precalc_sin = NULL;
1391       precalc_cos = NULL;
1392     }
1393   if (precalc_sin128 != NULL)
1394     {
1395       free_memory ((char *) precalc_sin128);
1396       precalc_sin128 = NULL;
1397       precalc_cos128 = NULL;
1398     }
1399 }
1400 
1401 /**
1402  * Open a file and return an I/O stream
1403  * @param fname fname The filename specified by path
1404  * @param fmode Mode parameter
1405  * @return A pointer to a FILE structure
1406  */
1407 FILE *
fopen_data(const char * fname,const char * fmode)1408 fopen_data (const char *fname, const char *fmode)
1409 {
1410   FILE *fi;
1411   fi = fopen (fname, fmode);
1412   if (fi == NULL)
1413     {
1414 #if defined(_WIN32_WCE)
1415       LOG_ERR ("fopen (%s, %s) failed!", fname, fmode);
1416 #else
1417       LOG_ERR ("fopen (%s, %s) return: %s", fname, fmode, strerror (errno));
1418 #endif
1419       return NULL;
1420     }
1421   return fi;
1422 }
1423 
1424 /**
1425  * create a new directory
1426  * @param dirname A direcotry name
1427  * @return Boolean value on success or failure
1428  */
1429 bool
create_dir(const char * dirname)1430 create_dir (const char *dirname)
1431 {
1432 #if defined(_WIN32_WCE)
1433   LOG_DBG ("create_dir(%s) not implemented!", dirname);
1434   return FALSE;
1435 
1436   /* FIXME convert char* ti wchar_t* */
1437 /*
1438   bool result = TRUE;
1439   if (CreateDirectory (config_dir, NULL) == FALSE)
1440     {
1441       if (GetLastError () != ERROR_ALREADY_EXISTS)
1442         {
1443           LOG_ERR ("CreateDirectory(%s) failed!", config_dir);
1444           result = FALSE;
1445         }
1446     }
1447   return result;
1448 */
1449 #else
1450 #if defined(_WIN32)
1451   Sint32 result;
1452   result = _mkdir (dirname);
1453   if (result == 0 || result == EEXIST)
1454     {
1455       return TRUE;
1456     }
1457   else
1458     {
1459       return FALSE;
1460     }
1461 #else
1462   Sint32 result;
1463   result = mkdir (dirname, S_IRWXU);
1464   if (result == 0 || result == EEXIST)
1465     {
1466       return TRUE;
1467     }
1468   else if (errno == EEXIST || errno == EISDIR)
1469     {
1470       return TRUE;
1471     }
1472   else
1473     {
1474       LOG_ERR ("mkdir(%s): %s", dirname, strerror (errno));
1475       return FALSE;
1476     }
1477 #endif
1478 #endif
1479 }
1480 
1481 #if defined(_WIN32_WCE)
1482 #define PARAMAX_LEN 256
1483 #ifndef SPI_GETPLATFORMMANUFACTURER
1484 #define SPI_GETPLATFORMMANUFACTURER 262
1485 #endif
1486 #ifndef SPI_GETPLATFORMNAME
1487 #define SPI_GETPLATFORMNAME 260
1488 #endif
1489 void
display_windows_ce_infos(void)1490 display_windows_ce_infos (void)
1491 {
1492   Uint32 i;
1493   char *param;
1494   WCHAR wparam[PARAMAX_LEN + 1];
1495   OSVERSIONINFO vinfo;
1496   static const char *action_names[] = {
1497     "SPI_GETPLATFORMMANUFACTURER",
1498     "SPI_GETPLATFORMNAME",
1499     "SPI_GETPLATFORMTYPE"
1500   };
1501   static const Uint32 actions[] = {
1502     SPI_GETPLATFORMMANUFACTURER,
1503     SPI_GETPLATFORMNAME,
1504     SPI_GETPLATFORMTYPE
1505   };
1506   for (i = 0; i < sizeof (actions) / sizeof (Uint32); i++)
1507     {
1508       if (SystemParametersInfo (actions[i], PARAMAX_LEN, wparam, 0) == FALSE)
1509         {
1510           LOG_ERR ("SystemParametersInfo(%s) "
1511                    "failed (error %i)", action_names[i], GetLastError ());
1512           continue;
1513         }
1514       param = wide_char_to_bytes (wparam, 0, CP_ACP);
1515       if (param == NULL)
1516         {
1517           continue;
1518         }
1519       LOG_INF ("%s %s", action_names[i], param);
1520       free_memory (param);
1521     }
1522 
1523   if (GetVersionEx (&vinfo) == FALSE)
1524     {
1525       LOG_ERR ("GetVersionEx() " "failed (error %i)", GetLastError ());
1526     }
1527   else
1528     {
1529       if (vinfo.dwPlatformId != VER_PLATFORM_WIN32_CE)
1530         {
1531           LOG_ERR ("this system is not a Windows Embedded CE OS");
1532         }
1533       else
1534         {
1535           LOG_INF ("Windows Mobile %i.%i", vinfo.dwMajorVersion,
1536                    vinfo.dwMinorVersion);
1537         }
1538     }
1539 
1540   LOG_INF ("SM_CXSCREEN: %i; SM_CYSCREEN: %i",
1541            GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN));
1542 }
1543 #endif
1544