the old Safe read/writes are gonedy now

This commit is contained in:
Jonathan 2022-06-16 20:22:03 -04:00
parent 62f5867581
commit e57633bbca
8 changed files with 112 additions and 170 deletions

View File

@ -322,65 +322,3 @@ data load(const path &p)
return arch->load(filename);
}
} // namespace fs
qfile_t SafeOpenWrite(const fs::path &filename)
{
FILE *f;
#ifdef _WIN32
f = _wfopen(filename.c_str(), L"wb");
#else
f = fopen(filename.string().c_str(), "wb");
#endif
if (!f)
FError("Error opening {}: {}", filename, strerror(errno));
return {f, fclose};
}
qfile_t SafeOpenRead(const fs::path &filename, bool must_exist)
{
FILE *f;
#ifdef _WIN32
f = _wfopen(filename.c_str(), L"rb");
#else
f = fopen(filename.string().c_str(), "rb");
#endif
if (!f) {
if (must_exist)
FError("Error opening {}: {}", filename, strerror(errno));
return {nullptr, nullptr};
}
return {f, fclose};
}
size_t SafeRead(const qfile_t &f, void *buffer, size_t count)
{
if (fread(buffer, 1, count, f.get()) != (size_t)count)
FError("File read failure");
return count;
}
size_t SafeWrite(const qfile_t &f, const void *buffer, size_t count)
{
if (fwrite(buffer, 1, count, f.get()) != (size_t)count)
FError("File write failure");
return count;
}
void SafeSeek(const qfile_t &f, long offset, int32_t origin)
{
fseek(f.get(), offset, origin);
}
long SafeTell(const qfile_t &f)
{
return ftell(f.get());
}

View File

@ -352,7 +352,7 @@ struct fmt::formatter<bspversion_t>
}
// Q1-esque BSPs are printed as, ex, 29
return format_to(ctx.out(), "{}", v.version.value());
return format_to(ctx.out(), "{}", v.ident);
}
};

View File

@ -124,15 +124,6 @@ inline fs::path DefaultExtension(const fs::path &path, const fs::path &extension
return fs::path(path).replace_extension(extension);
}
using qfile_t = std::unique_ptr<FILE, decltype(&fclose)>;
qfile_t SafeOpenWrite(const fs::path &filename);
qfile_t SafeOpenRead(const fs::path &filename, bool must_exist = false);
size_t SafeRead(const qfile_t &f, void *buffer, size_t count);
size_t SafeWrite(const qfile_t &f, const void *buffer, size_t count);
void SafeSeek(const qfile_t &f, long offset, int32_t origin);
long SafeTell(const qfile_t &f);
#include <fmt/format.h>
// TODO: no wchar_t support in this version apparently

View File

@ -27,13 +27,17 @@ struct litheader_t
{
struct
{
char ident[4];
std::array<char, 4> ident = { 'Q', 'L', 'I', 'T' };
int version;
auto stream_data() { return std::tie(ident, version); }
} v1;
struct
{
int numsurfs;
int lmsamples;
auto stream_data() { return std::tie(numsurfs, lmsamples); }
} v2;
};

View File

@ -24,22 +24,25 @@
#include <unordered_map>
#include <vector>
#include <list>
#include <fstream>
#include "common/cmdlib.hh"
#include "common/fs.hh"
// Texture data stored for quick searching
struct texture_t
{
char name[16];
std::string name;
int width, height;
};
// WAD Format
struct wadinfo_t
{
char identification[4]; // should be WAD2
std::array<char, 4> identification; // should be WAD2
int numlumps;
int infotableofs;
auto stream_data() { return std::tie(identification, numlumps, infotableofs); }
};
struct lumpinfo_t
@ -50,7 +53,9 @@ struct lumpinfo_t
char type;
char compression;
char pad1, pad2;
char name[16]; // must be null terminated
std::array<char, 16> name; // must be null terminated
auto stream_data() { return std::tie(filepos, disksize, size, type, compression, pad1, pad2, name); }
};
struct wad_t
@ -59,7 +64,7 @@ struct wad_t
int version;
std::unordered_map<std::string, lumpinfo_t, case_insensitive_hash, case_insensitive_equal> lumps;
std::unordered_map<std::string, texture_t, case_insensitive_hash, case_insensitive_equal> textures;
qfile_t file = {nullptr, nullptr};
std::ifstream file;
};
void WADList_Init(const std::string_view &wadstring);

