Crossfire Client, Trunk
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-2013 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 
20 #include "client.h"
21 
22 #include <ctype.h>
23 #include <glib/gstdio.h>
24 
25 #ifdef WIN32
26 #include <io.h>
27 #include <direct.h>
28 #endif
29 
30 #include "external.h"
31 
32 /* Rotate right from bsd sum. */
33 #define ROTATE_RIGHT(c) if ((c) & 01) (c) = ((c) >>1) + 0x80000000; else (c) >>= 1;
34 
35 /*#define CHECKSUM_DEBUG*/
36 
37 struct FD_Cache {
38  char name[MAX_BUF];
39  int fd;
41 
55 static int load_image(char *filename, guint8 *data, int *len, guint32 *csum) {
56  int fd, i;
57  char *cp;
58 
59  /* If the name includes an @, then that is a combined image file, so we
60  * need to load the image a bit specially. By using these combined image
61  * files, it reduces number of opens needed. In fact, we keep track of
62  * which ones we have opened to improve performance. Note that while not
63  * currently done, this combined image scheme could be done when storing
64  * images in the player's image cache. */
65  if ((cp = strchr(filename, '@')) != NULL) {
66  char *lp;
67  int offset, last = -1;
68 
69 #ifdef WIN32
70  int length;
71 #endif
72 
73  offset = atoi(cp + 1);
74  lp = strchr(cp, ':');
75  if (!lp) {
76  LOG(LOG_ERROR, "common::load_image",
77  "Corrupt filename - has '@' but no ':' ?(%s)", filename);
78  return -1;
79  }
80 #ifdef WIN32
81  length = atoi(lp + 1);
82 #endif
83  *cp = 0;
84  for (i = 0; i < MAX_FACE_SETS; i++) {
85  if (!strcmp(fd_cache[i].name, filename)) {
86  break;
87  }
88  if (last == -1 && fd_cache[i].fd == -1) {
89  last = i;
90  }
91  }
92  /* Didn't find a matching entry yet, so make one */
93  if (i == MAX_FACE_SETS) {
94  if (last == -1) {
95  LOG(LOG_WARNING, "common::load_image",
96  "fd_cache filled up? unable to load matching cache entry");
97  *cp = '@'; /* put @ back in string */
98  return -1;
99  }
100 #ifdef WIN32
101  if ((fd_cache[last].fd = open(filename, O_RDONLY | O_BINARY)) == -1)
102 #else
103  if ((fd_cache[last].fd = open(filename, O_RDONLY)) == -1)
104 #endif
105  {
106  LOG(LOG_WARNING, "common::load_image", "unable to load listed cache file %s",
107  filename);
108  *cp = '@'; /* put @ back in string */
109  return -1;
110  }
111  strcpy(fd_cache[last].name, filename);
112  i = last;
113  }
114  lseek(fd_cache[i].fd, offset, SEEK_SET);
115 #ifdef WIN32
116  *len = read(fd_cache[i].fd, data, length);
117 #else
118  *len = read(fd_cache[i].fd, data, 65535);
119 #endif
120  *cp = '@';
121  } else {
122 #ifdef WIN32
123  int length = 0;
124  if ((fd = open(filename, O_RDONLY | O_BINARY)) == -1) {
125  return -1;
126  }
127  length = lseek(fd, 0, SEEK_END);
128  lseek(fd, 0, SEEK_SET);
129  *len = read(fd, data, length);
130 #else
131  if ((fd = open(filename, O_RDONLY)) == -1) {
132  return -1;
133  }
134  *len = read(fd, data, 65535);
135 #endif
136  close(fd);
137  }
138 
140  *csum = 0;
141  return 0;
142 
143 #if 0
144  /* Shouldn't be needed anymore */
145  *csum = 0;
146  for (i = 0; i < *len; i++) {
147  ROTATE_RIGHT(*csum);
148  *csum += data[i];
149  *csum &= 0xffffffff;
150  }
151 #endif
152 
153 }
154 
155 /****************************************************************************
156  * This is our image caching logic. We use a hash to make the name lookups
157  * happen quickly - this is done for speed, but also because we don't really
158  * have a good idea on how many images may used. It also means that as the
159  * cache gets filled up with images in a random order, the lookup is still
160  * pretty quick.
161  *
162  * If a bucket is filled with an entry that is not of the right name,
163  * we store/look for the correct one in the next bucket.
164  */
165 
166 /* This should be a power of 2 */
167 #define IMAGE_HASH 8192
168 
170 
174 static char *facetoname[MAXPIXMAPNUM];
175 
176 
177 struct Image_Cache {
178  char *image_name;
181 
188 static guint32 image_hash_name(char *str, int tablesize) {
189  guint32 hash = 0;
190  char *p;
191 
192  /* use the same one-at-a-time hash function the server now uses */
193  for (p = str; *p != '\0' && *p != '.'; p++) {
194  hash += *p;
195  hash += hash << 10;
196  hash ^= hash >> 6;
197  }
198  hash += hash << 3;
199  hash ^= hash >> 11;
200  hash += hash << 15;
201  return hash % tablesize;
202 }
203 
208 static gint32 image_find_hash(char *str) {
209  guint32 hash = image_hash_name(str, IMAGE_HASH), newhash;
210 
211  newhash = hash;
212  do {
213  /* No entry - return immediately */
214  if (image_cache[newhash].image_name == NULL) {
215  return -1;
216  }
217  if (!strcmp(image_cache[newhash].image_name, str)) {
218  return newhash;
219  }
220  newhash ++;
221  if (newhash == IMAGE_HASH) {
222  newhash = 0;
223  }
224  } while (newhash != hash);
225 
226  /* If the hash table is full, this is bad because we won't be able to
227  * add any new entries.
228  */
229  LOG(LOG_WARNING, "common::image_find_hash",
230  "Hash table is full, increase IMAGE_CACHE size");
231  return -1;
232 }
233 
237 static void image_remove_hash(char *imagename, Cache_Entry *ce) {
238  int hash_entry;
239  Cache_Entry *last;
240 
241  hash_entry = image_find_hash(imagename);
242  if (hash_entry == -1) {
243  LOG(LOG_ERROR, "common::image_remove_hash",
244  "Unable to find cache entry for %s, %s", imagename, ce->filename);
245  return;
246  }
247  if (image_cache[hash_entry].cache_entry == ce) {
248  image_cache[hash_entry].cache_entry = ce->next;
249  free(ce->filename);
250  free(ce);
251  return;
252  }
253  last = image_cache[hash_entry].cache_entry;
254  while (last->next && last->next != ce) {
255  last = last->next;
256  }
257  if (!last->next) {
258  LOG(LOG_ERROR, "common::image_rmove_hash",
259  "Unable to find cache entry for %s, %s", imagename, ce->filename);
260  return;
261  }
262  last->next = ce->next;
263  free(ce->filename);
264  free(ce);
265 }
266 
272 static Cache_Entry *image_find_cache_entry(char *imagename, guint32 checksum,
273  int has_sum) {
274  int hash_entry;
275  Cache_Entry *entry;
276 
277  hash_entry = image_find_hash(imagename);
278  if (hash_entry == -1) {
279  return NULL;
280  }
281  entry = image_cache[hash_entry].cache_entry;
282  if (has_sum) {
283  while (entry) {
284  if (entry->checksum == checksum) {
285  break;
286  }
287  entry = entry->next;
288  }
289  }
290  return entry; /* This could be NULL */
291 }
292 
296 static Cache_Entry *image_add_hash(char *imagename, char *filename, guint32 checksum) {
297  Cache_Entry *new_entry;
298  guint32 hash = image_hash_name(imagename, IMAGE_HASH), newhash;
299 
300  newhash = hash;
301  while (image_cache[newhash].image_name != NULL &&
302  strcmp(image_cache[newhash].image_name, imagename)) {
303  newhash ++;
304  if (newhash == IMAGE_HASH) {
305  newhash = 0;
306  }
307  /* If the hash table is full, can't do anything */
308  if (newhash == hash) {
309  LOG(LOG_WARNING, "common::image_find_hash",
310  "Hash table is full, increase IMAGE_CACHE size");
311  return NULL;
312  }
313  }
314  if (!image_cache[newhash].image_name) {
315  image_cache[newhash].image_name = g_strdup(imagename);
316  }
317 
318  /* We insert the new entry at the start of the list of the buckets
319  * for this entry. In the case of the players entries, this probably
320  * improves performance, presuming ones later in the file are more likely
321  * to be used compared to those at the start of the file.
322  */
323  new_entry = g_malloc(sizeof(struct Cache_Entry));
324  new_entry->filename = g_strdup(filename);
325  new_entry->checksum = checksum;
326  new_entry->image_data = NULL;
327  new_entry->next = image_cache[newhash].cache_entry;
328  image_cache[newhash].cache_entry = new_entry;
329  return new_entry;
330 }
331 
338 static void image_process_line(char *line) {
339  char imagename[MAX_BUF], filename[MAX_BUF];
340  guint32 checksum;
341 
342  if (line[0] == '#') {
343  return; /* Ignore comments */
344  }
345 
346  if (sscanf(line, "%s %u %s", imagename, &checksum, filename) == 3) {
347  image_add_hash(imagename, filename, checksum);
348  } else {
349  LOG(LOG_WARNING, "common::image_process_line",
350  "Did not parse line %s properly?", line);
351  }
352 }
353 
358  FILE *fp;
359  char bmaps[MAX_BUF], inbuf[MAX_BUF];
360  int i;
361 
362  if (!want_config[CONFIG_CACHE]) {
363  return;
364  }
365 
366  for (i = 0; i < MAXPIXMAPNUM; i++) {
367  facetoname[i] = NULL;
368  }
369 
370  /* First, make sure that image_cache is nulled out */
371  memset(image_cache, 0, IMAGE_HASH * sizeof(struct Image_Cache));
372 
373  snprintf(bmaps, sizeof(bmaps), "%s/image-cache/bmaps.client", cache_dir);
374  if ((fp = fopen(bmaps, "r")) != NULL) {
375  while (fgets(inbuf, MAX_BUF - 1, fp) != NULL) {
376  image_process_line(inbuf);
377  }
378  fclose(fp);
379  } /* User may not have a cache, so no error if not found */
380  for (i = 0; i < MAX_FACE_SETS; i++) {
381  fd_cache[i].fd = -1;
382  fd_cache[i].name[0] = '\0';
383  }
384 }
385 
386 /******************************************************************************
387  *
388  * Code related to face caching.
389  *
390  *****************************************************************************/
391 
393 
397 void requestface(int pnum, char *facename) {
399  facetoname[pnum] = g_strdup(facename);
400  cs_print_string(csocket.fd, "askface %d", pnum);
401 }
402 
414 void finish_face_cmd(int pnum, guint32 checksum, int has_sum, char *face,
415  int faceset) {
416  int len;
417  guint32 nx, ny;
418  guint8 data[65536], *png_tmp;
419  char filename[1024];
420  guint32 newsum = 0;
421  Cache_Entry *ce = NULL;
422 
423 #if 0
424  fprintf(stderr, "finish_face_cmd, pnum=%d, checksum=%d, face=%s\n",
425  pnum, checksum, face);
426 #endif
427 
428  /* In the case of gfx, we don't care about checksum. For public and
429  * private areas, if we care about checksum, and the image doesn't match,
430  * we go onto the next step. If nothing found, we request it
431  * from the server.
432  */
433  snprintf(filename, sizeof(filename), "%s/gfx/%s.png", cache_dir, face);
434  if (load_image(filename, data, &len, &newsum) == -1) {
435  ce = image_find_cache_entry(face, checksum, has_sum);
436  if (!ce) {
437  /* Not in our cache, so request it from the server */
438  requestface(pnum, face);
439  return;
440  } else if (ce->image_data) {
441  /* If this has image_data, then it has already been rendered */
442  if (!associate_cache_entry(ce, pnum)) {
443  return;
444  }
445  }
446  snprintf(filename, sizeof(filename), "%s/image-cache/%s", cache_dir, ce->filename);
447  if (load_image(filename, data, &len, &newsum) == -1) {
448  LOG(LOG_WARNING, "common::finish_face_cmd",
449  "file %s listed in cache file, but unable to load", filename);
450  requestface(pnum, face);
451  return;
452  }
453  }
454 
455  /* If we got here, we found an image and the checksum is OK. */
456 
457  if (!(png_tmp = png_to_data(data, len, &nx, &ny))) {
458  /* If the data is bad, remove it if it is in the players private cache */
459  LOG(LOG_WARNING, "common::finish_face_cmd",
460  "Got error on png_to_data, image=%s", face);
461  if (ce) {
462  unlink(filename);
463  image_remove_hash(face, ce);
464  }
465 
466  requestface(pnum, face);
467  }
468 
469  /* create_and_rescale_image_from data is an external reference to a piece in
470  * the gui section of the code.
471  */
472  if (create_and_rescale_image_from_data(ce, pnum, png_tmp, nx, ny)) {
473  LOG(LOG_WARNING, "common::finish_face_cmd",
474  "Got error on create_and_rescale_image_from_data, file=%s", filename);
475  requestface(pnum, face);
476  }
477  free(png_tmp);
478 }
479 
480 
488  int i;
489 
490  if (want_config[CONFIG_CACHE]) {
491  for (i = 1; i < MAXPIXMAPNUM; i++) {
492  free(facetoname[i]);
493  facetoname[i] = NULL;
494  }
495  }
496 }
497 
504 void Face2Cmd(guint8 *data, int len) {
505  int pnum;
506  guint8 setnum;
507  guint32 checksum;
508  char *face;
509 
510  /* A quick sanity check, since if client isn't caching, all the data
511  * structures may not be initialized.
512  */
513  if (!use_config[CONFIG_CACHE]) {
514  LOG(LOG_WARNING, "common::Face2Cmd",
515  "Received a 'face' command when we are not caching");
516  return;
517  }
518  pnum = GetShort_String(data);
519  setnum = data[2];
520  checksum = GetInt_String(data + 3);
521  face = (char *)data + 7;
522  data[len] = '\0';
523 
524  finish_face_cmd(pnum, checksum, 1, face, setnum);
525 }
526 
530 void Image2Cmd(guint8 *data, int len) {
531  int pnum, plen;
532  guint8 setnum;
533 
534  pnum = GetInt_String(data);
535  setnum = data[4];
536  plen = GetInt_String(data + 5);
537  if (len < 9 || (len - 9) != plen) {
538  LOG(LOG_WARNING, "common::Image2Cmd", "Lengths don't compare (%d,%d)",
539  (len - 9), plen);
540  return;
541  }
542  display_newpng(pnum, data + 9, plen, setnum);
543 }
544 
548 static void cache_newpng(int face, guint8 *buf, int buflen, int setnum,
549  Cache_Entry **ce) {
550  char filename[MAX_BUF], basename[MAX_BUF];
551  FILE *tmpfile;
552  guint32 i, csum;
553 
554  if (facetoname[face] == NULL) {
555  LOG(LOG_WARNING, "common::display_newpng",
556  "Caching images, but name for %ld not set", face);
557  /* Return to avoid null dereference. */
558  return;
559  }
560  /* Make necessary leading directories */
561  snprintf(filename, sizeof(filename), "%s/image-cache", cache_dir);
562  if (g_access(filename, R_OK | W_OK | X_OK) == -1) {
563  g_mkdir(filename, 0755);
564  }
565 
566  snprintf(filename, sizeof(filename), "%s/image-cache/%c%c",
567  cache_dir, facetoname[face][0], facetoname[face][1]);
568  if (access(filename, R_OK | W_OK | X_OK) == -1) {
569  g_mkdir(filename, 0755);
570  }
571 
572  /* If setnum is valid, and we have faceset information for it,
573  * put that prefix in. This will make it easier later on to
574  * allow the client to switch image sets on the fly, as it can
575  * determine what set the image belongs to.
576  * We also append the number to it - there could be several versions
577  * of 'face.base.111.x' if different servers have different image
578  * values.
579  */
580  if (setnum >= 0 && setnum < MAX_FACE_SETS &&
581  face_info.facesets[setnum].prefix) {
582  snprintf(basename, sizeof(basename), "%s.%s", facetoname[face],
583  face_info.facesets[setnum].prefix);
584  } else {
585  strcpy(basename, facetoname[face]);
586  }
587 
588  /* Decrease it by one since it will immediately get increased
589  * in the loop below.
590  */
591  setnum--;
592  do {
593  setnum++;
594  snprintf(filename, sizeof(filename), "%s/image-cache/%c%c/%s.%d",
595  cache_dir, facetoname[face][0], facetoname[face][1], basename, setnum);
596  } while (g_access(filename, F_OK) == -0);
597 
598 #ifdef WIN32
599  if ((tmpfile = fopen(filename, "wb")) == NULL)
600 #else
601  if ((tmpfile = fopen(filename, "w")) == NULL)
602 #endif
603  {
604  LOG(LOG_WARNING, "common::display_newpng", "Can not open %s for writing",
605  filename);
606  } else {
607  /* found a file we can write to */
608 
609  fwrite(buf, buflen, 1, tmpfile);
610  fclose(tmpfile);
611  csum = 0;
612  for (i = 0; (int)i < buflen; i++) {
613  ROTATE_RIGHT(csum);
614  csum += buf[i];
615  csum &= 0xffffffff;
616  }
617  snprintf(filename, sizeof(filename), "%c%c/%s.%d", facetoname[face][0],
618  facetoname[face][1],
619  basename, setnum);
620  *ce = image_add_hash(facetoname[face], filename, csum);
621 
622  /* It may very well be more efficient to try to store these up
623  * and then write them as a bunch instead of constantly opening the
624  * file for appending. OTOH, hopefully people will be using the
625  * built image archives, so only a few faces actually need to get
626  * downloaded.
627  */
628  snprintf(filename, sizeof(filename), "%s/image-cache/bmaps.client", cache_dir);
629  if ((tmpfile = fopen(filename, "a")) == NULL) {
630  LOG(LOG_WARNING, "common::display_newpng", "Can not open %s for appending",
631  filename);
632  } else {
633  fprintf(tmpfile, "%s %u %c%c/%s.%d\n",
634  facetoname[face], csum, facetoname[face][0],
635  facetoname[face][1], basename, setnum);
636  fclose(tmpfile);
637  }
638  }
639 }
640 
641 
647 void display_newpng(int face, guint8 *buf, int buflen, int setnum) {
648  guint8 *pngtmp;
649  guint32 width, height;
650  Cache_Entry *ce = NULL;
651 
652  if (use_config[CONFIG_CACHE]) {
653  cache_newpng(face, buf, buflen, setnum, &ce);
654  }
655 
656  pngtmp = png_to_data(buf, buflen, &width, &height);
657  if (!pngtmp) {
658  LOG(LOG_ERROR, "display_newpng", "error in PNG data; discarding");
659  return;
660  }
661 
662  if (create_and_rescale_image_from_data(ce, face, pngtmp, width, height)) {
663  LOG(LOG_WARNING, "common::display_newpng",
664  "create_and_rescale_image_from_data failed for face %ld", face);
665  }
666 
667  if (use_config[CONFIG_CACHE]) {
668  free(facetoname[face]);
669  facetoname[face] = NULL;
670  }
671  free(pngtmp);
672 }
673 
684 void get_image_info(guint8 *data, int len) {
685  char *cp, *lp, *cps[7], buf[MAX_BUF];
686  int onset = 0, badline = 0, i;
687 
689 
690  lp = (char *)data;
691  cp = strchr(lp, '\n');
692  if (!cp || (cp - lp) > len) {
693  return;
694  }
695  face_info.num_images = atoi(lp);
696 
697  lp = cp + 1;
698  cp = strchr(lp, '\n');
699  if (!cp || (cp - lp) > len) {
700  return;
701  }
702  face_info.bmaps_checksum = strtoul(lp, NULL,
703  10); /* need unsigned, so no atoi */
704 
705  lp = cp + 1;
706  cp = strchr(lp, '\n');
707  while (cp && (cp - lp) <= len) {
708  *cp++ = '\0';
709 
710  /* The code below is pretty much the same as the code from the server
711  * which loads the original faceset file.
712  */
713  if (!(cps[0] = strtok(lp, ":"))) {
714  badline = 1;
715  }
716  for (i = 1; i < 7; i++) {
717  if (!(cps[i] = strtok(NULL, ":"))) {
718  badline = 1;
719  }
720  }
721  if (badline) {
722  LOG(LOG_WARNING, "common::get_image_info", "bad data, ignoring line:/%s/", lp);
723  } else {
724  onset = atoi(cps[0]);
725  if (onset >= MAX_FACE_SETS) {
726  LOG(LOG_WARNING, "common::get_image_info", "setnum is too high: %d > %d",
727  onset, MAX_FACE_SETS);
728  }
729  face_info.facesets[onset].prefix = g_strdup(cps[1]);
730  face_info.facesets[onset].fullname = g_strdup(cps[2]);
731  face_info.facesets[onset].fallback = atoi(cps[3]);
732  face_info.facesets[onset].size = g_strdup(cps[4]);
733  face_info.facesets[onset].extension = g_strdup(cps[5]);
734  face_info.facesets[onset].comment = g_strdup(cps[6]);
735  }
736  lp = cp;
737  cp = strchr(lp, '\n');
738  }
740  /* if the user has requested a specific face set and that set
741  * is not numeric, try to find a matching set and send the
742  * relevent setup command.
743  */
744  if (face_info.want_faceset && atoi(face_info.want_faceset) == 0) {
745  for (onset = 0; onset < MAX_FACE_SETS; onset++) {
746  if (face_info.facesets[onset].prefix &&
747  !g_ascii_strcasecmp(face_info.facesets[onset].prefix, face_info.want_faceset)) {
748  break;
749  }
750  if (face_info.facesets[onset].fullname &&
751  !g_ascii_strcasecmp(face_info.facesets[onset].fullname, face_info.want_faceset)) {
752  break;
753  }
754  }
755  if (onset < MAX_FACE_SETS) { /* We found a match */
756  face_info.faceset = onset;
757  cs_print_string(csocket.fd, "setup faceset %d", onset);
758  } else {
759  snprintf(buf, sizeof(buf), "Unable to find match for faceset %s on the server",
762  }
763  }
764 
765 }
766 
780 void get_image_sums(char *data, int len) {
781  int stop, imagenum, slen, faceset;
782  guint32 checksum;
783  char *cp, *lp;
784 
785  cp = strchr((char *)data, ' ');
786  if (!cp || (cp - data) > len) {
787  return;
788  }
789 
790  while (isspace(*cp)) {
791  cp++;
792  }
793  lp = cp;
794  cp = strchr(lp, ' ');
795  if (!cp || (cp - data) > len) {
796  return;
797  }
798  stop = atoi(lp);
799 
800  replyinfo_last_face = stop;
801 
802  /* Can't use isspace here, because it matches with tab, ascii code
803  * 9 - this results in advancing too many spaces because
804  * starting at image 2304, the MSB of the image number will be
805  * 9. Using a check against space will work until we get up to
806  * 8192 images.
807  */
808  while (*cp == ' ') {
809  cp++;
810  }
811  while ((cp - data) < len) {
812  imagenum = GetShort_String((guint8 *)cp);
813  cp += 2;
814  checksum = GetInt_String((guint8 *)cp);
815  cp += 4;
816  faceset = *cp;
817  cp++;
818  slen = *cp;
819  cp++;
820  /* Note that as is, this can break horribly if the client is missing a large number
821  * of images - that is because it will request a whole bunch which will overflow
822  * the servers output buffer, causing it to close the connection.
823  * What probably should be done is for the client to just request this checksum
824  * information in small batches so that even if the client has no local
825  * images, requesting the entire batch won't overflow the sockets buffer - this
826  * probably amounts to about 100 images at a time
827  */
828  finish_face_cmd(imagenum, checksum, 1, (char *)cp, faceset);
829  if (imagenum > stop) {
830  LOG(LOG_WARNING, "common::get_image_sums",
831  "Received an image beyond our range? %d > %d", imagenum, stop);
832  }
833  cp += slen;
834  }
835 }
836 
create_and_rescale_image_from_data
int create_and_rescale_image_from_data(Cache_Entry *ce, int pixmap_num, guint8 *rgba_data, int width, int height)
Takes the pixmap to put the data into, as well as the rgba data (ie, already loaded with png_to_data)...
Definition: image.c:142
MSG_TYPE_CLIENT
#define MSG_TYPE_CLIENT
Client originated Messages.
Definition: newclient.h:390
FaceSets_struct::comment
char * comment
Definition: client.h:400
GetShort_String
short GetShort_String(const unsigned char *data)
Definition: newsocket.c:180
LOG_WARNING
@ LOG_WARNING
Warning that something might not work.
Definition: client.h:437
FD_Cache::fd
int fd
Definition: image.c:39
facecachedir
char facecachedir[MAX_BUF]
Definition: image.c:392
load_image
static int load_image(char *filename, guint8 *data, int *len, guint32 *csum)
Given a filename, this tries to load the data.
Definition: image.c:55
image_cache
struct Image_Cache image_cache[IMAGE_HASH]
ClientSocket::fd
GSocketConnection * fd
Definition: client.h:124
Face_Information_struct::num_images
gint16 num_images
Definition: client.h:410
Cache_Entry
Used mostly in the cache.c file, however, it can be returned to the graphic side of things so that th...
Definition: client.h:501
cache_dir
const char * cache_dir
Definition: client.c:52
external.h
png_to_data
guint8 * png_to_data(guint8 *data, int len, guint32 *width, guint32 *height)
Definition: png.c:49
ROTATE_RIGHT
#define ROTATE_RIGHT(c)
Definition: image.c:33
cache_newpng
static void cache_newpng(int face, guint8 *buf, int buflen, int setnum, Cache_Entry **ce)
Helper for display_newpng, implements the caching of the image to disk.
Definition: image.c:548
fd_cache
struct FD_Cache fd_cache[MAX_FACE_SETS]
FaceSets_struct::size
char * size
Definition: client.h:398
height
static int height
Definition: mapdata.c:101
MAXPIXMAPNUM
#define MAXPIXMAPNUM
Definition: client.h:492
GetInt_String
int GetInt_String(const unsigned char *data)
The reverse of SockList_AddInt, but on strings instead.
Definition: newsocket.c:150
NDI_RED
#define NDI_RED
Definition: newclient.h:227
Face_Information_struct
One struct that holds most of the image related data to reduce danger of namespace collision.
Definition: client.h:407
Face_Information_struct::bmaps_checksum
guint32 bmaps_checksum
Definition: client.h:411
replyinfo_status
int replyinfo_status
Definition: client.c:56
IMAGE_HASH
#define IMAGE_HASH
Definition: image.c:167
FaceSets_struct::prefix
char * prefix
Definition: client.h:396
Image_Cache
Definition: image.c:177
Face_Information_struct::cache_misses
gint16 cache_misses
Definition: client.h:418
get_image_info
void get_image_info(guint8 *data, int len)
Takes the data from a replyinfo image_info and breaks it down.
Definition: image.c:684
image_add_hash
static Cache_Entry * image_add_hash(char *imagename, char *filename, guint32 checksum)
Add a hash entry.
Definition: image.c:296
CONFIG_CACHE
#define CONFIG_CACHE
Definition: client.h:186
Face_Information_struct::facesets
FaceSets facesets[MAX_FACE_SETS]
Definition: client.h:422
MAX_BUF
#define MAX_BUF
Definition: client.h:40
display_newpng
void display_newpng(int face, guint8 *buf, int buflen, int setnum)
This function is called when the server has sent us the actual png data for an image.
Definition: image.c:647
finish_face_cmd
void finish_face_cmd(int pnum, guint32 checksum, int has_sum, char *face, int faceset)
This is common for all the face commands (face2, face1, face).
Definition: image.c:414
reset_image_cache_data
void reset_image_cache_data(void)
We can now connect to different servers, so we need to clear out any old images.
Definition: image.c:487
Cache_Entry::checksum
guint32 checksum
Definition: client.h:503
associate_cache_entry
int associate_cache_entry(Cache_Entry *ce, int pixnum)
This functions associates image_data in the cache entry with the specific pixmap number.
Definition: image.c:264
get_image_sums
void get_image_sums(char *data, int len)
This gets a block of checksums from the server.
Definition: image.c:780
Face_Information_struct::want_faceset
char * want_faceset
Definition: client.h:409
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Log messages of a certain importance to stderr.
Definition: misc.c:111
cs_print_string
int cs_print_string(GSocketConnection *fd, const char *str,...)
Send a printf-formatted packet to the socket.
Definition: newsocket.c:251
width
static int width
Definition: mapdata.c:100
image_process_line
static void image_process_line(char *line)
Process a line from the bmaps.client file.
Definition: image.c:338
want_config
gint16 want_config[CONFIG_NUMS]
Definition: init.c:44
draw_ext_info
void draw_ext_info(int orig_color, int type, int subtype, const char *message)
A message processor that accepts messages along with meta information color and type.
Definition: info.c:915
csocket
ClientSocket csocket
Definition: client.c:69
RI_IMAGE_INFO
#define RI_IMAGE_INFO
Definition: client.h:519
MAX_FACE_SETS
#define MAX_FACE_SETS
Definition: client.h:383
FaceSets_struct::extension
char * extension
Definition: client.h:399
Face2Cmd
void Face2Cmd(guint8 *data, int len)
We only get here if the server believes we are caching images.
Definition: image.c:504
image_remove_hash
static void image_remove_hash(char *imagename, Cache_Entry *ce)
Definition: image.c:237
FD_Cache::name
char name[MAX_BUF]
Definition: image.c:38
FD_Cache
Definition: image.c:37
Cache_Entry::image_data
void * image_data
Definition: client.h:504
LOG_ERROR
@ LOG_ERROR
Warning that something definitely didn't work.
Definition: client.h:438
Image2Cmd
void Image2Cmd(guint8 *data, int len)
Definition: image.c:530
FaceSets_struct::fullname
char * fullname
Definition: client.h:397
MSG_TYPE_CLIENT_CONFIG
#define MSG_TYPE_CLIENT_CONFIG
Local configuration issues.
Definition: newclient.h:633
image_hash_name
static guint32 image_hash_name(char *str, int tablesize)
This function is basically hasharch from the server, common/arch.c a few changes - first,...
Definition: image.c:188
image_find_hash
static gint32 image_find_hash(char *str)
This function returns an index into the image_cache for a matching entry, -1 if no match is found.
Definition: image.c:208
Image_Cache::image_name
char * image_name
Definition: image.c:178
Image_Cache::cache_entry
struct Cache_Entry * cache_entry
Definition: image.c:179
replyinfo_last_face
int replyinfo_last_face
Definition: client.c:57
requestface
void requestface(int pnum, char *facename)
Definition: image.c:397
init_common_cache_data
void init_common_cache_data(void)
Definition: image.c:357
Face_Information_struct::faceset
guint8 faceset
Definition: client.h:408
face_info
Face_Information face_info
Definition: image.c:169
use_config
gint16 use_config[CONFIG_NUMS]
Definition: client.h:244
Face_Information_struct::have_faceset_info
guint8 have_faceset_info
Simple value to know if there is data in facesets[].
Definition: client.h:419
Face_Information_struct::cache_hits
gint16 cache_hits
Just for debugging/logging purposes.
Definition: client.h:418
image_find_cache_entry
static Cache_Entry * image_find_cache_entry(char *imagename, guint32 checksum, int has_sum)
This finds and returns the Cache_Entry of the image that matches name and checksum if has_sum is set.
Definition: image.c:272
facetoname
static char * facetoname[MAXPIXMAPNUM]
This holds the name we recieve with the 'face' command so we know what to save it as when we actually...
Definition: image.c:174
Cache_Entry::filename
char * filename
Definition: client.h:502
client.h
Cache_Entry::next
struct Cache_Entry * next
Definition: client.h:505
FaceSets_struct::fallback
guint8 fallback
Definition: client.h:395