Crossfire Server, Branches 1.12  R18729
image.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_image_c =
3  * "$Id: image.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The maintainer of this code can be reached at crossfire-devel@real-time.com
27 */
28 
34 #include <global.h>
35 #include <stdio.h>
36 #include "image.h"
37 
39 
52 struct bmappair {
53  char *name;
54  unsigned int number;
55 };
60 static struct bmappair *xbm = NULL;
61 
67 
68 
70 static int nroffiles = 0;
71 
76 int nrofpixmaps = 0;
77 
87 static const char *const colorname[] = {
88  "black", /* 0 */
89  "white", /* 1 */
90  "blue", /* 2 */
91  "red", /* 3 */
92  "orange", /* 4 */
93  "light_blue", /* 5 */
94  "dark_orange", /* 6 */
95  "green", /* 7 */
96  "light_green", /* 8 */
97  "grey", /* 9 */
98  "brown", /* 10 */
99  "yellow", /* 11 */
100  "khaki" /* 12 */
101 };
102 
106 static int compar(const struct bmappair *a, const struct bmappair *b) {
107  return strcmp(a->name, b->name);
108 }
109 
123 static uint8 find_color(const char *name) {
124  uint8 i;
125 
126  for (i = 0; i < sizeof(colorname)/sizeof(*colorname); i++)
127  if (!strcmp(name, colorname[i]))
128  return i;
129 
130  LOG(llevError, "Unknown color: %s\n", name);
131  return 0;
132 }
133 
141 static void read_face_data(void) {
142  char buf[MAX_BUF], *cp;
143  New_Face *on_face = NULL;
144  FILE *fp;
145 
146  snprintf(buf, sizeof(buf), "%s/faces", settings.datadir);
147  LOG(llevDebug, "Reading faces from %s...\n", buf);
148  if ((fp = fopen(buf, "r")) == NULL) {
149  LOG(llevError, "Cannot open faces file: %s\n", strerror_local(errno, buf, sizeof(buf)));
150  exit(-1);
151  }
152 
153  while (fgets(buf, MAX_BUF, fp) != NULL) {
154  if (*buf == '#')
155  continue;
156  if (!strncmp(buf, "end", 3)) {
157  on_face = NULL;
158  } else if (!strncmp(buf, "face", 4)) {
159  unsigned tmp;
160 
161  cp = buf+5;
162  cp[strlen(cp)-1] = '\0'; /* remove newline */
163 
164  if ((tmp = find_face(cp, (unsigned)-1)) == (unsigned)-1) {
165  LOG(llevError, "Could not find face %s\n", cp);
166  continue;
167  }
168  on_face = &new_faces[tmp];
169  on_face->visibility = 0;
170  } else if (on_face == NULL) {
171  LOG(llevError, "Got line with no face set: %s\n", buf);
172  } else if (!strncmp(buf, "visibility", 10)) {
173  on_face->visibility = atoi(buf+11);
174  } else if (!strncmp(buf, "magicmap", 8)) {
175  cp = buf+9;
176  cp[strlen(cp)-1] = '\0';
177  on_face->magicmap = find_color(cp);
178  } else if (!strncmp(buf, "is_floor", 8)) {
179  int value = atoi(buf+9);
180  if (value)
181  on_face->magicmap |= FACE_FLOOR;
182  } else
183  LOG(llevDebug, "Got unknown line in faces file: %s\n", buf);
184  }
185  LOG(llevDebug, "done\n");
186  fclose(fp);
187 }
188 
198 void read_bmap_names(void) {
199  char buf[MAX_BUF], *p, *q;
200  FILE *fp;
201  int value, nrofbmaps = 0, i;
202  size_t l;
203 
204  bmaps_checksum = 0;
205  snprintf(buf, sizeof(buf), "%s/bmaps", settings.datadir);
206  LOG(llevDebug, "Reading bmaps from %s...\n", buf);
207  if ((fp = fopen(buf, "r")) == NULL) {
208  LOG(llevError, "Cannot open bmaps file: %s\n", strerror_local(errno, buf, sizeof(buf)));
209  exit(-1);
210  }
211 
212  /* First count how many bitmaps we have, so we can allocate correctly */
213  while (fgets(buf, MAX_BUF, fp) != NULL)
214  if (buf[0] != '#' && buf[0] != '\n')
215  nrofbmaps++;
216  rewind(fp);
217 
218  xbm = (struct bmappair *)malloc(sizeof(struct bmappair)*nrofbmaps);
219  if (xbm == NULL) {
220  LOG(llevError, "read_bmap_names: xbm memory allocation failure.\n");
221  abort();
222  }
223  memset(xbm, 0, sizeof(struct bmappair)*nrofbmaps);
224 
225  nroffiles = 0;
226  while (nroffiles < nrofbmaps && fgets(buf, MAX_BUF, fp) != NULL) {
227  if (*buf == '#')
228  continue;
229 
230  p = (*buf == '\\') ? (buf+1) : buf;
231  if (!(p = strtok(p, " \t")) || !(q = strtok(NULL, " \t\n"))) {
232  LOG(llevDebug, "Warning, syntax error: %s\n", buf);
233  continue;
234  }
235  value = atoi(p);
236  xbm[nroffiles].name = strdup_local(q);
237 
238  /* We need to calculate the checksum of the bmaps file
239  * name->number mapping to send to the client. This does not
240  * need to match what sum or other utility may come up with -
241  * as long as we get the same results on the same real file
242  * data, it does the job as it lets the client know if
243  * the file has the same data or not.
244  */
246  bmaps_checksum += value&0xff;
247  bmaps_checksum &= 0xffffffff;
248 
250  bmaps_checksum += (value>>8)&0xff;
251  bmaps_checksum &= 0xffffffff;
252  for (l = 0; l < strlen(q); l++) {
254  bmaps_checksum += q[l];
255  bmaps_checksum &= 0xffffffff;
256  }
257 
258  xbm[nroffiles].number = value;
259  nroffiles++;
260  if (value >= nrofpixmaps)
261  nrofpixmaps = value+1;
262  }
263  fclose(fp);
264 
265  LOG(llevDebug, "done (got %d/%d/%d)\n", nrofpixmaps, nrofbmaps, nroffiles);
266 
267  new_faces = (New_Face *)malloc(sizeof(New_Face)*nrofpixmaps);
268  if (new_faces == NULL) {
269  LOG(llevError, "read_bmap_names: new_faces memory allocation failure.\n");
270  abort();
271  }
272 
273  for (i = 0; i < nrofpixmaps; i++) {
274  new_faces[i].name = "";
275  new_faces[i].number = i;
276  new_faces[i].visibility = 0;
277  new_faces[i].magicmap = 255;
278  new_faces[i].smoothface = (uint16)-1;
279  }
280 
281  for (i = 0; i < nroffiles; i++) {
282  new_faces[xbm[i].number].name = xbm[i].name;
283  }
284 
285  qsort(xbm, nroffiles, sizeof(struct bmappair), (int (*)(const void *, const void *))compar);
286 
287  read_face_data();
288 
289  for (i = 0; i < nrofpixmaps; i++) {
290  if (new_faces[i].magicmap == 255) {
291  new_faces[i].magicmap = 0;
292  }
293  }
294  /* Actually forcefully setting the colors here probably should not
295  * be done - it could easily create confusion.
296  */
297  blank_face = &new_faces[find_face(BLANK_FACE_NAME, 0)];
298  blank_face->magicmap = find_color("khaki")|FACE_FLOOR;
299 
300  empty_face = &new_faces[find_face(EMPTY_FACE_NAME, 0)];
301 
302  smooth_face = &new_faces[find_face(SMOOTH_FACE_NAME, 0)];
303 }
304 
324 unsigned find_face(const char *name, unsigned error) {
325  struct bmappair *bp, tmp;
326  char *p;
327 
328  if ((p = strchr(name, '\n')))
329  *p = '\0';
330 
331  tmp.name = (char *)name;
332  bp = (struct bmappair *)bsearch(&tmp, xbm, nroffiles, sizeof(struct bmappair), (int (*)(const void *, const void *))compar);
333 
334  return bp ? bp->number : error;
335 }
336 
348 int read_smooth(void) {
349  char buf[MAX_BUF], *p, *q;
350  FILE *fp;
351  int regular, smoothed, nrofsmooth = 0;
352 
353  snprintf(buf, sizeof(buf), "%s/smooth", settings.datadir);
354  LOG(llevDebug, "Reading smooth from %s...\n", buf);
355  if ((fp = fopen(buf, "r")) == NULL) {
356  LOG(llevError, "Cannot open smooth file %s: %s\n", strerror_local(errno, buf, sizeof(buf)));
357  exit(-1);
358  }
359 
360  while (fgets(buf, MAX_BUF, fp) != NULL) {
361  if (*buf == '#')
362  continue;
363 
364  p = strchr(buf, ' ');
365  if (!p)
366  continue;
367 
368  *p = '\0';
369  q = buf;
370  regular = find_face(q, (unsigned)-1);
371  if (regular == (unsigned)-1) {
372  LOG(llevError, "invalid regular face: %s\n", q);
373  continue;
374  }
375  q = p+1;
376  smoothed = find_face(q, (unsigned)-1);
377  if (smoothed == (unsigned)-1) {
378  LOG(llevError, "invalid smoothed face: %s\n", q);
379  continue;
380  }
381 
382  new_faces[regular].smoothface = smoothed;
383 
384  nrofsmooth++;
385  }
386  fclose(fp);
387 
388  LOG(llevDebug, "done (got %d smooth entries)\n", nrofsmooth);
389  return nrofsmooth;
390 }
391 
401 int find_smooth(uint16 face, uint16 *smoothed) {
402  (*smoothed) = 0;
403 
404  if (face < nrofpixmaps) {
405  if (new_faces[face].smoothface == ((uint16)-1))
406  return 0;
407 
408  (*smoothed) = new_faces[face].smoothface;
409  return 1;
410  }
411 
412  return 0;
413 }
414 
418 void free_all_images(void) {
419  int i;
420 
421  for (i = 0; i < nroffiles; i++)
422  free(xbm[i].name);
423  free(xbm);
424  free(new_faces);
425 }
426 
435 static void check_faceset_fallback(int faceset, int togo) {
436  int fallback = facesets[faceset].fallback;
437 
438  /* proper case - falls back to base set */
439  if (fallback == 0)
440  return;
441 
442  if (!facesets[fallback].prefix) {
443  LOG(llevError, "Face set %d falls to non set faceset %d\n", faceset, fallback);
444  abort();
445  }
446  togo--;
447  if (togo == 0) {
448  LOG(llevError, "Infinite loop found in facesets. aborting.\n");
449  abort();
450  }
451  check_faceset_fallback(fallback, togo);
452 }
453 
471 void read_client_images(void) {
472  char filename[400];
473  char buf[HUGE_BUF];
474  char *cp, *cps[7];
475  FILE *infile;
476  int num, len, compressed, fileno, i, badline;
477 
478  memset(facesets, 0, sizeof(facesets));
479  snprintf(filename, sizeof(filename), "%s/image_info", settings.datadir);
480  if ((infile = open_and_uncompress(filename, 0, &compressed)) == NULL) {
481  LOG(llevError, "Unable to open %s\n", filename);
482  abort();
483  }
484  while (fgets(buf, HUGE_BUF-1, infile) != NULL) {
485  badline = 0;
486 
487  if (buf[0] == '#')
488  continue;
489  if (!(cps[0] = strtok(buf, ":")))
490  badline = 1;
491  for (i = 1; i < 7; i++) {
492  if (!(cps[i] = strtok(NULL, ":")))
493  badline = 1;
494  }
495  if (badline) {
496  LOG(llevError, "Bad line in image_info file, ignoring line:\n %s", buf);
497  } else {
498  len = atoi(cps[0]);
499  if (len >= MAX_FACE_SETS) {
500  LOG(llevError, "To high a setnum in image_info file: %d > %d\n", len, MAX_FACE_SETS);
501  abort();
502  }
503  facesets[len].prefix = strdup_local(cps[1]);
504  facesets[len].fullname = strdup_local(cps[2]);
505  facesets[len].fallback = atoi(cps[3]);
506  facesets[len].size = strdup_local(cps[4]);
507  facesets[len].extension = strdup_local(cps[5]);
508  facesets[len].comment = strdup_local(cps[6]);
509  }
510  }
511  close_and_delete(infile, compressed);
512  for (i = 0; i < MAX_FACE_SETS; i++) {
513  if (facesets[i].prefix)
514  check_faceset_fallback(i, MAX_FACE_SETS);
515  }
516  /* Loaded the faceset information - now need to load up the
517  * actual faces.
518  */
519 
520  for (fileno = 0; fileno < MAX_FACE_SETS; fileno++) {
521  /* if prefix is not set, this is not used */
522  if (!facesets[fileno].prefix)
523  continue;
524  facesets[fileno].faces = calloc(nrofpixmaps, sizeof(face_info));
525 
526  snprintf(filename, sizeof(filename), "%s/crossfire.%d", settings.datadir, fileno);
527  LOG(llevDebug, "Loading image file %s\n", filename);
528 
529  if ((infile = open_and_uncompress(filename, 0, &compressed)) == NULL) {
530  LOG(llevError, "Unable to open %s\n", filename);
531  abort();
532  }
533  while (fgets(buf, HUGE_BUF-1, infile) != NULL) {
534  if (strncmp(buf, "IMAGE ", 6) != 0) {
535  LOG(llevError, "read_client_images:Bad image line - not IMAGE, instead\n%s", buf);
536  abort();
537  }
538  num = atoi(buf+6);
539  if (num < 0 || num >= nrofpixmaps) {
540  LOG(llevError, "read_client_images: Image num %d not in 0..%d\n%s", num, nrofpixmaps, buf);
541  abort();
542  }
543  /* Skip accross the number data */
544  for (cp = buf+6; *cp != ' '; cp++)
545  ;
546  len = atoi(cp);
547  if (len == 0 || len > MAX_IMAGE_SIZE) {
548  LOG(llevError, "read_client_images: length not valid: %d > %d \n%s", len, MAX_IMAGE_SIZE, buf);
549  abort();
550  }
551  /* We don't actualy care about the name if the image that
552  * is embedded in the image file, so just ignore it.
553  */
554  facesets[fileno].faces[num].datalen = len;
555  facesets[fileno].faces[num].data = malloc(len);
556  if ((i = fread(facesets[fileno].faces[num].data, len, 1, infile)) != 1) {
557  LOG(llevError, "read_client_images: Did not read desired amount of data, wanted %d, got %d\n%s", len, i, buf);
558  abort();
559  }
560  facesets[fileno].faces[num].checksum = 0;
561  for (i = 0; i < len; i++) {
562  ROTATE_RIGHT(facesets[fileno].faces[num].checksum);
563  facesets[fileno].faces[num].checksum += facesets[fileno].faces[num].data[i];
564  facesets[fileno].faces[num].checksum &= 0xffffffff;
565  }
566  }
567  close_and_delete(infile, compressed);
568  } /* For fileno < MAX_FACE_SETS */
569 }
570 
575 int is_valid_faceset(int fsn) {
576  if (fsn >= 0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix)
577  return TRUE;
578  return FALSE;
579 }
580 
584 void free_socket_images(void) {
585  int num, q;
586 
587  for (num = 0; num < MAX_FACE_SETS; num++) {
588  if (facesets[num].prefix) {
589  for (q = 0; q < nrofpixmaps; q++)
590  if (facesets[num].faces[q].data)
591  free(facesets[num].faces[q].data);
592  free(facesets[num].prefix);
593  free(facesets[num].fullname);
594  free(facesets[num].size);
595  free(facesets[num].extension);
596  free(facesets[num].comment);
597  free(facesets[num].faces);
598  }
599  }
600 }
601 
614 int get_face_fallback(int faceset, int imageno) {
615  /* faceset 0 is supposed to have every image, so just return. Doing
616  * so also prevents infinite loops in the case if it not having
617  * the face, but in that case, we are likely to crash when we try
618  * to access the data, but that is probably preferable to an infinite
619  * loop.
620  */
621  if (faceset == 0)
622  return 0;
623 
624  if (!facesets[faceset].prefix) {
625  LOG(llevError, "get_face_fallback called with unused set (%d)?\n", faceset);
626  return 0; /* use default set */
627  }
628  if (facesets[faceset].faces[imageno].data)
629  return faceset;
630  return get_face_fallback(facesets[faceset].fallback, imageno);
631 }
static int compar(const struct bmappair *a, const struct bmappair *b)
Definition: image.c:106
#define FALSE
Definition: exp.c:42
int nrofpixmaps
Definition: image.c:76
int find_smooth(uint16 face, uint16 *smoothed)
Definition: image.c:401
face_info * faces
Definition: image.h:47
#define ROTATE_RIGHT(c)
Definition: global.h:245
New_Face * new_faces
Definition: image.c:38
char * name
Definition: image.c:53
uint8 fallback
Definition: image.h:43
#define HUGE_BUF
Definition: define.h:83
int is_valid_faceset(int fsn)
Definition: image.c:575
void close_and_delete(FILE *fp, int compressed)
Definition: porting.c:748
uint16 datalen
Definition: image.h:35
unsigned int number
Definition: image.c:54
uint16 number
Definition: face.h:43
static void read_face_data(void)
Definition: image.c:141
const char * name
Definition: face.h:48
int read_smooth(void)
Definition: image.c:348
static struct bmappair * xbm
Definition: image.c:60
char * prefix
Definition: image.h:41
#define BLANK_FACE_NAME
Definition: define.h:900
char * extension
Definition: image.h:45
uint8 * data
Definition: image.h:34
#define TRUE
Definition: exp.c:41
unsigned char uint8
Definition: global.h:75
New_Face * smooth_face
Definition: image.c:66
char * size
Definition: image.h:44
void free_socket_images(void)
Definition: image.c:584
static uint8 find_color(const char *name)
Definition: image.c:123
void read_client_images(void)
Definition: image.c:471
char * strdup_local(const char *str)
Definition: porting.c:310
char * comment
Definition: image.h:46
New_Face * empty_face
Definition: image.c:66
#define MAX_BUF
Definition: define.h:81
void free_all_images(void)
Definition: image.c:418
unsigned short uint16
Definition: global.h:67
void read_bmap_names(void)
Definition: image.c:198
#define MAX_IMAGE_SIZE
Definition: image.h:53
uint8 visibility
Definition: face.h:45
const char * datadir
Definition: global.h:334
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
#define MAX_FACE_SETS
Definition: image.h:49
face_sets facesets[MAX_FACE_SETS]
Definition: image.c:78
New_Face * blank_face
Definition: image.c:66
static const char *const colorname[]
Definition: image.c:87
uint16 smoothface
Definition: face.h:47
EXTERN int bmaps_checksum
Definition: global.h:242
struct Settings settings
Definition: init.c:48
#define FACE_FLOOR
Definition: newclient.h:248
Definition: image.c:52
#define SMOOTH_FACE_NAME
Definition: define.h:902
char * fullname
Definition: image.h:42
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
int get_face_fallback(int faceset, int imageno)
Definition: image.c:614
#define EMPTY_FACE_NAME
Definition: define.h:901
char * strerror_local(int errnum, char *buf, size_t size)
Definition: porting.c:525
uint32 checksum
Definition: image.h:36
uint8 magicmap
Definition: face.h:46
unsigned find_face(const char *name, unsigned error)
Definition: image.c:324
FILE * open_and_uncompress(const char *name, int flag, int *compressed)
Definition: porting.c:724
static int nroffiles
Definition: image.c:70
static void check_faceset_fallback(int faceset, int togo)
Definition: image.c:435