ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/image.C
Revision: 1.18
Committed: Thu Feb 15 15:43:36 2007 UTC (17 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.17: +1 -1 lines
Log Message:
- useless ยต-opts
- use maximum norm in get_rangevector (a bit, should use more)

File Contents

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