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 (¤t_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