void file_manager::add_nfs_client(net_socket *sock) { uchar size[2]; char filename[300],mode[20],*mp; if (sock->read(size,2)!=2) { delete sock; return ; } if (sock->read(filename,size[0])!=size[0]) { delete sock; return ; } if (sock->read(mode,size[1])!=size[1]) { delete sock; return ; } secure_filename(filename,mode); // make sure this filename isn't a security risk if (filename[0]==0) { dprintf("(denied)\n"); delete sock; return ; } mp=mode; int flags=0; #ifdef __WATCOMC__ flags|=O_BINARY; #endif while (*mp) { if (*mp=='w') flags|=O_CREAT|O_RDWR; else if (*mp=='r') flags|=O_RDONLY; mp++; } #ifdef __MAC__ int f=open(macify_name(filename),flags); #else int f=open(filename,flags,S_IRWXU | S_IRWXG | S_IRWXO); #endif FILE *fp=fopen("open.log","ab"); fprintf(fp,"open file %s, fd=%d\n",filename,f); fclose(fp); if (f<0) f=-1; // make sure this is -1 long ret=lltl(f); if (sock->write(&ret,sizeof(ret))!=sizeof(ret)) { delete sock; return ; } if (f<0) // no file, sorry delete sock; else { long cur_pos=lseek(f,0,SEEK_CUR); long size=lseek(f,0,SEEK_END); lseek(f,cur_pos,SEEK_SET); size=lltl(size); if (sock->write(&size,sizeof(size))!=sizeof(size)) { close(f); delete sock; sock=NULL; return ; } nfs_list=new nfs_client(sock,f,nfs_list); nfs_list->size=size; } }
int32_t file_manager::remote_file::unbuffered_seek(int32_t offset) // tell server to seek to a spot in a file { if (sock) { uint8_t cmd=NFCMD_SEEK; if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("seek : could not send command"); return 0; } int32_t off=lltl(offset); if (sock->write(&off,sizeof(off))!=sizeof(off)) { r_close("seek : could not send offset"); return 0; } if (sock->read(&offset,sizeof(offset))!=sizeof(offset)) { r_close("seek : could not read offset"); return 0; } return lltl(offset); } return 0; }
int file_manager::process_nfs_command(nfs_client *c) { char cmd; if (c->sock->read(&cmd, 1) != 1) return 0; switch (cmd) { case NFCMD_READ: { int32_t size; if (c->sock->read(&size, sizeof(size)) != sizeof(size)) return 0; size = lltl(size); c->size_to_read = size; return c->send_read(); } break; case NFCMD_CLOSE: { return 0; } break; case NFCMD_SEEK: { int32_t offset; if (c->sock->read(&offset, sizeof(offset)) != sizeof(offset)) return 0; offset = lltl(offset); offset = lseek(c->file_fd, offset, 0); offset = lltl(offset); if (c->sock->write(&offset, sizeof(offset)) != sizeof(offset)) return 0; return 1; } break; case NFCMD_TELL: { int32_t offset = lseek(c->file_fd, 0, SEEK_CUR); offset = lltl(offset); if (c->sock->write(&offset, sizeof(offset)) != sizeof(offset)) return 0; return 1; } break; default: { fprintf(stderr, "net driver : bad command from nfs client\n"); return 0; } } }
file_manager::remote_file::remote_file(net_socket *sock, char const *filename, char const *mode, remote_file *Next) : sock(sock) { next=Next; open_local=0; uint8_t sizes[3]={ CLIENT_NFS,strlen(filename)+1,strlen(mode)+1}; if (sock->write(sizes,3)!=3) { r_close("could not send open info"); return ; } if (sock->write(filename,sizes[1])!=sizes[1]) { r_close("could not send filename"); return ; } if (sock->write(mode,sizes[2])!=sizes[2]) { r_close("could not send mode"); return ; } int32_t remote_file_fd; if (sock->read(&remote_file_fd,sizeof(remote_file_fd))!=sizeof(remote_file_fd)) { r_close("could not read remote fd"); return ; } remote_file_fd=lltl(remote_file_fd); if (remote_file_fd<0) { r_close("remote fd is bad"); return ; } if (sock->read(&size,sizeof(size))!=sizeof(size)) { r_close("could not read remote filesize"); return ; } size=lltl(size); }
int32_t file_manager::remote_file::unbuffered_tell() // ask server where the offset of the file pointer is { if (sock) { uint8_t cmd=NFCMD_TELL; if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("tell : could not send command"); return 0; } int32_t offset; if (sock->read(&offset,sizeof(offset))!=sizeof(offset)) { r_close("tell : could not read offset"); return 0; } return lltl(offset); } return 0; }
void server::add_change_log(view *f, packet &pk, int number) { if (f->view_changed()) { uint8_t cmd=SCMD_VIEW_RESIZE; pk.write(&cmd,1); if (number) { uint16_t pn=lstl(f->player_number); pk.write((uint8_t *)&pn,2); dprintf("Server : %s resized view %d %d %d %d\n",f->name, f->suggest.cx1,f->suggest.cy1,f->suggest.cx2,f->suggest.cy2); f->resize_view(f->suggest.cx1,f->suggest.cy1,f->suggest.cx2,f->suggest.cy2); f->suggest.send_view=0; } else dprintf("sending resize to server\n"); uint32_t view_size[8]; view_size[0]=lltl(f->suggest.cx1); view_size[1]=lltl(f->suggest.cy1); view_size[2]=lltl(f->suggest.cx2); view_size[3]=lltl(f->suggest.cy2); view_size[4]=lltl(f->suggest.pan_x); view_size[5]=lltl(f->suggest.pan_y); view_size[6]=lltl(f->suggest.shift_down); view_size[7]=lltl(f->suggest.shift_right); pk.write((uint8_t *)view_size,8*4); } if (f->weapon_changed()) { uint8_t cmd=SCMD_WEAPON_CHANGE; pk.write(&cmd,1); if (number) { uint16_t pn=lstl(f->player_number); pk.write((uint8_t *)&pn,2); dprintf("Server : %s change weapon to %d\n",f->name,f->suggest.new_weapon); f->current_weapon=f->suggest.new_weapon; f->suggest.send_weapon_change=0; } else dprintf("sending resize to server\n"); uint32_t nw=lltl(f->suggest.new_weapon); pk.write((uint8_t *)&nw,4); } }
int file_manager::remote_file::unbuffered_read(void *buffer, size_t count) { if (sock && count) { uint8_t cmd = NFCMD_READ; if (sock->write(&cmd, sizeof(cmd)) != sizeof(cmd)) { r_close("read : could not send command"); return 0; } int32_t rsize = lltl(count); if (sock->write(&rsize, sizeof(rsize)) != sizeof(rsize)) { r_close("read : could not send size"); return 0; } int32_t total_read = 0; char buf[READ_PACKET_SIZE]; ushort packet_size; do { if (sock->read(&packet_size, sizeof(packet_size)) != sizeof(packet_size)) { fprintf(stderr, "could not read packet size\n"); return 0; } packet_size = lstl(packet_size); ushort size_read = sock->read(buf, packet_size); if (size_read != packet_size) { if (sock->read(buf + 2 + size_read, packet_size - size_read) != packet_size - size_read) { fprintf(stderr, "incomplete packet\n"); return 0; } } memcpy(buffer, buf, packet_size); buffer = (void *) (((char *) buffer) + packet_size); total_read += packet_size; count -= packet_size; } while (packet_size == READ_PACKET_SIZE - 2 && count); return total_read; } return 0; }
view *server::add_view(packet &pk) { uint32_t x[TOT_VIEW_VARS]; if (!pk.read((uint8_t *)x,TOT_VIEW_VARS*4)) return NULL; for (int i=0; i<TOT_VIEW_VARS; i++) x[i]=lltl(x[i]); int skip=0; for (view *f=player_list; f; f=f->next) if (f->player_number==x[0]) skip=1; if (skip) { pk.advance(total_objects*4); char nm[200]; pk.get_string(nm,100); return NULL; } else { game_object *o=current_level->number_to_object(x[24]); if (!o) { o=create(x[25],x[26],x[27]); current_level->add_object(o); } view *v=new view(o,NULL,x[0]); o->set_controller(v); v->cx1=x[1]; v->cy1=x[2]; v->cx2=x[3]; v->cy2=x[4]; v->lives=x[5]; v->pan_x=x[6]; v->pan_y=x[7]; v->no_xleft=x[8]; v->no_xright=x[9]; v->no_ytop=x[10]; v->no_ybottom=x[11]; v->last_x=x[12]; v->last_y=x[13]; v->last_left=x[14]; v->last_right=x[15]; v->last_up=x[16]; v->last_down=x[17]; v->last_b1=x[18]; v->last_b2=x[19]; v->last_b3=x[20]; v->last_hp=x[21]; v->last_ammo=x[22]; v->last_type=x[23]; v->visor_time=x[28]; v->current_weapon=x[29]; v->secrets=x[30]; v->kills=x[31]; pk.read((uint8_t *)v->weapons,total_objects*4); pk.get_string(v->name,100); return v; } }
void server::distribute_changes() { char cmd; for (view *f=player_list; f; f=f->next) { cmd=SCMD_SET_INPUT; next_out.write((uint8_t *)&cmd,1); uint16_t pn=lstl(f->player_number); next_out.write((uint8_t *)&pn,2); signed char inp[5]; inp[0]=f->x_suggestion; inp[1]=f->y_suggestion; inp[2]=f->b1_suggestion; inp[3]=f->b2_suggestion; inp[4]=f->b3_suggestion; next_out.write((uint8_t *)inp,5); } if (sync_check) { cmd=SCMD_SYNC; uint32_t x=lltl(make_sync_uint32()); next_out.write((uint8_t *)&cmd,1); next_out.write((uint8_t *)&x,4); } for (f=player_list; f; ) { view *n=f->next; if (!f->local_player() && f->connect) if (!send_pkt(f->connect,next_out)) remove_player(f); f=n; } }
int server::join_game(out_socket *os, char *name, char *server_name) { char *re="Error occurred while reading from server\n"; packet pk; if (!get_pkt(os,pk)) // read join status packet, 0 means we can't join { fputs(re,stderr); exit(0); } int32_t nfs_port; if (pk.read((uint8_t *)&nfs_port,4)!=4) { fputs(re,stderr); exit(0); } // connect_to_nfs_server(server_name,lltl(nfs_port)); pk.write((uint8_t *)name,strlen(name)+1); // send or name and see if it's ok to join in if (!send_pkt(os,pk)) { printf("Unable to write to server\n"); exit(0); } if (!get_pkt(os,pk)) // read join status packet, 0 means we can't join { fputs(re,stderr); exit(0); } uint8_t stat; if (pk.read((uint8_t *)&stat,1)!=1) { fputs(re,stderr); exit(0); } if (stat==0) { printf("Sorry, this server is refusing you (%s)\n",name); exit(0); } if (current_level) delete current_level; int32_t vs[4]={ lltl(320/2-155),lltl(200/2-95),lltl(320/2+155),lltl(200/2+70)}; pk.write((uint8_t *)vs,4*4); if (!send_pkt(os,pk)) { printf("Unable to write to server\n"); exit(0); } current_level=new level(os); if (current_level->load_failed()) { printf("Error occurred while downloading level\n"); exit(1); } if (!get_pkt(os,pk)) { printf("Unable to read views from server\n"); exit(0); } uint16_t tv; if (pk.read((uint8_t *)&tv,2)!=2) { fputs(re,stderr); exit(0); } tv=lstl(tv); view *last=NULL; for (int i=0; i<tv; i++) { if (!get_pkt(os,pk)) { fputs(re,stderr); exit(0); } view *v=add_view(pk); if (v) { printf("added view %d\n",v->player_number); if (last) last->next=v; else player_list=v; last=v; } else printf("no view created, why?\n"); } if (!get_pkt(os,pk)) { fputs(re,stderr); exit(0); } if (pk.read((uint8_t *)&rand_on,2)!=2) // read the current random seed used by the server. { fputs(re,stderr); exit(0); } rand_on=lstl(rand_on); uint16_t rtab[1024]; if (!pk.read((uint8_t *)rtab,1024*2)) { fputs(re,stderr); exit(0); } // read the rand table for (int j=0; j<1024*2; j++) if (((uint8_t *)rtab)[j]!=((uint8_t *)rtable)[j]) { printf("rtables differ on byte %d\n",j); exit(0); } if (last) { last->Drawable=1; last->connect=os; } start_running=1; is_server=0; return 1; }
void server::check_for_new_players() { if (is_server && has_net) { out_socket *nd=in->check_for_connect(); if (nd) { packet pk; // pk.write_uint32(file_server->get_port()); if (!send_pkt(nd,pk)) { printf("error writing to connection\n"); return ; } // while (!file_server->service_request()) milli_wait(1000); if (!get_pkt(nd,pk)) { printf("error reading from connection\n"); return ; } else { char name[100]; pk.get_string(name,100); printf("Joined by player %s\n",name); pk.reset(); uint8_t ok=1; pk.write((uint8_t *)&ok,1); // write ok to join send_pkt(nd,pk); /**************** Read suggested view size from client ****/ if (!get_pkt(nd,pk)) { printf("error reading view info from connection\n"); return ; } int32_t cx1,cy1,cx2,cy2; if (pk.read((uint8_t *)&cx1,4)!=4) return ; cx1=lltl(cx1); if (pk.read((uint8_t *)&cy1,4)!=4) return ; cy1=lltl(cy1); if (pk.read((uint8_t *)&cx2,4)!=4) return ; cx2=lltl(cx2); if (pk.read((uint8_t *)&cy2,4)!=4) return ; cy2=lltl(cy2); /**************** Create the player *******************/ for (view *f=player_list; f && f->next; f=f->next); // find last player, add one for pn int i,st=0; for (i=0; i<total_objects; i++) if (!strcmp(object_names[i],"START")) st=i; game_object *o=create(current_start_type,0,0); game_object *start=current_level->get_random_start(320,NULL); if (start) { o->x=start->x; o->y=start->y; } else { o->x=100; o->y=100; } f->next=new view(o,NULL,f->player_number+1); o->set_controller(f->next); current_level->add_object(o); view *v=f->next; v->cx1=cx1; v->cy1=cy1; v->cx2=cx2; v->cy2=cy2; v->connect=nd; strcpy(v->name,name); if (current_level->send(nd)) { uint8_t cmd=SCMD_ADD_VIEW; next_out.write((uint8_t *)&cmd,1); v->write_packet(next_out); /********** Send all of the views to the player **********/ pk.reset(); uint16_t tv=0; for (f=player_list; f; f=f->next) tv++; tv=lstl(tv); pk.write((uint8_t *)&tv,2); if (!send_pkt(nd,pk)) return ; for (f=player_list; f; f=f->next) { pk.reset(); f->write_packet(pk); if (!send_pkt(nd,pk)) return ; } pk.reset(); uint16_t r=lstl(rand_on); pk.write((uint8_t *)&r,2); // write current random seed pk.write((uint8_t *)rtable,1024*2); send_pkt(nd,pk); } } } } }
int server::process_command(view *f, uint8_t command, packet &pk) { switch (command) { case SCMD_QUIT : // delete player { dprintf("Player %d has quit\n",f->player_number); return 0; } break; case SCMD_VIEW_RESIZE : // change view area { uint32_t view_size[8]; if (pk.read((uint8_t *)view_size,8*4)!=8*4) return 0; else { f->resize_view(lltl(view_size[0]),lltl(view_size[1]),lltl(view_size[2]),lltl(view_size[3])); f->pan_x=lltl(view_size[4]); f->pan_y=lltl(view_size[5]); f->shift_down=lltl(view_size[6]); f->shift_right=lltl(view_size[7]); f->suggest.send_view=0; if (is_server) // if we are a server, tell everybody about this. { uint8_t cmd=SCMD_VIEW_RESIZE; next_out.write((uint8_t *)&cmd,1); uint16_t pn=lstl(f->player_number); next_out.write((uint8_t *)&pn,2); next_out.write((uint8_t *)view_size,8*4); } } } break; case SCMD_WEAPON_CHANGE : // change weapon { uint32_t new_weap; if (pk.read((uint8_t *)&new_weap,4)!=4) return 0; else { f->current_weapon=lltl(new_weap); f->suggest.send_weapon_change=0; if (is_server) // if we are a server, tell everybody about this. { uint8_t cmd=SCMD_WEAPON_CHANGE; next_out.write((uint8_t *)&cmd,1); uint16_t pn=lstl(f->player_number); next_out.write((uint8_t *)&pn,2); next_out.write((uint8_t *)&new_weap,4); } } } break; case SCMD_SET_INPUT : // set the input from this player { signed char inp[5]; if (pk.read((uint8_t *)inp,5)!=5) return 0; else f->set_input(inp[0],inp[1],inp[2],inp[3],inp[4]); } break; case SCMD_ADD_VIEW : { view *v=add_view(pk); if (v) { for (view *f=player_list; f && f->next; f=f->next); if (f) f->next=v; else player_list=f; } } break; case SCMD_SYNC : { uint32_t x; if (pk.read((uint8_t *)&x,4)!=4) return 0; else { uint32_t s=make_sync_uint32(); if (lltl(x)!=s) printf("Out of sync, %x!=%x\n",lltl(x),s); return 1; } } break; default : return 0; } return 1; }
int main(int argc, char *argv[]) { if (argc < 3) { Usage(); return EXIT_FAILURE; } int cmd = !strcmp(argv[2], "list") ? CMD_LIST : !strcmp(argv[2], "get") ? CMD_GET : !strcmp(argv[2], "del") ? CMD_DEL : !strcmp(argv[2], "put") ? CMD_PUT : !strcmp(argv[2], "move") ? CMD_MOVE : !strcmp(argv[2], "rename") ? CMD_RENAME : !strcmp(argv[2], "type") ? CMD_TYPE : !strcmp(argv[2], "getpcx") ? CMD_GETPCX : !strcmp(argv[2], "putpcx") ? CMD_PUTPCX : CMD_INVALID; if (cmd == CMD_INVALID) { fprintf(stderr, "abuse-tool: unknown command `%s'\n", argv[2]); return EXIT_FAILURE; } /* Check argument count and file access mode */ char const *mode = "rwb"; int minargc = 3; switch (cmd) { case CMD_LIST: mode = "rb"; // Read-only access break; case CMD_GET: minargc = 4; mode = "rb"; // Read-only access break; case CMD_PUT: minargc = 6; break; case CMD_MOVE: minargc = 5; break; case CMD_RENAME: minargc = 5; break; case CMD_TYPE: minargc = 5; break; case CMD_DEL: minargc = 4; break; case CMD_GETPCX: minargc = 4; mode = "rb"; // Read-only access break; case CMD_PUTPCX: minargc = 6; break; } if (argc < minargc) { fprintf(stderr, "abuse-tool: too few arguments for command `%s'\n", argv[2]); return EXIT_FAILURE; } /* Open the SPEC file */ char tmpfile[4096]; char const *file = argv[1]; snprintf(tmpfile, 4096, "%s.tmp", file); jFILE fp(file, mode); if (fp.open_failure()) { fprintf(stderr, "ERROR - could not open %s\n", file); return EXIT_FAILURE; } spec_directory dir(&fp); /* Now really execute commands */ if (cmd == CMD_LIST) { printf(" id type bytes crc name & information\n"); printf(" ---- ---- ------- ---- ----------------------------\n"); dir.FullyLoad(&fp); for (int i = 0; i < dir.total; i++) { spec_entry *se = dir.entries[i]; /* Print basic information */ printf("% 5i % 3i % 8i %04x %s", i, se->type, (int)se->size, calc_crc(se->data, se->size), se->name); /* Is there anything special to say? */ switch (se->type) { case SPEC_IMAGE: case SPEC_FORETILE: case SPEC_BACKTILE: case SPEC_CHARACTER: case SPEC_CHARACTER2: { image *im = new image(&fp, se); printf(" \t# %i x %i pixels", im->Size().x, im->Size().y); delete im; break; } case SPEC_PALETTE: { palette *pal = new palette(se, &fp); printf(" \t# %i colors", pal->pal_size()); delete pal; break; } #if 0 default: { /* Try to print a representation of the item */ int has_binary = 0; for (int i = 0; i < Min(20, (int)se->size); i++) { uint8_t ch = ((uint8_t *)se->data)[i]; if (ch < 0x20 || ch >= 0x7f) has_binary++; } if (has_binary <= 2 && se->size > 5) has_binary = 0; printf(" \t# "); if (!has_binary) putchar('\"'); size_t max = Min(has_binary ? 15 : 30, (int)se->size); for (size_t i = 0; i < max; i++) { uint8_t ch = ((uint8_t *)se->data)[i]; if (has_binary) printf("%02x ", ch); else if (ch && (ch < 0x20 || ch >= 0x7f)) printf("\\x%02x", ch); else if (ch) putchar(ch); else printf("\\0"); } if (se->size > max) printf("..."); else if (!has_binary) printf("\""); break; } #endif } /* Finish line */ putchar('\n'); } return EXIT_SUCCESS; } else if (cmd == CMD_GET) { int id = atoi(argv[3]); if (id < 0 || id >= dir.total) { fprintf(stderr, "abuse-tool: id %i not found in %s\n", id, file); return EXIT_FAILURE; } spec_entry *se = dir.entries[id]; fp.seek(se->offset, SEEK_SET); for (size_t todo = se->size; todo > 0; ) { uint8_t buf[1024]; int step = Min((int)todo, 1024); fp.read(buf, step); fwrite(buf, step, 1, stdout); todo -= step; } return EXIT_SUCCESS; } else if (cmd == CMD_GETPCX) { palette *pal; int imgid = atoi(argv[3]); int palid = argc > 4 ? atoi(argv[4]) : -1; for (int i = 0; palid == -1 && i < dir.total; i++) if (dir.entries[i]->type == SPEC_PALETTE) palid = i; if (palid == -1) pal = new palette(256); else pal = new palette(dir.entries[palid], &fp); image *im = new image(&fp, dir.entries[imgid]); write_PCX(im, pal, "/dev/stdout"); delete im; delete pal; return EXIT_SUCCESS; } else if (cmd == CMD_MOVE) { int src = atoi(argv[3]); int dst = atoi(argv[4]); if (src < 0 || dst < 0 || src >= dir.total || dst >= dir.total) { fprintf(stderr, "abuse-tool: ids %i/%i out of range\n", src, dst); return EXIT_FAILURE; } dir.FullyLoad(&fp); spec_entry *tmp = dir.entries[src]; for (int d = src < dst ? 1 : -1; src != dst; src += d) dir.entries[src] = dir.entries[src + d]; dir.entries[dst] = tmp; } else if (cmd == CMD_RENAME || cmd == CMD_TYPE) { int id = atoi(argv[3]); if (id < 0 || id >= dir.total) { fprintf(stderr, "abuse-tool: id %i out of range\n", id); return EXIT_FAILURE; } dir.FullyLoad(&fp); if (cmd == CMD_RENAME) dir.entries[id]->name = argv[4]; else dir.entries[id]->type = (uint8_t)atoi(argv[4]); } else if (cmd == CMD_DEL) { int id = atoi(argv[3]); if (id < 0 || id >= dir.total) { fprintf(stderr, "abuse-tool: id %i out of range\n", id); return EXIT_FAILURE; } dir.total--; for (int i = id; i < dir.total; i++) dir.entries[i] = dir.entries[i + 1]; dir.FullyLoad(&fp); } else if (cmd == CMD_PUT || cmd == CMD_PUTPCX) { int id = atoi(argv[3]); uint8_t type = atoi(argv[4]); if (id == -1) id = dir.total; if (id < 0 || id > dir.total) { fprintf(stderr, "abuse-tool: id %i out of range\n", id); return EXIT_FAILURE; } dir.FullyLoad(&fp); dir.total++; dir.entries = (spec_entry **)realloc(dir.entries, dir.total * sizeof(spec_entry *)); for (int i = dir.total - 1; i-- > id; ) dir.entries[i + 1] = dir.entries[i]; char *name = strrchr(argv[5], '/'); if (!name) name = argv[5]; uint8_t *data; size_t len; if (cmd == CMD_PUT) { jFILE fp2(argv[5], "rb"); if (fp2.open_failure()) { fprintf(stderr, "abuse-tool: cannot open %s\n", argv[5]); return EXIT_FAILURE; } len = fp2.file_size(); data = (uint8_t *)malloc(len); fp2.read(data, len); } else { palette *pal = NULL; image *im = read_PCX(argv[5], pal); if (!im) { fprintf(stderr, "abuse-tool: cannot open %s\n", argv[5]); return EXIT_FAILURE; } vec2i size = im->Size(); len = 2 * sizeof(uint16_t) + size.x * size.y; data = (uint8_t *)malloc(len); uint16_t x = lltl((uint16_t)size.x); uint16_t y = lltl((uint16_t)size.y); memcpy(data, &x, sizeof(x)); memcpy(data + 2, &y, sizeof(y)); memcpy(data + 4, im->scan_line(0), size.x * size.y); } dir.entries[id] = new spec_entry(type, name, NULL, len, 0); dir.entries[id]->data = data; } else { /* Not implemented yet */ return EXIT_FAILURE; } /* If we get here, we need to write the directory back */ dir.calc_offsets(); fp.seek(0, SEEK_SET); // FIXME: create a new file dir.write(&fp); for (int i = 0; i < dir.total; i++) fp.write(dir.entries[i]->data, dir.entries[i]->size); return EXIT_SUCCESS; }