/* * @brief */ void WriteAASFile(void) { char path[MAX_QPATH]; file_t *f; StripExtension(bsp_name, path); g_strlcat(path, ".aas", sizeof(path)); if (!(f = Fs_OpenWrite(path))) { Com_Error(ERR_FATAL, "Couldn't open %s for writing\n", path); } Com_Print("Writing %d AAS nodes..\n", d_aas.num_nodes); SwapAASFile(); d_bsp_header_t header; memset(&header, 0, sizeof(header)); header.ident = LittleLong(AAS_IDENT); header.version = LittleLong(AAS_VERSION); Fs_Write(f, &header, 1, sizeof(header)); d_bsp_lump_t *lump = &header.lumps[AAS_LUMP_NODES]; WriteLump(f, lump, d_aas.nodes, sizeof(d_aas_node_t) * d_aas.num_nodes); // rewrite the header with the populated lumps Fs_Seek(f, 0); Fs_Write(f, &header, 1, sizeof(header)); Fs_Close(f); }
/* * @brief Writes the specified lump to the AAS file. */ static void WriteLump(file_t *f, d_bsp_lump_t *lump, void *data, size_t len) { lump->file_ofs = LittleLong((int32_t) Fs_Tell(f)); lump->file_len = LittleLong((int32_t) len); Fs_Write(f, data, 1, (len + 3) & ~3); }
/* * @brief Dumps the current net message, prefixed by the length. */ void Cl_WriteDemoMessage(void) { int32_t len; if (!cls.demo_file) return; // if we received an uncompressed frame, write the demo header if (cl.frame.delta_frame < 1 && !Fs_Tell(cls.demo_file)) { Cl_WriteDemoHeader(); } // the first eight bytes are just packet sequencing stuff len = LittleLong(net_message.size - 8); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, net_message.data + 8, len, 1); }
/* * Pak_CreatePakstream * * Allocate a new Pakfile for creating a new archive from arbitrary resources. */ pak_t *Pak_CreatePakstream(char *pakfile) { FILE *f; pak_t *pak; pak_header_t header; if (!(f = fopen(pakfile, "wb"))) { fprintf(stderr, "Couldn't open %s.\n", pakfile); err = ERR_DIR; return NULL; } // allocate a new pak pak = (pak_t *) Z_Malloc(sizeof(*pak)); pak->entries = (pak_entry_t *) Z_Malloc( sizeof(pak_entry_t) * MAX_PAK_ENTRIES); pak->num_entries = 0; pak->handle = f; strcpy(pak->file_name, pakfile); // stuff a bogus header for now memset(&header, 0, sizeof(header)); Fs_Write(&header, sizeof(header), 1, pak->handle); return pak; }
END_TEST START_TEST(check_Ms_BlacklistServer) { file_t *f = Fs_OpenAppend("servers-blacklist"); ck_assert_msg(f != NULL, "Failed to open servers-blacklist"); const char *test = "192.168.0.*\n"; int64_t len = Fs_Write(f, (void *) test, 1, strlen(test)); ck_assert_msg((size_t) len == strlen(test), "Failed to write servers-blacklist"); ck_assert_msg(Fs_Close(f), "Failed to close servers-blacklist"); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); *(in_addr_t *) &addr.sin_addr = inet_addr("192.168.0.1"); addr.sin_family = AF_INET; addr.sin_port = htons(PORT_SERVER); ck_assert_msg(Ms_BlacklistServer(&addr), "Missed %s", inet_ntoa(addr.sin_addr)); *(in_addr_t *) &addr.sin_addr = inet_addr("127.0.0.1"); ck_assert_msg(!Ms_BlacklistServer(&addr), "False positive for %s", inet_ntoa(addr.sin_addr)); }
/* * Pak_ClosePakstream * * Finalizes and frees a newly created Pakfile archive. */ void Pak_ClosePakstream(pak_t *pak) { pak_header_t header; int i; header.ident = PAK_HEADER; header.dir_len = pak->num_entries * sizeof(pak_entry_t); header.dir_ofs = ftell(pak->handle); // write the directory (table of contents) of entries for (i = 0; i < pak->num_entries; i++) Fs_Write(&pak->entries[i], sizeof(pak_entry_t), 1, pak->handle); // go back to the beginning to finalize header fseek(pak->handle, 0, SEEK_SET); Fs_Write(&header, sizeof(pak_header_t), 1, pak->handle); Pak_FreePakfile(pak); }
/* * Cl_WriteDemoMessage * * Dumps the current net message, prefixed by the length. */ void Cl_WriteDemoMessage(void) { int size; if (!cls.demo_file) return; if (cls.demo_waiting) // we have not yet received a non-delta frame return; if (!ftell(cls.demo_file)) // write header Cl_WriteDemoHeader(); // the first eight bytes are just packet sequencing stuff size = LittleLong(net_message.size - 8); Fs_Write(&size, 4, 1, cls.demo_file); // write the message payload Fs_Write(net_message.data + 8, size, 1, cls.demo_file); }
/** * @brief Dumps the current net message, prefixed by the length. */ void Cl_WriteDemoMessage(void) { if (!cls.demo_file) { return; } if (!Fs_Tell(cls.demo_file)) { if (cl.frame.delta_frame_num < 0) { Com_Debug(DEBUG_CLIENT, "Received uncompressed frame, writing demo header..\n"); Cl_WriteDemoHeader(); } else { return; // wait for an uncompressed packet } } // the first eight bytes are just packet sequencing stuff const int32_t len = LittleLong((int32_t) (net_message.size - 8)); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, net_message.data + 8, len, 1); }
/* * @brief A download message has been received from the server. */ static void Cl_ParseDownload(void) { int32_t size, percent; // read the data size = Net_ReadShort(&net_message); percent = Net_ReadByte(&net_message); if (size < 0) { Com_Debug("Server does not have this file\n"); if (cls.download.file) { // if here, we tried to resume a file but the server said no Fs_Close(cls.download.file); cls.download.file = NULL; } Cl_RequestNextDownload(); return; } // open the file if not opened yet if (!cls.download.file) { if (!(cls.download.file = Fs_OpenWrite(cls.download.tempname))) { net_message.read += size; Com_Warn("Failed to open %s\n", cls.download.tempname); Cl_RequestNextDownload(); return; } } Fs_Write(cls.download.file, net_message.data + net_message.read, 1, size); net_message.read += size; if (percent != 100) { Net_WriteByte(&cls.net_chan.message, CL_CMD_STRING); Net_WriteString(&cls.net_chan.message, "nextdl"); } else { Fs_Close(cls.download.file); cls.download.file = NULL; // add new archives to the search path if (Fs_Rename(cls.download.tempname, cls.download.name)) { if (strstr(cls.download.name, ".zip")) { Fs_AddToSearchPath(cls.download.name); } } else { Com_Error(ERR_DROP, "Failed to rename %s\n", cls.download.name); } // get another file if needed Cl_RequestNextDownload(); } }
/* * Pak_ExtractPakfile * * A convenience function for deserializing a Pakfile to the filesystem. */ void Pak_ExtractPakfile(const char *pakfile, char *dir, boolean_t test) { pak_t *pak; FILE *f; void *p; int i; if (dir && chdir(dir) == -1) { fprintf(stderr, "Couldn't unpak to %s.\n", dir); err = ERR_DIR; return; } if (!(pak = Pak_ReadPakfile(pakfile))) { err = ERR_PAK; return; } for (i = 0; i < pak->num_entries; i++) { if (test) { // print contents and continue printf("Contents %s (%d bytes).\n", pak->entries[i].name, pak->entries[i].file_len); continue; } Pak_MakePath(pak->entries[i].name); if (!(f = fopen(pak->entries[i].name, "wb"))) { fprintf(stderr, "Couldn't write %s.\n", pak->entries[i].name); err = ERR_PAK; continue; } fseek(pak->handle, pak->entries[i].file_ofs, SEEK_SET); p = (void *) Z_Malloc(pak->entries[i].file_len); Fs_Read(p, 1, pak->entries[i].file_len, pak->handle); Fs_Write(p, 1, pak->entries[i].file_len, f); Fs_CloseFile(f); Z_Free(p); printf("Extracted %s (%d bytes).\n", pak->entries[i].name, pak->entries[i].file_len); } Pak_FreePakfile(pak); }
/** * @brief Stop recording a demo */ void Cl_Stop_f(void) { int32_t len = -1; if (!cls.demo_file) { Com_Print("Not recording a demo\n"); return; } // finish up Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Close(cls.demo_file); cls.demo_file = NULL; Com_Print("Stopped demo\n"); }
}END_TEST START_TEST(check_Fs_OpenWrite) { file_t *f = Fs_OpenWrite(__func__); ck_assert_msg(f != NULL, "Failed to open %s", __func__); const char *testing = "testing"; int64_t len = Fs_Write(f, (void *) testing, 1, strlen(testing)); ck_assert_msg((size_t) len == strlen(testing), "Failed to write %s", __func__); ck_assert_msg(Fs_Close(f), "Failed to close %s", __func__); }END_TEST
/* * Cl_Stop_f * * Stop recording a demo */ void Cl_Stop_f(void) { int size; if (!cls.demo_file) { Com_Print("Not recording a demo.\n"); return; } // finish up size = -1; Fs_Write(&size, 4, 1, cls.demo_file); Fs_CloseFile(cls.demo_file); cls.demo_file = NULL; Com_Print("Stopped demo.\n"); // inform server we're done recording Cvar_ForceSet("recording", "0"); }
/* * Pak_AddEntry * * Add an entry to the specified Pakfile stream. */ void Pak_AddEntry(pak_t *pak, char *name, int len, void *p) { char *c; if (pak->num_entries == MAX_PAK_ENTRIES) { fprintf(stderr, "Maximum pak entries (4096) reached.\n"); return; } c = name; // strip './' from names if (!strncmp(c, "./", 2)) c += 2; memset(pak->entries[pak->num_entries].name, 0, 56); strncpy(pak->entries[pak->num_entries].name, c, 55); pak->entries[pak->num_entries].file_len = len; pak->entries[pak->num_entries].file_ofs = ftell(pak->handle); Fs_Write(p, len, 1, pak->handle); printf("Added %s (%d bytes).\n", c, len); pak->num_entries++; }
/** * @brief Writes server_data, config_strings, and baselines once a non-delta * compressed frame arrives from the server. */ static void Cl_WriteDemoHeader(void) { static entity_state_t null_state; mem_buf_t msg; byte buffer[MAX_MSG_SIZE]; // write out messages to hold the startup information Mem_InitBuffer(&msg, buffer, sizeof(buffer)); // write the server data Net_WriteByte(&msg, SV_CMD_SERVER_DATA); Net_WriteShort(&msg, PROTOCOL_MAJOR); Net_WriteShort(&msg, cls.cgame->protocol); Net_WriteByte(&msg, 1); // demo_server byte Net_WriteString(&msg, Cvar_GetString("game")); Net_WriteShort(&msg, cl.client_num); Net_WriteString(&msg, cl.config_strings[CS_NAME]); // and config_strings for (int32_t i = 0; i < MAX_CONFIG_STRINGS; i++) { if (*cl.config_strings[i] != '\0') { if (msg.size + strlen(cl.config_strings[i]) + 32 > msg.max_size) { // write it out const int32_t len = LittleLong((int32_t) msg.size); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, msg.data, msg.size, 1); msg.size = 0; } Net_WriteByte(&msg, SV_CMD_CONFIG_STRING); Net_WriteShort(&msg, i); Net_WriteString(&msg, cl.config_strings[i]); } } // and baselines for (size_t i = 0; i < lengthof(cl.entities); i++) { entity_state_t *ent = &cl.entities[i].baseline; if (!ent->number) { continue; } if (msg.size + 64 > msg.max_size) { // write it out const int32_t len = LittleLong((int32_t) msg.size); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, msg.data, msg.size, 1); msg.size = 0; } Net_WriteByte(&msg, SV_CMD_BASELINE); Net_WriteDeltaEntity(&msg, &null_state, &cl.entities[i].baseline, true); } Net_WriteByte(&msg, SV_CMD_CBUF_TEXT); Net_WriteString(&msg, "precache 0\n"); // write it to the demo file const int32_t len = LittleLong((int32_t) msg.size); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, msg.data, msg.size, 1); Com_Debug(DEBUG_CLIENT, "Demo started\n"); // the rest of the demo file will be individual frames }
/* * Cl_WriteDemoHeader * * Writes server_data, config_strings, and baselines once a non-delta * compressed frame arrives from the server. */ static void Cl_WriteDemoHeader(void) { byte buffer[MAX_MSG_SIZE]; size_buf_t msg; int i; int len; entity_state_t null_state; // write out messages to hold the startup information Sb_Init(&msg, buffer, sizeof(buffer)); // write the server data Msg_WriteByte(&msg, SV_CMD_SERVER_DATA); Msg_WriteLong(&msg, PROTOCOL); Msg_WriteLong(&msg, cl.server_count); Msg_WriteLong(&msg, cl.server_frame_rate); Msg_WriteByte(&msg, 1); // demo_server byte Msg_WriteString(&msg, Cvar_GetString("game")); Msg_WriteShort(&msg, cl.player_num); Msg_WriteString(&msg, cl.config_strings[CS_NAME]); // and config_strings for (i = 0; i < MAX_CONFIG_STRINGS; i++) { if (*cl.config_strings[i] != '\0') { if (msg.size + strlen(cl.config_strings[i]) + 32 > msg.max_size) { // write it out len = LittleLong(msg.size); Fs_Write(&len, 4, 1, cls.demo_file); Fs_Write(msg.data, msg.size, 1, cls.demo_file); msg.size = 0; } Msg_WriteByte(&msg, SV_CMD_CONFIG_STRING); Msg_WriteShort(&msg, i); Msg_WriteString(&msg, cl.config_strings[i]); } } // and baselines for (i = 0; i < MAX_EDICTS; i++) { entity_state_t *ent = &cl.entities[i].baseline; if (!ent->number) continue; if (msg.size + 64 > msg.max_size) { // write it out len = LittleLong(msg.size); Fs_Write(&len, 4, 1, cls.demo_file); Fs_Write(msg.data, msg.size, 1, cls.demo_file); msg.size = 0; } memset(&null_state, 0, sizeof(null_state)); Msg_WriteByte(&msg, SV_CMD_ENTITY_BASELINE); Msg_WriteDeltaEntity(&null_state, &cl.entities[i].baseline, &msg, true, true); } Msg_WriteByte(&msg, SV_CMD_CBUF_TEXT); Msg_WriteString(&msg, "precache 0\n"); // write it to the demo file len = LittleLong(msg.size); Fs_Write(&len, 4, 1, cls.demo_file); Fs_Write(msg.data, msg.size, 1, cls.demo_file); Com_Print("Recording to %s.\n", cls.demo_path); // the rest of the demo file will be individual frames }
long status; _Bool ready; _Bool success; char error_buffer[MAX_STRING_CHARS]; } cl_http_state_t; static cl_http_state_t cl_http_state; /* * @brief cURL HTTP receive handler. */ static size_t Cl_HttpDownload_Receive(void *buffer, size_t size, size_t count, void *p __attribute__((unused))) { const int64_t i = Fs_Write(cls.download.file, buffer, size, count); return i > 0 ? (size_t) i : 0; } /* * @brief If a download is currently taking place, clean it up. This is called * both to finalize completed downloads as well as abort incomplete ones. */ void Cl_HttpDownload_Complete() { if (!cls.download.file || !cls.download.http) return; curl_multi_remove_handle(cl_http_state.curlm, cl_http_state.curl); // cleanup curl Fs_Close(cls.download.file); // always close the file