View File

@ -17,6 +17,8 @@
See file, 'COPYING', for details.
*/
#include <fstream>
#include <light/litfile.hh>
#include <light/light.hh>
@ -31,47 +33,38 @@ void WriteLitFile(const mbsp_t *bsp, facesup_t *facesup, const fs::path &filenam
fs::path litname = filename;
litname.replace_extension("lit");
header.v1.ident[0] = 'Q';
header.v1.ident[1] = 'L';
header.v1.ident[2] = 'I';
header.v1.ident[3] = 'T';
header.v1.version = LittleLong(version);
header.v2.numsurfs = LittleLong(bsp->dfaces.size());
header.v2.lmsamples = LittleLong(bsp->dlightdata.size());
header.v1.version = version;
header.v2.numsurfs = bsp->dfaces.size();
header.v2.lmsamples = bsp->dlightdata.size();
logging::print("Writing {}\n", litname);
auto litfile = SafeOpenWrite(litname);
SafeWrite(litfile, &header.v1, sizeof(header.v1));
std::ofstream litfile(litname, std::ios_base::out | std::ios_base::binary);
litfile <= header.v1;
if (version == 2) {
unsigned int i, j;
unsigned int *offsets = new unsigned int[bsp->dfaces.size()];
unsigned short *extents = new unsigned short[2 * bsp->dfaces.size()];
unsigned char *styles = new unsigned char[4 * bsp->dfaces.size()];
unsigned char *shifts = new unsigned char[bsp->dfaces.size()];
litfile <= header.v2;
for (i = 0; i < bsp->dfaces.size(); i++) {
offsets[i] = LittleLong(facesup[i].lightofs);
styles[i * 4 + 0] = LittleShort(facesup[i].styles[0]);
styles[i * 4 + 1] = LittleShort(facesup[i].styles[1]);
styles[i * 4 + 2] = LittleShort(facesup[i].styles[2]);
styles[i * 4 + 3] = LittleShort(facesup[i].styles[3]);
extents[i * 2 + 0] = LittleShort(facesup[i].extent[0]);
extents[i * 2 + 1] = LittleShort(facesup[i].extent[1]);
litfile <= facesup[i].lightofs;
for (int j = 0; j < 4; j++) {
litfile <= facesup[i].styles[j];
}
for (int j = 0; j < 2; j++) {
litfile <= facesup[i].extent[j];
}
j = 0;
while (nth_bit(j) < facesup[i].lmscale)
j++;
shifts[i] = j;
litfile <= (uint8_t) j;
}
SafeWrite(litfile, &header.v2, sizeof(header.v2));
SafeWrite(litfile, offsets, bsp->dfaces.size() * sizeof(*offsets));
SafeWrite(litfile, extents, 2 * bsp->dfaces.size() * sizeof(*extents));
SafeWrite(litfile, styles, 4 * bsp->dfaces.size() * sizeof(*styles));
SafeWrite(litfile, shifts, bsp->dfaces.size() * sizeof(*shifts));
SafeWrite(litfile, lit_filebase, bsp->dlightdata.size() * 3);
SafeWrite(litfile, lux_filebase, bsp->dlightdata.size() * 3);
} else
SafeWrite(litfile, lit_filebase, bsp->dlightdata.size() * 3);
litfile.write((const char *) lit_filebase, bsp->dlightdata.size() * 3);
litfile.write((const char *) lux_filebase, bsp->dlightdata.size() * 3);
}
else
litfile.write((const char *) lit_filebase, bsp->dlightdata.size() * 3);
}
#include <fstream>
void WriteLuxFile(const mbsp_t *bsp, const fs::path &filename, int version)
{
litheader_t header;
@ -79,13 +72,9 @@ void WriteLuxFile(const mbsp_t *bsp, const fs::path &filename, int version)
fs::path luxname = filename;
luxname.replace_extension("lux");
header.v1.ident[0] = 'Q';
header.v1.ident[1] = 'L';
header.v1.ident[2] = 'I';
header.v1.ident[3] = 'T';
header.v1.version = LittleLong(version);
header.v1.version = version;
auto luxfile = SafeOpenWrite(luxname);
SafeWrite(luxfile, &header.v1, sizeof(header.v1));
SafeWrite(luxfile, lux_filebase, bsp->dlightdata.size() * 3);
std::ofstream luxfile(luxname, std::ios_base::out | std::ios_base::binary);
luxfile <= header.v1;
luxfile.write((const char *) lux_filebase, bsp->dlightdata.size() * 3);
}

