ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/image.C
Revision: 1.13
Committed: Fri Dec 15 19:59:20 2006 UTC (17 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.12: +5 -11 lines
Log Message:
the rename for sanity campaign hits
you died
- renamed stuff
- partially updated copyrights
- some cleanups

File Contents

# User Rev Content
1 elmex 1.1 /*
2     CrossFire, A Multiplayer game for X-windows
3    
4     Copyright (C) 2001 Mark Wedel
5     Copyright (C) 1992 Frank Tore Johansen
6    
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 root 1.4 The author can be reached via e-mail to <crossfire@schmorp.de>
22 elmex 1.1 */
23    
24     /** \file
25     * Image related communication
26     *
27     * \date 2003-12-02
28     *
29     * This file deals with the image related communication to the
30     * client. I've located all the functions in this file - this
31     * localizes it more, and means that we don't need to declare
32     * things like all the structures as globals.
33     */
34    
35     #include <global.h>
36     #include <sproto.h>
37    
38     #define MAX_FACE_SETS 20 /**< Maximum number of image sets the program will handle */
39    
40     /** Information about one image */
41 root 1.3 typedef struct FaceInfo
42     {
43    
44     uint8 *data; /**< image data */
45     uint16 datalen; /**< length of the xpm data */
46     uint32 checksum; /**< Checksum of face data */
47 elmex 1.1 } FaceInfo;
48    
49     /** Information about one face set */
50 root 1.3 typedef struct
51     {
52    
53     char *prefix; /**< */
54     char *fullname;
55    
56     uint8 fallback; /**< faceset to use when an image is not found in this faceset */
57     char *size;
58     char *extension;
59     char *comment;
60    
61     FaceInfo *faces; /**< images in this faceset */
62 elmex 1.1 } FaceSets;
63    
64     static FaceSets facesets[MAX_FACE_SETS]; /**< All facesets */
65    
66     /**
67     * Checks specified faceset is valid
68     * \param fsn faceset number
69     */
70 root 1.3 int
71     is_valid_faceset (int fsn)
72 elmex 1.1 {
73 root 1.3 if (fsn >= 0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix)
74     return TRUE;
75     return FALSE;
76 elmex 1.1 }
77    
78     /**
79     * Frees all faceset information
80     */
81 root 1.3 void
82     free_socket_images (void)
83 elmex 1.1 {
84 root 1.3 int num, q;
85 elmex 1.1
86 root 1.3 for (num = 0; num < MAX_FACE_SETS; num++)
87     {
88     if (facesets[num].prefix)
89     {
90     for (q = 0; q < nrofpixmaps; q++)
91     if (facesets[num].faces[q].data)
92     free (facesets[num].faces[q].data);
93     free (facesets[num].prefix);
94     free (facesets[num].fullname);
95     free (facesets[num].size);
96     free (facesets[num].extension);
97     free (facesets[num].comment);
98     free (facesets[num].faces);
99 root 1.2 }
100 elmex 1.1 }
101     }
102    
103     /**
104     * This returns the set we will actually use when sending
105     * a face. This is used because the image files may be sparse.
106     * This function is recursive. imageno is the face number we are
107     * trying to send
108     *
109     * If face is not found in specified faceset, tries with 'fallback' faceset.
110     *
111     * \param faceset faceset to check
112     * \param imageno image number
113     *
114     */
115 root 1.3 static int
116     get_face_fallback (int faceset, int imageno)
117 elmex 1.1 {
118 root 1.3 /* faceset 0 is supposed to have every image, so just return. Doing
119     * so also prevents infinite loops in the case if it not having
120     * the face, but in that case, we are likely to crash when we try
121     * to access the data, but that is probably preferable to an infinite
122     * loop.
123     */
124     if (faceset == 0)
125     return 0;
126    
127     if (!facesets[faceset].prefix)
128     {
129     LOG (llevError, "get_face_fallback called with unused set (%d)?\n", faceset);
130     return 0; /* use default set */
131     }
132     if (facesets[faceset].faces[imageno].data)
133     return faceset;
134     return get_face_fallback (facesets[faceset].fallback, imageno);
135 elmex 1.1 }
136    
137     /**
138     * Checks fallback are correctly defined.
139     * This is a simple recursive function that makes sure the fallbacks
140     * are all proper (eg, the fall back to defined sets, and also
141     * eventually fall back to 0). At the top level, togo is set to MAX_FACE_SETS,
142     * if togo gets to zero, it means we have a loop.
143     * This is only run when we first load the facesets.
144     */
145 root 1.3 static void
146     check_faceset_fallback (int faceset, int togo)
147 elmex 1.1 {
148 root 1.3 int fallback = facesets[faceset].fallback;
149 elmex 1.1
150 root 1.3 /* proper case - falls back to base set */
151     if (fallback == 0)
152     return;
153    
154     if (!facesets[fallback].prefix)
155     {
156     LOG (llevError, "Face set %d falls to non set faceset %d\n", faceset, fallback);
157     abort ();
158     }
159     togo--;
160     if (togo == 0)
161     {
162     LOG (llevError, "Infinite loop found in facesets. aborting.\n");
163     abort ();
164 elmex 1.1 }
165 root 1.3 check_faceset_fallback (fallback, togo);
166 elmex 1.1 }
167    
168     #define MAX_IMAGE_SIZE 10000
169    
170     /**
171     * Loads all the image types into memory.
172     *
173     * This way, we can easily send them to the client. We should really do something
174     * better than abort on any errors - on the other hand, these are all fatal
175     * to the server (can't work around them), but the abort just seems a bit
176     * messy (exit would probably be better.)
177     *
178     * Couple of notes: We assume that the faces are in a continous block.
179     * This works fine for now, but this could perhaps change in the future
180     *
181     * Function largely rewritten May 2000 to be more general purpose.
182     * The server itself does not care what the image data is - to the server,
183     * it is just data it needs to allocate. As such, the code is written
184     * to do such.
185     */
186    
187 root 1.3 void
188     read_client_images (void)
189 elmex 1.1 {
190 root 1.3 char filename[400];
191     char buf[HUGE_BUF];
192     char *cp, *cps[7];
193     FILE *infile;
194     int num, len, compressed, fileno, i, badline;
195    
196     memset (facesets, 0, sizeof (facesets));
197     sprintf (filename, "%s/image_info", settings.datadir);
198     if ((infile = open_and_uncompress (filename, 0, &compressed)) == NULL)
199     {
200     LOG (llevError, "Unable to open %s\n", filename);
201     abort ();
202     }
203     while (fgets (buf, HUGE_BUF - 1, infile) != NULL)
204     {
205     badline = 0;
206    
207     if (buf[0] == '#')
208     continue;
209     if (!(cps[0] = strtok (buf, ":")))
210     badline = 1;
211     for (i = 1; i < 7; i++)
212     {
213     if (!(cps[i] = strtok (NULL, ":")))
214     badline = 1;
215     }
216     if (badline)
217     {
218     LOG (llevError, "Bad line in image_info file, ignoring line:\n %s", buf);
219 root 1.2 }
220 root 1.3 else
221     {
222     len = atoi (cps[0]);
223     if (len >= MAX_FACE_SETS)
224     {
225     LOG (llevError, "To high a setnum in image_info file: %d > %d\n", len, MAX_FACE_SETS);
226     abort ();
227 root 1.2 }
228 root 1.12 facesets[len].prefix = strdup (cps[1]);
229     facesets[len].fullname = strdup (cps[2]);
230 root 1.3 facesets[len].fallback = atoi (cps[3]);
231 root 1.12 facesets[len].size = strdup (cps[4]);
232     facesets[len].extension = strdup (cps[5]);
233     facesets[len].comment = strdup (cps[6]);
234 root 1.2 }
235 elmex 1.1 }
236 root 1.3 close_and_delete (infile, compressed);
237     for (i = 0; i < MAX_FACE_SETS; i++)
238     {
239     if (facesets[i].prefix)
240     check_faceset_fallback (i, MAX_FACE_SETS);
241     }
242     /* Loaded the faceset information - now need to load up the
243     * actual faces.
244     */
245    
246     for (fileno = 0; fileno < MAX_FACE_SETS; fileno++)
247     {
248     /* if prefix is not set, this is not used */
249     if (!facesets[fileno].prefix)
250     continue;
251     facesets[fileno].faces = (FaceInfo *) calloc (nrofpixmaps, sizeof (FaceInfo));
252    
253     sprintf (filename, "%s/crossfire.%d", settings.datadir, fileno);
254     LOG (llevDebug, "Loading image file %s\n", filename);
255    
256     if ((infile = open_and_uncompress (filename, 0, &compressed)) == NULL)
257     {
258     LOG (llevError, "Unable to open %s\n", filename);
259     abort ();
260 root 1.2 }
261 root 1.3 while (fgets (buf, HUGE_BUF - 1, infile) != NULL)
262     {
263     if (strncmp (buf, "IMAGE ", 6) != 0)
264     {
265     LOG (llevError, "read_client_images:Bad image line - not IMAGE, instead\n%s", buf);
266     abort ();
267 root 1.2 }
268 root 1.3 num = atoi (buf + 6);
269     if (num < 0 || num >= nrofpixmaps)
270     {
271     LOG (llevError, "read_client_images: Image num %d not in 0..%d\n%s", num, nrofpixmaps, buf);
272     abort ();
273 root 1.2 }
274 root 1.3 /* Skip accross the number data */
275     for (cp = buf + 6; *cp != ' '; cp++);
276     len = atoi (cp);
277     if (len == 0 || len > MAX_IMAGE_SIZE)
278     {
279     LOG (llevError, "read_client_images: length not valid: %d > %d \n%s", len, MAX_IMAGE_SIZE, buf);
280     abort ();
281 root 1.2 }
282 root 1.5 /* We don't actualy care about the name of the image that
283 root 1.3 * is embedded in the image file, so just ignore it.
284     */
285     facesets[fileno].faces[num].datalen = len;
286     facesets[fileno].faces[num].data = (uint8 *) malloc (len);
287     if ((i = fread (facesets[fileno].faces[num].data, len, 1, infile)) != 1)
288     {
289     LOG (llevError, "read_client_images: Did not read desired amount of data, wanted %d, got %d\n%s", len, i, buf);
290     abort ();
291 root 1.2 }
292 root 1.3 facesets[fileno].faces[num].checksum = 0;
293     for (i = 0; i < len; i++)
294     {
295     ROTATE_RIGHT (facesets[fileno].faces[num].checksum);
296     facesets[fileno].faces[num].checksum += facesets[fileno].faces[num].data[i];
297     facesets[fileno].faces[num].checksum &= 0xffffffff;
298 root 1.2 }
299     }
300 root 1.3 close_and_delete (infile, compressed);
301     } /* For fileno < MAX_FACE_SETS */
302 elmex 1.1 }
303    
304     /**
305     * Client tells us what type of faces it wants. Also sets
306     * the caching attribute.
307     *
308     */
309    
310 root 1.3 void
311 root 1.13 SetFaceMode (char *buf, int len, client *ns)
312 elmex 1.1 {
313 root 1.3 int mask = (atoi (buf) & CF_FACE_CACHE), mode = (atoi (buf) & ~CF_FACE_CACHE);
314 elmex 1.1
315 root 1.3 if (mode == CF_FACE_NONE)
316 root 1.7 ns->facecache = 1;
317 root 1.3 else if (mode != CF_FACE_PNG)
318     {
319 root 1.8 packet sl;
320 root 1.7 sl.printf ("drawinfo %d %s", NDI_RED, "Warning - send unsupported face mode. Will use Png");
321     ns->send_packet (sl);
322 elmex 1.1 }
323 root 1.7
324 root 1.3 if (mask)
325 root 1.7 ns->facecache = 1;
326 elmex 1.1 }
327    
328     /**
329     * Client has requested pixmap that it somehow missed getting.
330     * This will be called often if the client is
331     * caching images.
332     */
333    
334 root 1.3 void
335 root 1.13 SendFaceCmd (char *buff, int len, client * ns)
336 elmex 1.1 {
337 root 1.3 long tmpnum = atoi (buff);
338     short facenum = tmpnum & 0xffff;
339 elmex 1.1
340 root 1.3 if (facenum != 0)
341     esrv_send_face (ns, facenum, 1);
342 elmex 1.1 }
343    
344     /**
345     * Sends a face to a client if they are in pixmap mode
346     * nothing gets sent in bitmap mode.
347     * If nocache is true (nonzero), ignore the cache setting from the client -
348     * this is needed for the askface, in which we really do want to send the
349     * face (and askface is the only place that should be setting it). Otherwise,
350     * we look at the facecache, and if set, send the image name.
351     */
352    
353 root 1.3 void
354 root 1.13 esrv_send_face (client *ns, short face_num, int nocache)
355 elmex 1.1 {
356 root 1.3 char fallback;
357 elmex 1.1
358 root 1.3 if (face_num <= 0 || face_num >= nrofpixmaps)
359     {
360     LOG (llevError, "esrv_send_face (%d) out of bounds??\n", face_num);
361     return;
362     }
363    
364 root 1.8 packet sl;
365 root 1.3 fallback = get_face_fallback (ns->faceset, face_num);
366    
367     if (facesets[fallback].faces[face_num].data == NULL)
368     {
369     LOG (llevError, "esrv_send_face: faces[%d].data == NULL\n", face_num);
370     return;
371     }
372    
373     if (ns->facecache && !nocache)
374     {
375 root 1.6 sl << (ns->image2 ? "face2 " : "face1 ")
376     << uint16 (face_num);
377    
378 root 1.3 if (ns->image2)
379 root 1.6 sl << uint8 (fallback);
380    
381     sl << uint32 (facesets[fallback].faces[face_num].checksum)
382     << new_faces[face_num].name;
383 root 1.3
384 root 1.11 ns->send_packet (sl);
385 root 1.3 }
386     else
387     {
388 root 1.6 sl << (ns->image2 ? "image2 " : "image ")
389     << uint32 (face_num);
390    
391 root 1.3 if (ns->image2)
392 root 1.6 sl << uint8 (fallback);
393    
394     sl << uint32 (facesets[fallback].faces[face_num].datalen)
395     << data (facesets[fallback].faces[face_num].data, facesets[fallback].faces[face_num].datalen);
396    
397 root 1.11 ns->send_packet (sl);
398 elmex 1.1 }
399 root 1.6
400 root 1.3 ns->faces_sent[face_num] |= NS_FACESENT_FACE;
401 elmex 1.1 }
402    
403     /**
404     * Sends the number of images, checksum of the face file,
405     * and the image_info file information. See the doc/Developers/protocol
406     * if you want further detail.
407     */
408    
409 root 1.3 void
410 root 1.13 send_image_info (client * ns, char *params)
411 elmex 1.1 {
412 root 1.8 packet sl;
413 elmex 1.1
414 root 1.6 sl.printf ("replyinfo image_info\n%d\n%d\n", nrofpixmaps - 1, bmaps_checksum);
415    
416     for (int i = 0; i < MAX_FACE_SETS; i++)
417     if (facesets[i].prefix)
418     sl.printf ("%d:%s:%s:%d:%s:%s:%s",
419     i, facesets[i].prefix, facesets[i].fullname, facesets[i].fallback,
420     facesets[i].size, facesets[i].extension, facesets[i].comment);
421 elmex 1.1
422 root 1.11 ns->send_packet (sl);
423 elmex 1.1 }
424    
425     /**
426     * Sends requested face information.
427     * \param ns socket to send to
428     * \param params contains first and last index of face
429     *
430     * For each image in [start..stop] sends
431     * - checksum
432     * - name
433     */
434 root 1.3 void
435 root 1.13 send_image_sums (client * ns, char *params)
436 elmex 1.1 {
437 root 1.3 int start, stop;
438     char *cp, buf[MAX_BUF];
439    
440 root 1.8 packet sl;
441 root 1.3
442     start = atoi (params);
443     for (cp = params; *cp != '\0'; cp++)
444     if (*cp == ' ')
445     break;
446    
447     stop = atoi (cp);
448     if (stop < start || *cp == '\0' || (stop - start) > 1000 || stop >= nrofpixmaps)
449     {
450 root 1.7 sl.printf ("replyinfo image_sums %d %d", start, stop);
451     ns->send_packet (sl);
452     sl.reset ();
453 root 1.3 return;
454     }
455    
456 root 1.6 sl.printf ("replyinfo image_sums %d %d ", start, stop);
457 root 1.3
458 root 1.6 for (int i = start; i <= stop; i++)
459 root 1.3 {
460     ns->faces_sent[i] |= NS_FACESENT_FACE;
461    
462 root 1.6 int qq = get_face_fallback (ns->faceset, i);
463    
464     sl << uint16 (i)
465     << uint32 (facesets[qq].faces[i].checksum)
466     << uint8 (qq)
467     << data8 (&new_faces[i].name, new_faces[i].name.length () + 1);
468 root 1.3 }
469 root 1.6
470 root 1.3 /* It would make more sense to catch this pre-emptively in the code above.
471     * however, if this really happens, we probably just want to cut down the
472     * size to less than 1000, since that is what we claim the protocol would
473     * support.
474     */
475 root 1.9 if (sl.length () >= MAXSOCKBUF)
476 root 1.3 {
477 root 1.9 LOG (llevError, "send_image_send: buffer overrun, %d > %d\n", sl.length (), MAXSOCKBUF);
478 root 1.3 abort ();
479 elmex 1.1 }
480 root 1.6
481 root 1.11 ns->send_packet (sl);
482 elmex 1.1 }
483 root 1.6