/* * static char *rcsid_init_c = * "$Id: image.c,v 1.1.1.1 2006/02/03 07:14:43 root Exp $"; */ /* CrossFire, A Multiplayer game for X-windows Copyright (C) 2001 Mark Wedel Copyright (C) 1992 Frank Tore Johansen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author can be reached via e-mail to crossfire-devel@real-time.com */ /** \file * Image related communication * * \date 2003-12-02 * * This file deals with the image related communication to the * client. I've located all the functions in this file - this * localizes it more, and means that we don't need to declare * things like all the structures as globals. */ #include #include #include #include #include #define MAX_FACE_SETS 20 /**< Maximum number of image sets the program will handle */ /** Information about one image */ typedef struct FaceInfo { uint8 *data; /**< image data */ uint16 datalen; /**< length of the xpm data */ uint32 checksum; /**< Checksum of face data */ } FaceInfo; /** Information about one face set */ typedef struct { char *prefix; /**< */ char *fullname; uint8 fallback; /**< faceset to use when an image is not found in this faceset */ char *size; char *extension; char *comment; FaceInfo *faces; /**< images in this faceset */ } FaceSets; static FaceSets facesets[MAX_FACE_SETS]; /**< All facesets */ /** * Checks specified faceset is valid * \param fsn faceset number */ int is_valid_faceset(int fsn) { if (fsn >=0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix) return TRUE; return FALSE; } /** * Frees all faceset information */ void free_socket_images(void) { int num,q; for(num=0;num=MAX_FACE_SETS) { LOG(llevError,"To high a setnum in image_info file: %d > %d\n", len, MAX_FACE_SETS); abort(); } facesets[len].prefix = strdup_local(cps[1]); facesets[len].fullname = strdup_local(cps[2]); facesets[len].fallback = atoi(cps[3]); facesets[len].size = strdup_local(cps[4]); facesets[len].extension = strdup_local(cps[5]); facesets[len].comment = strdup_local(cps[6]); } } close_and_delete(infile,compressed); for (i=0; i=nrofpixmaps) { LOG(llevError,"read_client_images: Image num %d not in 0..%d\n%s", num,nrofpixmaps,buf); abort(); } /* Skip accross the number data */ for (cp=buf+6; *cp!=' '; cp++) ; len = atoi(cp); if (len==0 || len>MAX_IMAGE_SIZE) { LOG(llevError,"read_client_images: length not valid: %d > %d \n%s", len,MAX_IMAGE_SIZE,buf); abort(); } /* We don't actualy care about the name if the image that * is embedded in the image file, so just ignore it. */ facesets[fileno].faces[num].datalen = len; facesets[fileno].faces[num].data = malloc(len); if ((i=fread(facesets[fileno].faces[num].data, len, 1, infile))!=1) { LOG(llevError,"read_client_images: Did not read desired amount of data, wanted %d, got %d\n%s", len, i, buf); abort(); } facesets[fileno].faces[num].checksum=0; for (i=0; ifacecache=1; } else if (mode!=CF_FACE_PNG) { sprintf(tmp,"drawinfo %d %s", NDI_RED,"Warning - send unsupported face mode. Will use Png"); Write_String_To_Socket(ns, tmp, strlen(tmp)); #ifdef ESRV_DEBUG LOG(llevDebug,"SetFaceMode: Invalid mode from client: %d\n", mode); #endif } if (mask) { ns->facecache=1; } } /** * Client has requested pixmap that it somehow missed getting. * This will be called often if the client is * caching images. */ void SendFaceCmd(char *buff, int len, NewSocket *ns) { long tmpnum = atoi(buff); short facenum=tmpnum & 0xffff; if(facenum!=0) esrv_send_face(ns, facenum,1); } /** * Sends a face to a client if they are in pixmap mode * nothing gets sent in bitmap mode. * If nocache is true (nonzero), ignore the cache setting from the client - * this is needed for the askface, in which we really do want to send the * face (and askface is the only place that should be setting it). Otherwise, * we look at the facecache, and if set, send the image name. */ void esrv_send_face(NewSocket *ns,short face_num, int nocache) { SockList sl; char fallback; if (face_num <= 0 || face_num >= nrofpixmaps) { LOG(llevError,"esrv_send_face (%d) out of bounds??\n",face_num); return; } sl.buf = malloc(MAXSOCKBUF); fallback = get_face_fallback(ns->faceset, face_num); if (facesets[fallback].faces[face_num].data == NULL) { LOG(llevError,"esrv_send_face: faces[%d].data == NULL\n",face_num); return; } if (ns->facecache && !nocache) { if (ns->image2) strcpy((char*)sl.buf, "face2 "); else if (ns->sc_version >= 1026) strcpy((char*)sl.buf, "face1 "); else strcpy((char*)sl.buf, "face "); sl.len=strlen(sl.buf); SockList_AddShort(&sl, face_num); if (ns->image2) SockList_AddChar(&sl, fallback); if (ns->sc_version >= 1026) SockList_AddInt(&sl, facesets[fallback].faces[face_num].checksum); strcpy((char*)sl.buf + sl.len, new_faces[face_num].name); sl.len += strlen(new_faces[face_num].name); Send_With_Handling(ns, &sl); } else { if (ns->image2) strcpy((char*)sl.buf, "image2 "); else strcpy((char*)sl.buf, "image "); sl.len=strlen((char*)sl.buf); SockList_AddInt(&sl, face_num); if (ns->image2) SockList_AddChar(&sl, fallback); SockList_AddInt(&sl, facesets[fallback].faces[face_num].datalen); memcpy(sl.buf+sl.len, facesets[fallback].faces[face_num].data, facesets[fallback].faces[face_num].datalen); sl.len += facesets[fallback].faces[face_num].datalen; Send_With_Handling(ns, &sl); } ns->faces_sent[face_num] |= NS_FACESENT_FACE; free(sl.buf); } /** * Sends the number of images, checksum of the face file, * and the image_info file information. See the doc/Developers/protocol * if you want further detail. */ void send_image_info(NewSocket *ns, char *params) { SockList sl; int i; sl.buf = malloc(MAXSOCKBUF); sprintf(sl.buf,"replyinfo image_info\n%d\n%d\n", nrofpixmaps-1, bmaps_checksum); for (i=0; i1000 || stop >= nrofpixmaps) { sprintf(buf,"replyinfo image_sums %d %d", start, stop); cs_write_string(ns, buf, strlen(buf)); return; } sprintf(sl.buf,"replyinfo image_sums %d %d ", start, stop); sl.len = strlen(sl.buf); for (i=start; i<=stop; i++) { SockList_AddShort(&sl, i); ns->faces_sent[i] |= NS_FACESENT_FACE; qq = get_face_fallback(ns->faceset, i); SockList_AddInt(&sl, facesets[qq].faces[i].checksum); SockList_AddChar(&sl, qq); qq = strlen(new_faces[i].name); SockList_AddChar(&sl, ( char )( qq + 1 )); strcpy(sl.buf + sl.len, new_faces[i].name); sl.len += qq; SockList_AddChar(&sl, 0); } /* It would make more sense to catch this pre-emptively in the code above. * however, if this really happens, we probably just want to cut down the * size to less than 1000, since that is what we claim the protocol would * support. */ if (sl.len > MAXSOCKBUF) { LOG(llevError,"send_image_send: buffer overrun, %d > %d\n", sl.len, MAXSOCKBUF); abort(); } Send_With_Handling(ns, &sl); free(sl.buf); }