Crossfire Server, Trunk  R21670
image.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #include "global.h"
20 
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "image.h"
28 
34 
40 
41 
45 static unsigned int nrofpixmaps = 0;
46 
56 static const char *const colorname[] = {
57  "black", /* 0 */
58  "white", /* 1 */
59  "blue", /* 2 */
60  "red", /* 3 */
61  "orange", /* 4 */
62  "light_blue", /* 5 */
63  "dark_orange", /* 6 */
64  "green", /* 7 */
65  "light_green", /* 8 */
66  "grey", /* 9 */
67  "brown", /* 10 */
68  "yellow", /* 11 */
69  "khaki" /* 12 */
70 };
71 
83 static int compare_face(const Face *a, const Face *b) {
84  if (strcmp(a->name, "bug.111") == 0) {
85  if (strcmp(b->name, "bug.111") == 0)
86  return 0;
87  return -1;
88  } else if (strcmp(b->name, "bug.111") == 0)
89  return 1;
90  return strcmp(a->name, b->name);
91 }
92 
100 static Face *internal_find_face(const char *name) {
101  Face *bp, tmp;
102 
103  tmp.name = name;
104  bp = (Face *)bsearch(&tmp, new_faces, nrofpixmaps, sizeof(Face), (int (*)(const void *, const void *))compare_face);
105 
106  return bp;
107 }
108 
122 static uint8_t find_color(const char *name) {
123  uint8_t i;
124 
125  for (i = 0; i < sizeof(colorname)/sizeof(*colorname); i++)
126  if (!strcmp(name, colorname[i]))
127  return i;
128 
129  LOG(llevError, "Unknown color: %s\n", name);
130  return 0;
131 }
132 
140 static void read_face_data(void) {
141  char buf[MAX_BUF], *cp;
142  Face *on_face = NULL;
143  FILE *fp;
144 
145  snprintf(buf, sizeof(buf), "%s/faces", settings.datadir);
146  if ((fp = fopen(buf, "r")) == NULL) {
147  LOG(llevError, "faces: couldn't open file: %s\n", strerror(errno));
148  exit(-1);
149  }
150 
151  while (fgets(buf, MAX_BUF, fp) != NULL) {
152  if (*buf == '#')
153  continue;
154  if (!strncmp(buf, "end", 3)) {
155  on_face = NULL;
156  } else if (!strncmp(buf, "face", 4)) {
157  Face *tmp;
158 
159  cp = buf+5;
160  cp[strlen(cp)-1] = '\0'; /* remove newline */
161 
162  if ((tmp = internal_find_face(cp)) == NULL) {
163  LOG(llevError, "faces: couldn't find '%s'\n", cp);
164  on_face = NULL;
165  continue;
166  }
167  on_face = tmp;
168  on_face->visibility = 0;
169  } else if (on_face == NULL) {
170  LOG(llevError, "faces: got line with no face set: %s\n", buf);
171  } else if (!strncmp(buf, "visibility", 10)) {
172  on_face->visibility = atoi(buf+11);
173  } else if (!strncmp(buf, "magicmap", 8)) {
174  cp = buf+9;
175  cp[strlen(cp)-1] = '\0';
176  on_face->magicmap = find_color(cp);
177  } else if (!strncmp(buf, "is_floor", 8)) {
178  int value = atoi(buf+9);
179  if (value)
180  on_face->magicmap |= FACE_FLOOR;
181  } else
182  LOG(llevDebug, "faces: unknown line in %s\n", buf);
183  }
184  fclose(fp);
185 }
186 
196 void read_bmap_names(void) {
197  char buf[MAX_BUF], *p;
198  FILE *fp;
199  unsigned int i;
200  size_t l;
201 
202  bmaps_checksum = 0;
203  snprintf(buf, sizeof(buf), "%s/bmaps.paths", settings.datadir);
204  if ((fp = fopen(buf, "r")) == NULL) {
205  LOG(llevError, "bmaps: couldn't open: %s\n", strerror(errno));
206  exit(-1);
207  }
208 
209  nrofpixmaps = 0;
210 
211  /* First count how many bitmaps we have, so we can allocate correctly */
212  while (fgets(buf, MAX_BUF, fp) != NULL) {
213  if (buf[0] != '#' && buf[0] != '\n') {
214  nrofpixmaps++;
215  }
216  }
217 
218  rewind(fp);
219  assert(nrofpixmaps > 0);
220  new_faces = (Face *)malloc(sizeof(Face)*nrofpixmaps);
221  if (new_faces == NULL) {
223  }
224 
225  for (i = 0; i < nrofpixmaps; i++) {
226  new_faces[i].name = NULL;
227  new_faces[i].visibility = 0;
228  new_faces[i].magicmap = 255;
229  new_faces[i].smoothface = NULL;
230  }
231 
232  i = 0;
233  while (i < nrofpixmaps && fgets(buf, MAX_BUF, fp) != NULL) {
234  if (*buf == '#')
235  continue;
236 
237  p = strrchr(buf, '/');
238  if ((p == NULL) || (strtok(p, " \t\n") == NULL)) {
239  LOG(llevError, "bmaps: syntax error in %s\n", buf);
241  }
242  /* strtok converted the final newline or tab to NULL so all is ok */
243  new_faces[i].name = strdup_local(p + 1);
244 
245  /* We need to calculate the checksum of the bmaps file
246  * name->number mapping to send to the client. This does not
247  * need to match what sum or other utility may come up with -
248  * as long as we get the same results on the same real file
249  * data, it does the job as it lets the client know if
250  * the file has the same data or not.
251  */
253  bmaps_checksum += i&0xff;
254  bmaps_checksum &= 0xffffffff;
255 
257  bmaps_checksum += (i>>8)&0xff;
258  bmaps_checksum &= 0xffffffff;
259  for (l = 0; l < strlen(p); l++) {
261  bmaps_checksum += p[l];
262  bmaps_checksum &= 0xffffffff;
263  }
264 
265  i++;
266  }
267  fclose(fp);
268 
269  if (i != nrofpixmaps) {
270  LOG(llevError, "read_bmap_names: first read gave %d faces but only loaded %d??\n", nrofpixmaps, i);
272  }
273 
274  LOG(llevDebug, "bmaps: loaded %d faces\n", nrofpixmaps);
275 
276  qsort(new_faces, nrofpixmaps, sizeof(Face), (int (*)(const void *, const void *))compare_face);
277 
278  for (i = 0; i < nrofpixmaps; i++) {
279  new_faces[i].number = i;
280  }
281 
282  read_face_data();
283 
284  for (i = 0; i < nrofpixmaps; i++) {
285  if (new_faces[i].magicmap == 255) {
286  new_faces[i].magicmap = 0;
287  }
288  }
289  /* Actually forcefully setting the colors here probably should not
290  * be done - it could easily create confusion.
291  */
292  blank_face = internal_find_face(BLANK_FACE_NAME);
293  ((Face*)blank_face)->magicmap = find_color("khaki")|FACE_FLOOR; // TODO: doh :(
294 
295  empty_face = internal_find_face(EMPTY_FACE_NAME);
296 
297  smooth_face = internal_find_face(SMOOTH_FACE_NAME);
298 }
299 
316 const Face *find_face(const char *name, const Face *error) {
317  const Face *bp = internal_find_face(name);
318  return bp ? bp : error;
319 }
320 
332 int read_smooth(void) {
333  char buf[MAX_BUF], *p, *q;
334  FILE *fp;
335  Face *regular, *smoothed;
336  int nrofsmooth = 0;
337 
338  snprintf(buf, sizeof(buf), "%s/smooth", settings.datadir);
339  if ((fp = fopen(buf, "r")) == NULL) {
340  LOG(llevError, "Cannot open smooth file: %s\n", strerror(errno));
341  exit(-1);
342  }
343 
344  while (fgets(buf, MAX_BUF, fp) != NULL) {
345  if (*buf == '#')
346  continue;
347 
348  if ((p = strchr(buf, '\n')))
349  *p = '\0';
350 
351  p = strchr(buf, ' ');
352  if (!p)
353  continue;
354 
355  *p = '\0';
356  q = buf;
357  regular = internal_find_face(q);
358  if (regular == NULL) {
359  LOG(llevError, "invalid regular face: %s\n", q);
360  continue;
361  }
362  q = p+1;
363  smoothed = internal_find_face(q);
364  if (smoothed == NULL) {
365  LOG(llevError, "invalid smoothed face: %s\n", q);
366  continue;
367  }
368 
369  regular->smoothface = smoothed;
370 
371  nrofsmooth++;
372  }
373  fclose(fp);
374 
375  LOG(llevDebug, "smooth: loaded %d entries\n", nrofsmooth);
376  return nrofsmooth;
377 }
378 
388 int find_smooth(const Face *face, const Face **smoothed) {
389  (*smoothed) = NULL;
390 
391  if (face && face->smoothface) {
392  (*smoothed) = face->smoothface;
393  return 1;
394  }
395 
396  return 0;
397 }
398 
402 void free_all_images(void) {
403  unsigned int i;
404 
405  for (i = 0; i < nrofpixmaps; i++)
406  free((char*)(new_faces[i].name));
407  free(new_faces);
408 }
409 
418 static void check_faceset_fallback(int faceset, int togo) {
419  int fallback = facesets[faceset].fallback;
420 
421  /* proper case - falls back to base set */
422  if (fallback == 0)
423  return;
424 
425  if (!facesets[fallback].prefix) {
426  LOG(llevError, "Face set %d falls to non set faceset %d\n", faceset, fallback);
427  abort();
428  }
429  togo--;
430  if (togo == 0) {
431  LOG(llevError, "Infinite loop found in facesets. aborting.\n");
432  abort();
433  }
434  check_faceset_fallback(fallback, togo);
435 }
436 
454 void read_client_images(void) {
455  char filename[400];
456  char buf[HUGE_BUF];
457  char *cp, *cps[7+1], *slash;
458  FILE *infile;
459  int len, fileno, i;
460  unsigned int num;
461  const Face *face;
462 
463  memset(facesets, 0, sizeof(facesets));
464  snprintf(filename, sizeof(filename), "%s/image_info", settings.datadir);
465  if ((infile = fopen(filename, "r")) == NULL) {
466  LOG(llevError, "Unable to open %s\n", filename);
467  abort();
468  }
469  while (fgets(buf, HUGE_BUF-1, infile) != NULL) {
470  if (buf[0] == '#')
471  continue;
472  if (split_string(buf, cps, sizeof(cps)/sizeof(*cps), ':') != 7)
473  LOG(llevError, "Bad line in image_info file, ignoring line:\n %s", buf);
474  else {
475  len = atoi(cps[0]);
476  if (len >= MAX_FACE_SETS) {
477  LOG(llevError, "To high a setnum in image_info file: %d > %d\n", len, MAX_FACE_SETS);
478  abort();
479  }
480  facesets[len].prefix = strdup_local(cps[1]);
481  facesets[len].fullname = strdup_local(cps[2]);
482  facesets[len].fallback = atoi(cps[3]);
483  facesets[len].size = strdup_local(cps[4]);
484  facesets[len].extension = strdup_local(cps[5]);
485  facesets[len].comment = strdup_local(cps[6]);
486  }
487  }
488  fclose(infile);
489  for (i = 0; i < MAX_FACE_SETS; i++) {
490  if (facesets[i].prefix)
491  check_faceset_fallback(i, MAX_FACE_SETS);
492  }
493  /* Loaded the faceset information - now need to load up the
494  * actual faces.
495  */
496 
497  for (fileno = 0; fileno < MAX_FACE_SETS; fileno++) {
498  /* if prefix is not set, this is not used */
499  if (!facesets[fileno].prefix)
500  continue;
501  facesets[fileno].faces = calloc(nrofpixmaps, sizeof(face_info));
502 
503  snprintf(filename, sizeof(filename), "%s/crossfire.%d", settings.datadir, fileno);
504  LOG(llevDebug, "images: loading from %s\n", filename);
505 
506  if ((infile = fopen(filename, "rb")) == NULL) {
507  LOG(llevError, "Unable to open %s\n", filename);
508  abort();
509  }
510  while (fgets(buf, HUGE_BUF-1, infile) != NULL) {
511  if (strncmp(buf, "IMAGE ", 6) != 0) {
512  LOG(llevError, "read_client_images:Bad image line - not IMAGE, instead\n%s", buf);
513  abort();
514  }
515  cp = buf + 6;
516  len = atoi(cp);
517  if (len == 0 || len > MAX_IMAGE_SIZE) {
518  LOG(llevError, "read_client_images: length not valid: %d > %d \n%s", len, MAX_IMAGE_SIZE, buf);
519  abort();
520  }
521 
522  for ( ; *cp != ' ' && *cp != '\n' && *cp != '\0'; cp++) {
523  /* Increment pointer until next token. */
524  }
525 
526  if (*cp != ' ') {
527  LOG(llevError, "read_client_images: couldn't read name\n");
528  abort();
529  }
530  cp++;
531  /* cp points to the start of the full name */
532  slash = strrchr(cp, '/');
533  if (slash != NULL)
534  cp = slash + 1;
535  if (cp[strlen(cp) - 1] == '\n')
536  cp[strlen(cp) - 1] = '\0';
537 
538  /* cp points to the start of the picture name itself */
539  face = find_face(cp, NULL);
540  if (face == NULL) {
541  LOG(llevError, "read_client_images: couldn't find picture %s\n", cp);
542  abort();
543  }
544  num = face->number;
545  if (num >= nrofpixmaps) {
546  LOG(llevError, "read_client_images: invalid picture number %d for %s\n", num, cp);
547  abort();
548  }
549 
550  facesets[fileno].faces[num].datalen = len;
551  facesets[fileno].faces[num].data = malloc(len);
552  if ((i = fread(facesets[fileno].faces[num].data, len, 1, infile)) != 1) {
553  LOG(llevError, "read_client_images: Did not read desired amount of data, wanted %d, got %d\n%s", len, i, buf);
554  abort();
555  }
556  facesets[fileno].faces[num].checksum = 0;
557  for (i = 0; i < len; i++) {
558  ROTATE_RIGHT(facesets[fileno].faces[num].checksum);
559  facesets[fileno].faces[num].checksum += facesets[fileno].faces[num].data[i];
560  facesets[fileno].faces[num].checksum &= 0xffffffff;
561  }
562  }
563  fclose(infile);
564  } /* For fileno < MAX_FACE_SETS */
565 }
566 
571 int is_valid_faceset(int fsn) {
572  if (fsn >= 0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix)
573  return TRUE;
574  return FALSE;
575 }
576 
580 void free_socket_images(void) {
581  int num;
582  unsigned int q;
583 
584  for (num = 0; num < MAX_FACE_SETS; num++) {
585  if (facesets[num].prefix) {
586  for (q = 0; q < nrofpixmaps; q++)
587  free(facesets[num].faces[q].data);
588  free(facesets[num].prefix);
589  free(facesets[num].fullname);
590  free(facesets[num].size);
591  free(facesets[num].extension);
592  free(facesets[num].comment);
593  free(facesets[num].faces);
594  }
595  }
596 }
597 
610 int get_face_fallback(int faceset, int imageno) {
611  /* faceset 0 is supposed to have every image, so just return. Doing
612  * so also prevents infinite loops in the case if it not having
613  * the face, but in that case, we are likely to crash when we try
614  * to access the data, but that is probably preferable to an infinite
615  * loop.
616  */
617  if (faceset == 0)
618  return 0;
619 
620  if (!facesets[faceset].prefix) {
621  LOG(llevError, "get_face_fallback called with unused set (%d)?\n", faceset);
622  return 0; /* use default set */
623  }
624  if (facesets[faceset].faces[imageno].data)
625  return faceset;
626  return get_face_fallback(facesets[faceset].fallback, imageno);
627 }
628 
633 unsigned int get_faces_count() {
634  return nrofpixmaps;
635 }
636 
642 const Face *get_face_by_index(int index) {
643  if (index < 0 || index >= nrofpixmaps)
644  return NULL;
645  return &new_faces[index];
646 }
647 
654  for (int f = 0; f < nrofpixmaps; f++) {
655  if (new_faces[f].number == id)
656  return &new_faces[f];
657  }
658  return NULL;
659 }
const Face * smooth_face
Definition: image.c:39
static Face * internal_find_face(const char *name)
Definition: image.c:100
const Face * get_face_by_id(uint16_t id)
Definition: image.c:653
face_info * faces
Definition: image.h:24
#define ROTATE_RIGHT(c)
Definition: global.h:165
unsigned char uint8_t
Definition: win32.h:161
static int compare_face(const Face *a, const Face *b)
Definition: image.c:83
#define strdup_local
Definition: compat.h:25
const Face * blank_face
Definition: image.c:39
void fatal(enum fatal_error err)
Definition: utils.c:597
Definition: face.h:14
#define HUGE_BUF
Definition: define.h:37
const Face * get_face_by_index(int index)
Definition: image.c:642
const char * name
Definition: face.h:19
int is_valid_faceset(int fsn)
Definition: image.c:571
#define TRUE
Definition: compat.h:10
#define FALSE
Definition: compat.h:11
#define FACE_FLOOR
Definition: newclient.h:277
static unsigned int nrofpixmaps
Definition: image.c:45
static void read_face_data(void)
Definition: image.c:140
int read_smooth(void)
Definition: image.c:332
Face * new_faces
Definition: image.c:33
const Face * empty_face
Definition: image.c:39
uint8_t * data
Definition: image.h:11
#define snprintf
Definition: win32.h:46
struct Face * smoothface
Definition: face.h:18
char * prefix
Definition: image.h:18
#define BLANK_FACE_NAME
Definition: define.h:592
char * extension
Definition: image.h:22
static uint8_t find_color(const char *name)
Definition: image.c:122
char * size
Definition: image.h:21
void free_socket_images(void)
Definition: image.c:580
uint16_t number
Definition: face.h:15
void read_client_images(void)
Definition: image.c:454
uint32_t checksum
Definition: image.h:13
unsigned int get_faces_count()
Definition: image.c:633
char * comment
Definition: image.h:23
#define MAX_BUF
Definition: define.h:35
void free_all_images(void)
Definition: image.c:402
unsigned short uint16_t
Definition: win32.h:163
void read_bmap_names(void)
Definition: image.c:196
#define MAX_IMAGE_SIZE
Definition: image.h:30
const char * datadir
Definition: global.h:247
#define MAX_FACE_SETS
Definition: image.h:26
face_sets facesets[MAX_FACE_SETS]
Definition: image.c:47
uint16_t datalen
Definition: image.h:12
uint8_t visibility
Definition: face.h:16
static const char *const colorname[]
Definition: image.c:56
EXTERN int bmaps_checksum
Definition: global.h:162
struct Settings settings
Definition: init.c:39
#define SMOOTH_FACE_NAME
Definition: define.h:594
char * fullname
Definition: image.h:19
size_t split_string(char *str, char *array[], size_t array_size, char sep)
Definition: utils.c:500
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
int get_face_fallback(int faceset, int imageno)
Definition: image.c:610
#define EMPTY_FACE_NAME
Definition: define.h:593
const Face * find_face(const char *name, const Face *error)
Definition: image.c:316
uint8_t magicmap
Definition: face.h:17
uint8_t fallback
Definition: image.h:20
int find_smooth(const Face *face, const Face **smoothed)
Definition: image.c:388
static void check_faceset_fallback(int faceset, int togo)
Definition: image.c:418