Crossfire Client, Trunk  R20612
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,
297  guint32 checksum, guint32 ispublic) {
298  Cache_Entry *new_entry;
299  guint32 hash = image_hash_name(imagename, IMAGE_HASH), newhash;
300 
301  newhash = hash;
302  while (image_cache[newhash].image_name != NULL &&
303  strcmp(image_cache[newhash].image_name, imagename)) {
304  newhash ++;
305  if (newhash == IMAGE_HASH) {
306  newhash = 0;
307  }
308  /* If the hash table is full, can't do anything */
309  if (newhash == hash) {
310  LOG(LOG_WARNING, "common::image_find_hash",
311  "Hash table is full, increase IMAGE_CACHE size");
312  return NULL;
313  }
314  }
315  if (!image_cache[newhash].image_name) {
316  image_cache[newhash].image_name = g_strdup(imagename);
317  }
318 
319  /* We insert the new entry at the start of the list of the buckets
320  * for this entry. In the case of the players entries, this probably
321  * improves performance, presuming ones later in the file are more likely
322  * to be used compared to those at the start of the file.
323  */
324  new_entry = g_malloc(sizeof(struct Cache_Entry));
325  new_entry->filename = g_strdup(filename);
326  new_entry->checksum = checksum;
327  new_entry->ispublic = ispublic;
328  new_entry->image_data = NULL;
329  new_entry->next = image_cache[newhash].cache_entry;
330  image_cache[newhash].cache_entry = new_entry;
331  return new_entry;
332 }
333 
340 static void image_process_line(char *line, guint32 ispublic) {
341  char imagename[MAX_BUF], filename[MAX_BUF];
342  guint32 checksum;
343 
344  if (line[0] == '#') {
345  return; /* Ignore comments */
346  }
347 
348  if (sscanf(line, "%s %u %s", imagename, &checksum, filename) == 3) {
349  image_add_hash(imagename, filename, checksum, ispublic);
350  } else {
351  LOG(LOG_WARNING, "common::image_process_line",
352  "Did not parse line %s properly?", line);
353  }
354 }
355 
360  FILE *fp;
361  char bmaps[MAX_BUF], inbuf[MAX_BUF];
362  int i;
363 
364  if (!want_config[CONFIG_CACHE]) {
365  return;
366  }
367 
368  for (i = 0; i < MAXPIXMAPNUM; i++) {
369  facetoname[i] = NULL;
370  }
371 
372  /* First, make sure that image_cache is nulled out */
373  memset(image_cache, 0, IMAGE_HASH * sizeof(struct Image_Cache));
374 
375  snprintf(bmaps, sizeof(bmaps), "%s/bmaps.client", CF_DATADIR);
376  if ((fp = fopen(bmaps, "r")) != NULL) {
377  while (fgets(inbuf, MAX_BUF - 1, fp) != NULL) {
378  image_process_line(inbuf, 1);
379  }
380  fclose(fp);
381  } else {
382  snprintf(inbuf, sizeof(inbuf),
383  "Unable to open %s. You may wish to download and install the image file to improve performance.\n",
384  bmaps);
386  }
387 
388  snprintf(bmaps, sizeof(bmaps), "%s/image-cache/bmaps.client", cache_dir);
389  if ((fp = fopen(bmaps, "r")) != NULL) {
390  while (fgets(inbuf, MAX_BUF - 1, fp) != NULL) {
391  image_process_line(inbuf, 0);
392  }
393  fclose(fp);
394  } /* User may not have a cache, so no error if not found */
395  for (i = 0; i < MAX_FACE_SETS; i++) {
396  fd_cache[i].fd = -1;
397  fd_cache[i].name[0] = '\0';
398  }
399 }
400 
401 /******************************************************************************
402  *
403  * Code related to face caching.
404  *
405  *****************************************************************************/
406 
408 
412 void requestface(int pnum, char *facename) {
413  face_info.cache_misses++;
414  facetoname[pnum] = g_strdup(facename);
415  cs_print_string(csocket.fd, "askface %d", pnum);
416 }
417 
429 void finish_face_cmd(int pnum, guint32 checksum, int has_sum, char *face,
430  int faceset) {
431  int len;
432  guint32 nx, ny;
433  guint8 data[65536], *png_tmp;
434  char filename[1024];
435  guint32 newsum = 0;
436  Cache_Entry *ce = NULL;
437 
438 #if 0
439  fprintf(stderr, "finish_face_cmd, pnum=%d, checksum=%d, face=%s\n",
440  pnum, checksum, face);
441 #endif
442 
443  /* In the case of gfx, we don't care about checksum. For public and
444  * private areas, if we care about checksum, and the image doesn't match,
445  * we go onto the next step. If nothing found, we request it
446  * from the server.
447  */
448  snprintf(filename, sizeof(filename), "%s/gfx/%s.png", cache_dir, face);
449  if (load_image(filename, data, &len, &newsum) == -1) {
450  ce = image_find_cache_entry(face, checksum, has_sum);
451  if (!ce) {
452  /* Not in our cache, so request it from the server */
453  requestface(pnum, face);
454  return;
455  } else if (ce->image_data) {
456  /* If this has image_data, then it has already been rendered */
457  if (!associate_cache_entry(ce, pnum)) {
458  return;
459  }
460  }
461  if (ce->ispublic)
462  snprintf(filename, sizeof(filename), "%s/%s",
463  CF_DATADIR, ce->filename);
464  else
465  snprintf(filename, sizeof(filename), "%s/image-cache/%s",
466  cache_dir, ce->filename);
467  if (load_image(filename, data, &len, &newsum) == -1) {
468  LOG(LOG_WARNING, "common::finish_face_cmd",
469  "file %s listed in cache file, but unable to load", filename);
470  requestface(pnum, face);
471  return;
472  }
473  }
474 
475  /* If we got here, we found an image and the checksum is OK. */
476 
477  if (!(png_tmp = png_to_data(data, len, &nx, &ny))) {
478  /* If the data is bad, remove it if it is in the players private cache */
479  LOG(LOG_WARNING, "common::finish_face_cmd",
480  "Got error on png_to_data, image=%s", face);
481  if (ce) {
482  if (!ce->ispublic) {
483  unlink(filename);
484  }
485  image_remove_hash(face, ce);
486  }
487 
488  requestface(pnum, face);
489  }
490 
491  /* create_and_rescale_image_from data is an external reference to a piece in
492  * the gui section of the code.
493  */
494  if (create_and_rescale_image_from_data(ce, pnum, png_tmp, nx, ny)) {
495  LOG(LOG_WARNING, "common::finish_face_cmd",
496  "Got error on create_and_rescale_image_from_data, file=%s", filename);
497  requestface(pnum, face);
498  }
499  free(png_tmp);
500 }
501 
502 
510  int i;
511 
512  if (want_config[CONFIG_CACHE]) {
513  for (i = 1; i < MAXPIXMAPNUM; i++) {
514  free(facetoname[i]);
515  facetoname[i] = NULL;
516  }
517  }
518 }
519 
526 void Face2Cmd(guint8 *data, int len) {
527  int pnum;
528  guint8 setnum;
529  guint32 checksum;
530  char *face;
531 
532  /* A quick sanity check, since if client isn't caching, all the data
533  * structures may not be initialized.
534  */
535  if (!use_config[CONFIG_CACHE]) {
536  LOG(LOG_WARNING, "common::Face2Cmd",
537  "Received a 'face' command when we are not caching");
538  return;
539  }
540  pnum = GetShort_String(data);
541  setnum = data[2];
542  checksum = GetInt_String(data + 3);
543  face = (char *)data + 7;
544  data[len] = '\0';
545 
546  finish_face_cmd(pnum, checksum, 1, face, setnum);
547 }
548 
552 void Image2Cmd(guint8 *data, int len) {
553  int pnum, plen;
554  guint8 setnum;
555 
556  pnum = GetInt_String(data);
557  setnum = data[4];
558  plen = GetInt_String(data + 5);
559  if (len < 9 || (len - 9) != plen) {
560  LOG(LOG_WARNING, "common::Image2Cmd", "Lengths don't compare (%d,%d)",
561  (len - 9), plen);
562  return;
563  }
564  display_newpng(pnum, data + 9, plen, setnum);
565 }
566 
570 static void cache_newpng(int face, guint8 *buf, int buflen, int setnum,
571  Cache_Entry **ce) {
572  char filename[MAX_BUF], basename[MAX_BUF];
573  FILE *tmpfile;
574  guint32 i, csum;
575 
576  if (facetoname[face] == NULL) {
577  LOG(LOG_WARNING, "common::display_newpng",
578  "Caching images, but name for %ld not set", face);
579  /* Return to avoid null dereference. */
580  return;
581  }
582  /* Make necessary leading directories */
583  snprintf(filename, sizeof(filename), "%s/image-cache", cache_dir);
584  if (g_access(filename, R_OK | W_OK | X_OK) == -1) {
585  g_mkdir(filename, 0755);
586  }
587 
588  snprintf(filename, sizeof(filename), "%s/image-cache/%c%c",
589  cache_dir, facetoname[face][0], facetoname[face][1]);
590  if (access(filename, R_OK | W_OK | X_OK) == -1) {
591  g_mkdir(filename, 0755);
592  }
593 
594  /* If setnum is valid, and we have faceset information for it,
595  * put that prefix in. This will make it easier later on to
596  * allow the client to switch image sets on the fly, as it can
597  * determine what set the image belongs to.
598  * We also append the number to it - there could be several versions
599  * of 'face.base.111.x' if different servers have different image
600  * values.
601  */
602  if (setnum >= 0 && setnum < MAX_FACE_SETS &&
603  face_info.facesets[setnum].prefix) {
604  snprintf(basename, sizeof(basename), "%s.%s", facetoname[face],
605  face_info.facesets[setnum].prefix);
606  } else {
607  strcpy(basename, facetoname[face]);
608  }
609 
610  /* Decrease it by one since it will immediately get increased
611  * in the loop below.
612  */
613  setnum--;
614  do {
615  setnum++;
616  snprintf(filename, sizeof(filename), "%s/image-cache/%c%c/%s.%d",
617  cache_dir, facetoname[face][0], facetoname[face][1], basename, setnum);
618  } while (g_access(filename, F_OK) == -0);
619 
620 #ifdef WIN32
621  if ((tmpfile = fopen(filename, "wb")) == NULL)
622 #else
623  if ((tmpfile = fopen(filename, "w")) == NULL)
624 #endif
625  {
626  LOG(LOG_WARNING, "common::display_newpng", "Can not open %s for writing",
627  filename);
628  } else {
629  /* found a file we can write to */
630 
631  fwrite(buf, buflen, 1, tmpfile);
632  fclose(tmpfile);
633  csum = 0;
634  for (i = 0; (int)i < buflen; i++) {
635  ROTATE_RIGHT(csum);
636  csum += buf[i];
637  csum &= 0xffffffff;
638  }
639  snprintf(filename, sizeof(filename), "%c%c/%s.%d", facetoname[face][0],
640  facetoname[face][1],
641  basename, setnum);
642  *ce = image_add_hash(facetoname[face], filename, csum, 0);
643 
644  /* It may very well be more efficient to try to store these up
645  * and then write them as a bunch instead of constantly opening the
646  * file for appending. OTOH, hopefully people will be using the
647  * built image archives, so only a few faces actually need to get
648  * downloaded.
649  */
650  snprintf(filename, sizeof(filename), "%s/image-cache/bmaps.client", cache_dir);
651  if ((tmpfile = fopen(filename, "a")) == NULL) {
652  LOG(LOG_WARNING, "common::display_newpng", "Can not open %s for appending",
653  filename);
654  } else {
655  fprintf(tmpfile, "%s %u %c%c/%s.%d\n",
656  facetoname[face], csum, facetoname[face][0],
657  facetoname[face][1], basename, setnum);
658  fclose(tmpfile);
659  }
660  }
661 }
662 
663 
669 void display_newpng(int face, guint8 *buf, int buflen, int setnum) {
670  guint8 *pngtmp;
671  guint32 width, height;
672  Cache_Entry *ce = NULL;
673 
674  if (use_config[CONFIG_CACHE]) {
675  cache_newpng(face, buf, buflen, setnum, &ce);
676  }
677 
678  pngtmp = png_to_data(buf, buflen, &width, &height);
679  if (!pngtmp) {
680  LOG(LOG_ERROR, "display_newpng", "error in PNG data; discarding");
681  return;
682  }
683 
684  if (create_and_rescale_image_from_data(ce, face, pngtmp, width, height)) {
685  LOG(LOG_WARNING, "common::display_newpng",
686  "create_and_rescale_image_from_data failed for face %ld", face);
687  }
688 
689  if (use_config[CONFIG_CACHE]) {
690  free(facetoname[face]);
691  facetoname[face] = NULL;
692  }
693  free(pngtmp);
694 }
695 
706 void get_image_info(guint8 *data, int len) {
707  char *cp, *lp, *cps[7], buf[MAX_BUF];
708  int onset = 0, badline = 0, i;
709 
711 
712  lp = (char *)data;
713  cp = strchr(lp, '\n');
714  if (!cp || (cp - lp) > len) {
715  return;
716  }
717  face_info.num_images = atoi(lp);
718 
719  lp = cp + 1;
720  cp = strchr(lp, '\n');
721  if (!cp || (cp - lp) > len) {
722  return;
723  }
724  face_info.bmaps_checksum = strtoul(lp, NULL,
725  10); /* need unsigned, so no atoi */
726 
727  lp = cp + 1;
728  cp = strchr(lp, '\n');
729  while (cp && (cp - lp) <= len) {
730  *cp++ = '\0';
731 
732  /* The code below is pretty much the same as the code from the server
733  * which loads the original faceset file.
734  */
735  if (!(cps[0] = strtok(lp, ":"))) {
736  badline = 1;
737  }
738  for (i = 1; i < 7; i++) {
739  if (!(cps[i] = strtok(NULL, ":"))) {
740  badline = 1;
741  }
742  }
743  if (badline) {
744  LOG(LOG_WARNING, "common::get_image_info", "bad data, ignoring line:/%s/", lp);
745  } else {
746  onset = atoi(cps[0]);
747  if (onset >= MAX_FACE_SETS) {
748  LOG(LOG_WARNING, "common::get_image_info", "setnum is too high: %d > %d",
749  onset, MAX_FACE_SETS);
750  }
751  face_info.facesets[onset].prefix = g_strdup(cps[1]);
752  face_info.facesets[onset].fullname = g_strdup(cps[2]);
753  face_info.facesets[onset].fallback = atoi(cps[3]);
754  face_info.facesets[onset].size = g_strdup(cps[4]);
755  face_info.facesets[onset].extension = g_strdup(cps[5]);
756  face_info.facesets[onset].comment = g_strdup(cps[6]);
757  }
758  lp = cp;
759  cp = strchr(lp, '\n');
760  }
761  face_info.have_faceset_info = 1;
762  /* if the user has requested a specific face set and that set
763  * is not numeric, try to find a matching set and send the
764  * relevent setup command.
765  */
766  if (face_info.want_faceset && atoi(face_info.want_faceset) == 0) {
767  for (onset = 0; onset < MAX_FACE_SETS; onset++) {
768  if (face_info.facesets[onset].prefix &&
769  !g_ascii_strcasecmp(face_info.facesets[onset].prefix, face_info.want_faceset)) {
770  break;
771  }
772  if (face_info.facesets[onset].fullname &&
773  !g_ascii_strcasecmp(face_info.facesets[onset].fullname, face_info.want_faceset)) {
774  break;
775  }
776  }
777  if (onset < MAX_FACE_SETS) { /* We found a match */
778  face_info.faceset = onset;
779  cs_print_string(csocket.fd, "setup faceset %d", onset);
780  } else {
781  snprintf(buf, sizeof(buf), "Unable to find match for faceset %s on the server",
782  face_info.want_faceset);
784  }
785  }
786 
787 }
788 
802 void get_image_sums(char *data, int len) {
803  int stop, imagenum, slen, faceset;
804  guint32 checksum;
805  char *cp, *lp;
806 
807  cp = strchr((char *)data, ' ');
808  if (!cp || (cp - data) > len) {
809  return;
810  }
811 
812  while (isspace(*cp)) {
813  cp++;
814  }
815  lp = cp;
816  cp = strchr(lp, ' ');
817  if (!cp || (cp - data) > len) {
818  return;
819  }
820  stop = atoi(lp);
821 
822  replyinfo_last_face = stop;
823 
824  /* Can't use isspace here, because it matches with tab, ascii code
825  * 9 - this results in advancing too many spaces because
826  * starting at image 2304, the MSB of the image number will be
827  * 9. Using a check against space will work until we get up to
828  * 8192 images.
829  */
830  while (*cp == ' ') {
831  cp++;
832  }
833  while ((cp - data) < len) {
834  imagenum = GetShort_String((guint8 *)cp);
835  cp += 2;
836  checksum = GetInt_String((guint8 *)cp);
837  cp += 4;
838  faceset = *cp;
839  cp++;
840  slen = *cp;
841  cp++;
842  /* Note that as is, this can break horribly if the client is missing a large number
843  * of images - that is because it will request a whole bunch which will overflow
844  * the servers output buffer, causing it to close the connection.
845  * What probably should be done is for the client to just request this checksum
846  * information in small batches so that even if the client has no local
847  * images, requesting the entire batch won't overflow the sockets buffer - this
848  * probably amounts to about 100 images at a time
849  */
850  finish_face_cmd(imagenum, checksum, 1, (char *)cp, faceset);
851  if (imagenum > stop) {
852  LOG(LOG_WARNING, "common::get_image_sums",
853  "Received an image beyond our range? %d > %d", imagenum, stop);
854  }
855  cp += slen;
856  }
857 }
858 
char * comment
Definition: client.h:406
static int load_image(char *filename, guint8 *data, int *len, guint32 *csum)
Definition: image.c:55
guint32 width
Definition: image.c:42
GSocketConnection * fd
Definition: client.h:120
gint16 use_config[CONFIG_NUMS]
Definition: init.c:40
static void cache_newpng(int face, guint8 *buf, int buflen, int setnum, Cache_Entry **ce)
Definition: image.c:570
int replyinfo_last_face
Definition: client.c:58
guint8 fallback
Definition: client.h:401
char facecachedir[MAX_BUF]
Definition: image.c:407
guint8 have_faceset_info
Definition: client.h:425
short GetShort_String(const unsigned char *data)
Definition: newsocket.c:172
Warning that something might not work.
Definition: client.h:443
Definition: image.c:37
#define ROTATE_RIGHT(c)
Definition: image.c:33
ClientSocket csocket
Definition: client.c:69
struct Image_Cache image_cache[IMAGE_HASH]
FaceSets facesets[MAX_FACE_SETS]
Definition: client.h:428
#define MSG_TYPE_CLIENT
Definition: newclient.h:395
#define MAXPIXMAPNUM
Definition: client.h:499
struct Cache_Entry * cache_entry
Definition: image.c:179
const char * cache_dir
Definition: client.c:53
#define IMAGE_HASH
Definition: image.c:167
guint32 bmaps_checksum
Definition: client.h:417
char * prefix
Definition: client.h:402
void * image_data
Definition: client.h:512
char * filename
Definition: client.h:509
static Cache_Entry * image_add_hash(char *imagename, char *filename, guint32 checksum, guint32 ispublic)
Definition: image.c:296
guint32 ispublic
Definition: client.h:511
int create_and_rescale_image_from_data(Cache_Entry *ce, int pixmap_num, guint8 *rgba_data, int width, int height)
Definition: image.c:261
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:109
char * size
Definition: client.h:404
#define NDI_RED
Definition: newclient.h:224
#define RI_IMAGE_INFO
Definition: client.h:527
void display_newpng(int face, guint8 *buf, int buflen, int setnum)
Definition: image.c:669
void finish_face_cmd(int pnum, guint32 checksum, int has_sum, char *face, int faceset)
Definition: image.c:429
#define MSG_TYPE_CLIENT_NOTICE
Definition: newclient.h:664
void get_image_info(guint8 *data, int len)
Definition: image.c:706
guint32 checksum
Definition: client.h:510
struct Cache_Entry * next
Definition: client.h:513
struct FD_Cache fd_cache[MAX_FACE_SETS]
guint32 height
Definition: image.c:42
char name[MAX_BUF]
Definition: image.c:38
void reset_image_cache_data(void)
Definition: image.c:509
#define MAX_BUF
Definition: client.h:40
void get_image_sums(char *data, int len)
Definition: image.c:802
#define CONFIG_CACHE
Definition: client.h:189
guint32 checksum
Definition: image.c:40
static void image_remove_hash(char *imagename, Cache_Entry *ce)
Definition: image.c:237
#define MAX_FACE_SETS
Definition: client.h:383
gint16 want_config[CONFIG_NUMS]
Definition: init.c:40
guint8 * png_to_data(guint8 *data, int len, guint32 *width, guint32 *height)
Definition: png.c:49
void Face2Cmd(guint8 *data, int len)
Definition: image.c:526
char * extension
Definition: client.h:405
int replyinfo_status
Definition: client.c:57
void Image2Cmd(guint8 *data, int len)
Definition: image.c:552
Warning that something definitely didn't work.
Definition: client.h:444
static void image_process_line(char *line, guint32 ispublic)
Definition: image.c:340
void draw_ext_info(int orig_color, int type, int subtype, const char *message)
Definition: info.c:932
Definition: client.h:508
static gint32 image_find_hash(char *str)
Definition: image.c:208
char * fullname
Definition: client.h:403
static guint32 image_hash_name(char *str, int tablesize)
Definition: image.c:188
char * image_name
Definition: image.c:178
void requestface(int pnum, char *facename)
Definition: image.c:412
void init_common_cache_data(void)
Definition: image.c:359
int cs_print_string(GSocketConnection *fd, const char *str,...)
Definition: newsocket.c:245
char * name
Definition: image.c:39
Face_Information face_info
Definition: image.c:169
int GetInt_String(const unsigned char *data)
Definition: newsocket.c:142
static char * facetoname[MAXPIXMAPNUM]
Definition: image.c:174
static Cache_Entry * image_find_cache_entry(char *imagename, guint32 checksum, int has_sum)
Definition: image.c:272
int fd
Definition: image.c:39
int associate_cache_entry(Cache_Entry *ce, int pixnum)
Definition: image.c:416
#define MSG_TYPE_CLIENT_CONFIG
Definition: newclient.h:659