ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/image.C
Revision: 1.2
Committed: Tue Aug 29 08:01:38 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.1: +151 -151 lines
Log Message:
expand initial tabs to spaces

File Contents

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