/* * @brief Returns true if the specified server has been blacklisted, false otherwise. * The format of the blacklist file is one-IP-per-line, with wildcards. Ex: * * // This guy is a joker * 66.182.58.* * * Ensure that the file is new-line terminated for all rules to be evaluated. * TODO This is entirely untested */ static _Bool Ms_BlacklistServer(struct sockaddr_in *from) { void *buf; int32_t len; if ((len = Fs_Load("servers-blacklist", &buf)) == -1) { return false; } char *c = (char *) buf; char *ip = inet_ntoa(from->sin_addr); while ((c - (char *) buf) < len) { char line[256]; sscanf(c, "%s\n", line); if (strncmp(line, "//", 2)) { if (GlobMatch(line, ip)) { return true; } } c += strlen(line) + 1; } return false; }
/* * @brief Handles the actual loading of .ogg music files. */ static _Bool S_LoadMusicFile(const char *name, void **buffer, SDL_RWops **rw, Mix_Music **music) { char path[MAX_QPATH]; *music = NULL; StripExtension(name, path); g_snprintf(path, sizeof(path), "music/%s.ogg", name); int32_t len; if ((len = Fs_Load(path, buffer)) != -1) { if ((*rw = SDL_RWFromMem(*buffer, len))) { if ((*music = Mix_LoadMUS_RW(*rw))) { Com_Debug("Loaded %s\n", name); } else { Com_Warn("Failed to load %s: %s\n", name, Mix_GetError()); SDL_FreeRW(*rw); } } else { Com_Warn("Failed to create SDL_RWops for %s\n", name); Fs_Free(*buffer); } } else { Com_Debug("Failed to load %s\n", name); } return *music != NULL; }
/** * @brief Returns true if the specified server has been blacklisted, false otherwise. * The format of the blacklist file is one-IP-per-line, with wildcards. Ex: * * // This guy is a joker * 66.182.58.* * * Ensure that the file is new-line terminated for all rules to be evaluated. */ static _Bool Ms_BlacklistServer(struct sockaddr_in *from) { char *buffer; int64_t len; if ((len = Fs_Load("servers-blacklist", (void *) &buffer)) == -1) { return false; } char *c = buffer; char *ip = inet_ntoa(from->sin_addr); _Bool blacklisted = false; while ((c - buffer) < len) { char line[256]; sscanf(c, "%s\n", line); c += strlen(line) + 1; const char *l = g_strstrip(line); if (!strlen(l) || g_str_has_prefix(l, "//") || g_str_has_prefix(l, "#")) { continue; } if (GlobMatch(l, ip)) { blacklisted = true; break; } } Fs_Free((void *) buffer); return blacklisted; }
/* * @brief */ static void S_LoadSampleChunk(s_sample_t *sample) { char path[MAX_QPATH]; void *buf; int32_t i, len; SDL_RWops *rw; if (sample->media.name[0] == '*') // place holder return; if (sample->media.name[0] == '#') { // global path g_strlcpy(path, (sample->media.name + 1), sizeof(path)); } else { // or relative g_snprintf(path, sizeof(path), "sounds/%s", sample->media.name); } buf = NULL; rw = NULL; i = 0; while (SAMPLE_TYPES[i]) { StripExtension(path, path); g_strlcat(path, SAMPLE_TYPES[i++], sizeof(path)); if ((len = Fs_Load(path, &buf)) == -1) continue; if (!(rw = SDL_RWFromMem(buf, len))) { Fs_Free(buf); continue; } if (!(sample->chunk = Mix_LoadWAV_RW(rw, false))) Com_Warn("%s\n", Mix_GetError()); Fs_Free(buf); SDL_FreeRW(rw); if (sample->chunk) { // success break; } } if (sample->chunk) { Mix_VolumeChunk(sample->chunk, s_volume->value * MIX_MAX_VOLUME); Com_Debug("Loaded %s\n", path); } else { if (g_str_has_prefix(sample->media.name, "#players")) { Com_Debug("Failed to load player sample %s\n", sample->media.name); } else { Com_Warn("Failed to load %s\n", sample->media.name); } } }
}END_TEST START_TEST(check_Fs_LoadFile) { void *buffer; int64_t len = Fs_Load("quetoo.cfg", &buffer); ck_assert_msg(len > 0, "Failed to load quetoo.cfg"); const char *prefix = "// generated by Quetoo, do not modify\n"; ck_assert(g_str_has_prefix((const char *) buffer, prefix)); Fs_Free(buffer); }END_TEST
/* * @brief */ static void AddScriptToStack(const char *file_name) { int64_t size; script++; if (script == &scriptstack[MAX_INCLUDES]) Com_Error(ERR_FATAL, "Script file exceeded MAX_INCLUDES\n"); strcpy(script->file_name, file_name); size = Fs_Load(script->file_name, (void **) (char *) &script->buffer); if (size == -1) Com_Error(ERR_FATAL, "Could not load %s\n", script->file_name); Com_Verbose("Loading %s (%u bytes)\n", script->file_name, (uint32_t) size); script->line = 1; script->script_p = script->buffer; script->end_p = script->buffer + size; }
/* * @brief Loads the model by the specified name. */ r_model_t *R_LoadModel(const char *name) { r_model_t *mod; char key[MAX_QPATH]; size_t i; if (!name || !name[0]) { Com_Error(ERR_DROP, "R_LoadModel: NULL name\n"); } if (*name == '*') { g_snprintf(key, sizeof(key), "%s#%s", r_model_state.world->media.name, name + 1); } else { StripExtension(name, key); } if (!(mod = (r_model_t *) R_FindMedia(key))) { void *buf; const r_model_format_t *format = r_model_formats; for (i = 0; i < lengthof(r_model_formats); i++, format++) { StripExtension(name, key); strcat(key, format->extension); if (Fs_Load(key, &buf) != -1) break; } if (i == lengthof(r_model_formats)) { // not found if (strstr(name, "players/")) { Com_Debug("Failed to load player %s\n", name); } else { Com_Warn("Failed to load %s\n", name); } return NULL; } StripExtension(name, key); mod = (r_model_t *) R_AllocMedia(key, sizeof(r_model_t)); mod->media.Register = R_RegisterModel; mod->media.Free = R_FreeModel; mod->type = format->type; // load the materials first, so that we can resolve surfaces lists R_LoadMaterials(mod); // load it format->Load(mod, buf); // free the file Fs_Free(buf); // assemble vertex buffer objects from static arrays R_LoadVertexBuffers(mod); // calculate an approximate radius from the bounding box vec3_t tmp; VectorSubtract(mod->maxs, mod->mins, tmp); mod->radius = VectorLength(tmp) / 2.0; R_RegisterMedia((r_media_t *) mod); } return mod; }
/* * @brief Returns true if the file exists, otherwise it attempts to start a download * from the server. */ _Bool Cl_CheckOrDownloadFile(const char *filename) { char cmd[MAX_STRING_CHARS]; if (cls.state == CL_DISCONNECTED) { Com_Print("Not connected\n"); return true; } if (IS_INVALID_DOWNLOAD(filename)) { Com_Warn("Refusing to download \"%s\"\n", filename); return true; } Com_Debug("Checking for %s\n", filename); if (Fs_Exists(filename)) { // it exists, no need to download return true; } Com_Debug("Attempting to download %s\n", filename); strncpy(cls.download.name, filename, sizeof(cls.download.name)); // udp downloads to a temp name, and only renames when done StripExtension(cls.download.name, cls.download.tempname); g_strlcat(cls.download.tempname, ".tmp", sizeof(cls.download.tempname)); // attempt an http download if available if (cls.download_url[0] && Cl_HttpDownload()) return false; // check to see if we already have a tmp for this file, if so, try to resume // open the file if not opened yet if (Fs_Exists(cls.download.tempname)) { // a temp file exists, resume download int64_t len = Fs_Load(cls.download.tempname, NULL); if ((cls.download.file = Fs_OpenAppend(cls.download.tempname))) { if (Fs_Seek(cls.download.file, len - 1)) { // give the server the offset to start the download Com_Debug("Resuming %s...\n", cls.download.name); g_snprintf(cmd, sizeof(cmd), "download %s %u", cls.download.name, (uint32_t) len); Net_WriteByte(&cls.net_chan.message, CL_CMD_STRING); Net_WriteString(&cls.net_chan.message, cmd); return false; } } } // or start if from the beginning Com_Debug("Downloading %s...\n", cls.download.name); g_snprintf(cmd, sizeof(cmd), "download %s", cls.download.name); Net_WriteByte(&cls.net_chan.message, CL_CMD_STRING); Net_WriteString(&cls.net_chan.message, cmd); return false; }
/* * @brief */ static void LoadPortals(const char *filename) { uint32_t i; portal_t *p; leaf_t *l; char magic[80]; char *buffer, *s; int32_t len; int32_t num_points; winding_t *w; int32_t leaf_nums[2]; plane_t plane; if (Fs_Load(filename, (void **) &buffer) == -1) Com_Error(ERR_FATAL, "Could not open %s\n", filename); s = buffer; memset(&map_vis, 0, sizeof(map_vis)); if (sscanf(s, "%79s\n%u\n%u\n%n", magic, &map_vis.portal_clusters, &map_vis.num_portals, &len) != 3) Com_Error(ERR_FATAL, "Failed to read header: %s\n", filename); s += len; if (g_strcmp0(magic, PORTALFILE)) Com_Error(ERR_FATAL, "Not a portal file: %s\n", filename); Com_Verbose("Loading %4u portals, %4u clusters from %s...\n", map_vis.num_portals, map_vis.portal_clusters, filename); // these counts should take advantage of 64 bit systems automatically map_vis.leaf_bytes = ((map_vis.portal_clusters + 63) & ~63) >> 3; map_vis.leaf_longs = map_vis.leaf_bytes / sizeof(long); map_vis.portal_bytes = ((map_vis.num_portals * 2 + 63) & ~63) >> 3; map_vis.portal_longs = map_vis.portal_bytes / sizeof(long); // each file portal is split into two memory portals map_vis.portals = Mem_Malloc(2 * map_vis.num_portals * sizeof(portal_t)); // allocate the leafs map_vis.leafs = Mem_Malloc(map_vis.portal_clusters * sizeof(leaf_t)); map_vis.uncompressed_size = map_vis.portal_clusters * map_vis.leaf_bytes; map_vis.uncompressed = Mem_Malloc(map_vis.uncompressed_size); map_vis.base = map_vis.pointer = d_bsp.vis_data; d_vis->num_clusters = map_vis.portal_clusters; map_vis.pointer = (byte *) &d_vis->bit_offsets[map_vis.portal_clusters]; map_vis.end = map_vis.base + MAX_BSP_VISIBILITY; for (i = 0, p = map_vis.portals; i < map_vis.num_portals; i++) { int32_t j; if (sscanf(s, "%i %i %i %n", &num_points, &leaf_nums[0], &leaf_nums[1], &len) != 3) { Com_Error(ERR_FATAL, "Failed to read portal %i\n", i); } s += len; if (num_points > MAX_POINTS_ON_WINDING) { Com_Error(ERR_FATAL, "Portal %i has too many points\n", i); } if ((uint32_t) leaf_nums[0] > map_vis.portal_clusters || (uint32_t) leaf_nums[1] > map_vis.portal_clusters) { Com_Error(ERR_FATAL, "Portal %i has invalid leafs\n", i); } w = p->winding = NewWinding(num_points); w->original = true; w->num_points = num_points; for (j = 0; j < num_points; j++) { double v[3]; int32_t k; // scanf into double, then assign to vec_t // so we don't care what size vec_t is if (sscanf(s, "(%lf %lf %lf ) %n", &v[0], &v[1], &v[2], &len) != 3) Com_Error(ERR_FATAL, "Failed to read portal vertex definition %i:%i\n", i, j); s += len; for (k = 0; k < 3; k++) w->points[j][k] = v[k]; } if (sscanf(s, "\n%n", &len)) { s += len; } // calc plane PlaneFromWinding(w, &plane); // create forward portal l = &map_vis.leafs[leaf_nums[0]]; if (l->num_portals == MAX_PORTALS_ON_LEAF) Com_Error(ERR_FATAL, "MAX_PORTALS_ON_LEAF\n"); l->portals[l->num_portals] = p; l->num_portals++; p->winding = w; VectorSubtract(vec3_origin, plane.normal, p->plane.normal); p->plane.dist = -plane.dist; p->leaf = leaf_nums[1]; SetPortalSphere(p); p++; // create backwards portal l = &map_vis.leafs[leaf_nums[1]]; if (l->num_portals == MAX_PORTALS_ON_LEAF) Com_Error(ERR_FATAL, "MAX_PORTALS_ON_LEAF\n"); l->portals[l->num_portals] = p; l->num_portals++; p->winding = NewWinding(w->num_points); p->winding->num_points = w->num_points; for (j = 0; j < w->num_points; j++) { VectorCopy(w->points[w->num_points - 1 - j], p->winding->points[j]); } p->plane = plane; p->leaf = leaf_nums[0]; SetPortalSphere(p); p++; } Fs_Free(buffer); }
/* * @brief Loads in the BSP and all sub-models for collision detection. This * function can also be used to initialize or clean up the collision model by * invoking with NULL. */ cm_bsp_model_t *Cm_LoadBspModel(const char *name, int64_t *size) { void *buf; memset(&cm_bsp, 0, sizeof(cm_bsp)); cm_vis = (d_bsp_vis_t *) cm_bsp.visibility; // clean up and return if (!name) { if (size) { *size = 0; } return &cm_bsp.models[0]; } // load the file const int64_t s = Fs_Load(name, &buf); if (s == -1) { Com_Error(ERR_DROP, "Couldn't load %s\n", name); } if (size) { *size = s; } // byte-swap the entire header d_bsp_header_t header = *(d_bsp_header_t *) buf; for (size_t i = 0; i < sizeof(d_bsp_header_t) / sizeof(int32_t); i++) { ((int32_t *) &header)[i] = LittleLong(((int32_t *) &header)[i]); } if (header.version != BSP_VERSION && header.version != BSP_VERSION_QUETOO) { Com_Error(ERR_DROP, "%s has unsupported version: %d\n", name, header.version); } g_strlcpy(cm_bsp.name, name, sizeof(cm_bsp.name)); cm_bsp.base = (byte *) buf; // load into heap Cm_LoadEntityString(&header.lumps[BSP_LUMP_ENTITIES]); Cm_LoadBspPlanes(&header.lumps[BSP_LUMP_PLANES]); Cm_LoadBspNodes(&header.lumps[BSP_LUMP_NODES]); Cm_LoadBspSurfaces(&header.lumps[BSP_LUMP_TEXINFO]); Cm_LoadBspLeafs(&header.lumps[BSP_LUMP_LEAFS]); Cm_LoadBspLeafBrushes(&header.lumps[BSP_LUMP_LEAF_BRUSHES]); Cm_LoadBspInlineModels(&header.lumps[BSP_LUMP_MODELS]); Cm_LoadBspBrushes(&header.lumps[BSP_LUMP_BRUSHES]); Cm_LoadBspBrushSides(&header.lumps[BSP_LUMP_BRUSH_SIDES]); Cm_LoadBspVisibility(&header.lumps[BSP_LUMP_VISIBILITY]); Cm_LoadBspAreas(&header.lumps[BSP_LUMP_AREAS]); Cm_LoadBspAreaPortals(&header.lumps[BSP_LUMP_AREA_PORTALS]); Fs_Free(buf); Cm_SetupBspBrushes(); Cm_InitBoxHull(); Cm_FloodAreas(); return &cm_bsp.models[0]; }
/** * @brief Loads in the BSP and all sub-models for collision detection. This * function can also be used to initialize or clean up the collision model by * invoking with NULL. */ cm_bsp_model_t *Cm_LoadBspModel(const char *name, int64_t *size) { // don't re-load if we don't have to if (name && !g_strcmp0(name, cm_bsp.name)) { if (size) { *size = cm_bsp.size; } return &cm_bsp.models[0]; } Cm_UnloadBspMaterials(); Bsp_UnloadLumps(&cm_bsp.bsp, BSP_LUMPS_ALL); // free dynamic memory Mem_Free(cm_bsp.planes); Mem_Free(cm_bsp.nodes); Mem_Free(cm_bsp.texinfos); Mem_Free(cm_bsp.leafs); Mem_Free(cm_bsp.leaf_brushes); Mem_Free(cm_bsp.models); Mem_Free(cm_bsp.brushes); Mem_Free(cm_bsp.brush_sides); Mem_Free(cm_bsp.areas); Mem_Free(cm_bsp.portal_open); memset(&cm_bsp, 0, sizeof(cm_bsp)); // clean up and return if (!name) { if (size) { *size = 0; } return &cm_bsp.models[0]; } // load the common BSP structure and the lumps we need bsp_header_t *file; if (!Fs_Load(name, (void **) &file)) { Com_Error(ERROR_DROP, "Couldn't load %s\n", name); } int32_t version = Bsp_Verify(file); if (version != BSP_VERSION && version != BSP_VERSION_QUETOO) { Fs_Free(file); Com_Error(ERROR_DROP, "%s has unsupported version: %d\n", name, version); } if (!Bsp_LoadLumps(file, &cm_bsp.bsp, CM_BSP_LUMPS)) { Fs_Free(file); Com_Error(ERROR_DROP, "Lump error loading %s\n", name); } // in theory, by this point the BSP is valid - now we have to create the cm_ // structures out of the raw file data if (size) { cm_bsp.size = *size = Bsp_Size(file); } g_strlcpy(cm_bsp.name, name, sizeof(cm_bsp.name)); Fs_Free(file); cm_bsp.materials = Cm_LoadBspMaterials(name); Cm_LoadBspPlanes(); Cm_LoadBspNodes(); Cm_LoadBspSurfaces(); Cm_LoadBspLeafs(); Cm_LoadBspLeafBrushes(); Cm_LoadBspInlineModels(); Cm_LoadBspBrushes(); Cm_LoadBspBrushSides(); Cm_LoadBspVisibility(); Cm_LoadBspAreas(); Cm_LoadBspAreaPortals(); Cm_SetupBspBrushes(); Cm_InitBoxHull(); Cm_FloodAreas(); return &cm_bsp.models[0]; }
/* * @brief */ static r_shader_t *R_LoadShader(GLenum type, const char *name) { r_shader_t *sh; char path[MAX_QPATH], *src[1], log[MAX_STRING_CHARS]; uint32_t e, length[1]; void *buf; int32_t i, len; g_snprintf(path, sizeof(path), "shaders/%s", name); if ((len = Fs_Load(path, &buf)) == -1) { Com_Warn("Failed to load %s\n", name); return NULL; } src[0] = (char *) buf; length[0] = len; for (i = 0; i < MAX_SHADERS; i++) { sh = &r_state.shaders[i]; if (!sh->id) break; } if (i == MAX_SHADERS) { Com_Warn("MAX_SHADERS reached\n"); Fs_Free(buf); return NULL; } g_strlcpy(sh->name, name, sizeof(sh->name)); sh->type = type; sh->id = qglCreateShader(sh->type); if (!sh->id) { Fs_Free(buf); return NULL; } // upload the shader source qglShaderSource(sh->id, 1, src, length); // compile it and check for errors qglCompileShader(sh->id); qglGetShaderiv(sh->id, GL_COMPILE_STATUS, &e); if (!e) { qglGetShaderInfoLog(sh->id, sizeof(log) - 1, NULL, log); Com_Warn("%s: %s\n", sh->name, log); qglDeleteShader(sh->id); memset(sh, 0, sizeof(*sh)); Fs_Free(buf); return NULL; } Fs_Free(buf); return sh; }