View File

@ -59,43 +59,47 @@ uint8_t thepalette[768] = // Quake palette
static bool WAD_LoadInfo(wad_t &wad, bool external)
{
wadinfo_t *hdr = &wad.header;
int i, len;
wadinfo_t &hdr = wad.header;
int i;
dmiptex_t miptex;
external |= options.notextures.value();
len = SafeRead(wad.file, hdr, sizeof(wadinfo_t));
if (len != sizeof(wadinfo_t))
wad.file >= hdr;
if (wad.file.bad())
return false;
wad.version = 0;
if (!strncmp(hdr->identification, "WAD2", 4))
if (!strncmp(hdr.identification.data(), "WAD2", 4))
wad.version = 2;
else if (!strncmp(hdr->identification, "WAD3", 4))
else if (!strncmp(hdr.identification.data(), "WAD3", 4))
wad.version = 3;
if (!wad.version)
return false;
SafeSeek(wad.file, hdr->infotableofs, SEEK_SET);
wad.file.seekg(hdr.infotableofs, std::ios_base::beg);
wad.lumps.reserve(wad.header.numlumps);
/* Get the dimensions and make a texture_t */
for (i = 0; i < wad.header.numlumps; i++) {
lumpinfo_t lump;
wad.file >= lump;
len = SafeRead(wad.file, &lump, sizeof(lump));
if (len != sizeof(lump))
if (wad.file.bad())
return false;
auto restore_pos = SafeTell(wad.file);
std::streampos restore_pos = wad.file.tellg();
wad.file.seekg(lump.filepos, std::ios_base::beg);
wad.file >= miptex;
miptex.name[15] = '\0'; // just in case we encounter a bad name
SafeSeek(wad.file, lump.filepos, SEEK_SET);
len = SafeRead(wad.file, &miptex, sizeof(miptex));
if (len == sizeof(miptex)) {
int w = LittleLong(miptex.width);
int h = LittleLong(miptex.height);
if (wad.file.bad()) {
lump.size = 0;
wad.lumps.insert({lump.name.data(), lump});
} else {
int w = miptex.width;
int h = miptex.height;
lump.size =
sizeof(miptex) + (w >> 0) * (h >> 0) + (w >> 1) * (h >> 1) + (w >> 2) * (h >> 2) + (w >> 3) * (h >> 3);
if (options.target_game->id == GAME_HALF_LIFE)
@ -103,8 +107,7 @@ static bool WAD_LoadInfo(wad_t &wad, bool external)
lump.size = (lump.size + 3) & ~3; // keep things aligned if we can.
texture_t tex;
memcpy(tex.name, miptex.name.data(), 16);
tex.name[15] = '\0';
tex.name = miptex.name.data();
tex.width = miptex.width;
tex.height = miptex.height;
wad.textures.insert({tex.name, tex});
@ -115,12 +118,9 @@ static bool WAD_LoadInfo(wad_t &wad, bool external)
// fmt::print("Created texture_t {} {} {}\n", tex->name, tex->width, tex->height);
wad.lumps.insert({tex.name, lump});
} else {
lump.size = 0;
wad.lumps.insert({lump.name, lump});
}
SafeSeek(wad.file, restore_pos, SEEK_SET);
wad.file.seekg(restore_pos, std::ios_base::beg);
}
return true;
@ -130,7 +130,7 @@ static void WADList_OpenWad(const fs::path &fpath, bool external)
{
wad_t wad;
wad.file = SafeOpenRead(fpath);
wad.file.open(fpath, std::ios_base::in | std::ios_base::binary);
if (wad.file) {
if (options.fVerbose)
@ -142,7 +142,7 @@ static void WADList_OpenWad(const fs::path &fpath, bool external)
}
logging::print("WARNING: {} isn't a wadfile\n", fpath);
wad.file.reset();
wad.file.close();
} else {
// Message?
}
@ -196,7 +196,7 @@ static const lumpinfo_t *WADList_FindTexture(const std::string &name)
return NULL;
}
static bool WAD_LoadLump(const wad_t &wad, const char *name, miptexhl_t &dest)
static bool WAD_LoadLump(wad_t &wad, const char *name, miptexhl_t &dest)
{
auto it = wad.lumps.find(name);
@ -207,7 +207,7 @@ static bool WAD_LoadLump(const wad_t &wad, const char *name, miptexhl_t &dest)
auto &lump = it->second;
SafeSeek(wad.file, lump.filepos, SEEK_SET);
wad.file.seekg(lump.filepos, std::ios_base::beg);
if (lump.disksize < sizeof(dmiptex_t)) {
logging::print("Wad texture {} is invalid", name);
@ -215,7 +215,8 @@ static bool WAD_LoadLump(const wad_t &wad, const char *name, miptexhl_t &dest)
}
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(lump.disksize);
size_t size = SafeRead(wad.file, buffer.get(), lump.disksize);
wad.file.read((char *) buffer.get(), lump.disksize);
size_t size = wad.file.gcount();
if (size != lump.disksize)
FError("Failure reading from file");

View File

@ -598,6 +598,8 @@ void CalcVis(mbsp_t *bsp)
// ===========================================================================
#include <fstream>
/*
============
LoadPortals
@ -605,26 +607,28 @@ void CalcVis(mbsp_t *bsp)
*/
static void LoadPortals(const fs::path &name, mbsp_t *bsp)
{
int i, j, count;
int i, j;
portal_t *p;
leaf_t *l;
char magic[80];
std::string magic;
int numpoints;
int leafnums[2];
qplane3d plane;
qfile_t f = SafeOpenRead(name, true);
std::ifstream f(name);
/*
* Parse the portal file header
*/
count = fscanf(f.get(), "%79s\n", magic);
if (count != 1)
FError("unknown header: {}\n", magic);
std::getline(f, magic);
if (magic.empty()) {
FError("unknown header/empty portal file {}\n", name);
}
if (!strcmp(magic, PORTALFILE)) {
count = fscanf(f.get(), "%i\n%i\n", &portalleafs, &numportals);
if (count != 2)
FError("unable to parse {} HEADER\n", PORTALFILE);
if (magic == PORTALFILE) {
f >> portalleafs >> numportals;
if (f.bad())
FError("unable to parse {} header\n", PORTALFILE);
if (bsp->loadversion->game->id == GAME_QUAKE_II) {
// since q2bsp has native cluster support, we shouldn't look at portalleafs_real at all.
@ -636,23 +640,25 @@ static void LoadPortals(const fs::path &name, mbsp_t *bsp)
logging::print("{:6} leafs\n", portalleafs);
logging::print("{:6} portals\n", numportals);
}
} else if (!strcmp(magic, PORTALFILE2)) {
count = fscanf(f.get(), "%i\n%i\n%i\n", &portalleafs_real, &portalleafs, &numportals);
if (count != 3)
FError("unable to parse {} HEADER\n", PORTALFILE);
} else if (magic == PORTALFILE2) {
if (bsp->loadversion->game->id == GAME_QUAKE_II) {
FError("{} can not be used with Q2\n", PORTALFILE2);
}
f >> portalleafs_real >> portalleafs >> numportals;
if (f.bad())
FError("unable to parse {} header\n", PORTALFILE);
logging::print("{:6} leafs\n", portalleafs_real);
logging::print("{:6} clusters\n", portalleafs);
logging::print("{:6} portals\n", numportals);
} else if (!strcmp(magic, PORTALFILEAM)) {
count = fscanf(f.get(), "%i\n%i\n%i\n", &portalleafs, &numportals, &portalleafs_real);
if (count != 3)
FError("unable to parse {} HEADER\n", PORTALFILE);
} else if (magic == PORTALFILEAM) {
if (bsp->loadversion->game->id == GAME_QUAKE_II) {
FError("{} can not be used with Q2\n", PORTALFILEAM);
}
f >> portalleafs >> numportals >> portalleafs_real;
if (f.bad())
FError("unable to parse {} header\n", PORTALFILE);
logging::print("{:6} leafs\n", portalleafs_real);
logging::print("{:6} clusters\n", portalleafs);
logging::print("{:6} portals\n", numportals);
@ -688,7 +694,8 @@ static void LoadPortals(const fs::path &name, mbsp_t *bsp)
vismap_end = vismap + bsp->dvis.bits.size();
for (i = 0, p = portals; i < numportals; i++) {
if (fscanf(f.get(), "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
f >> numpoints >> leafnums[0] >> leafnums[1];
if (f.bad())
FError("reading portal {}", i);
if (numpoints > MAX_WINDING)
FError("portal {} has too many points", i);
@ -698,10 +705,17 @@ static void LoadPortals(const fs::path &name, mbsp_t *bsp)
winding_t &w = *(p->winding = std::make_shared<winding_t>(numpoints));
for (j = 0; j < numpoints; j++) {
if (fscanf(f.get(), "(%lf %lf %lf ) ", &w[j][0], &w[j][1], &w[j][2]) != 3)
while (!f.bad() && f.get() != '(')
;
f >> w[j][0] >> w[j][1] >> w[j][2];
while (!f.bad() && f.get() != ')')
;
if (f.bad())
FError("reading portal {}", i);
}
fscanf(f.get(), "\n");
// calc plane
plane = w.plane();
@ -752,12 +766,12 @@ static void LoadPortals(const fs::path &name, mbsp_t *bsp)
return;
}
if (!strcmp(magic, PORTALFILE2)) {
if (magic == PORTALFILE2) {
for (i = 0; i < portalleafs; i++) {
while (1) {
int leafnum;
count = fscanf(f.get(), "%i", &leafnum);
if (!count || count == EOF)
f >> leafnum;
if (f.bad() || f.eof())
break;
if (leafnum < 0)
break;
@ -765,16 +779,16 @@ static void LoadPortals(const fs::path &name, mbsp_t *bsp)
FError("Invalid leaf number in cluster map ({} >= {})", leafnum, portalleafs_real);
bsp->dleafs[leafnum + 1].cluster = i;
}
if (count == EOF)
if (f.bad() || f.eof())
break;
}
if (i < portalleafs)
FError("Couldn't read cluster map ({} / {})\n", i, portalleafs);
} else if (!strcmp(magic, PORTALFILEAM)) {
} else if (magic == PORTALFILEAM) {
for (i = 0; i < portalleafs_real; i++) {
int clusternum;
count = fscanf(f.get(), "%i", &clusternum);
if (!count || count == EOF) {
f >> clusternum;
if (f.bad() || f.eof()) {
Error("Unexpected end of cluster map\n");
}
if (clusternum < 0 || clusternum >= portalleafs) {