Use Unicode-aware fopen and remove on Windows.
After this commit, SolveSpace can robustly handle non-ASCII filenames on every OS. Additionally, on Windows, filenames longer than 260 characeters can be used, and files on network shares can be opened directly, without mounting them as a network drive.pull/4/head
parent
97a9b4743e
commit
ba10a75a7d
|
@ -421,7 +421,7 @@ VectorFileWriter *VectorFileWriter::ForFile(const std::string &filename) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
FILE *f = fopen(filename.c_str(), "wb");
|
||||
FILE *f = ssfopen(filename, "wb");
|
||||
if(!f) {
|
||||
Error("Couldn't write to '%s'", filename.c_str());
|
||||
return NULL;
|
||||
|
@ -565,7 +565,7 @@ void SolveSpaceUI::ExportMeshTo(const std::string &filename) {
|
|||
return;
|
||||
}
|
||||
|
||||
FILE *f = fopen(filename.c_str(), "wb");
|
||||
FILE *f = ssfopen(filename, "wb");
|
||||
if(!f) {
|
||||
Error("Couldn't write to '%s'", filename.c_str());
|
||||
return;
|
||||
|
@ -996,7 +996,7 @@ void SolveSpaceUI::ExportAsPngTo(const std::string &filename) {
|
|||
SS.GW.Paint();
|
||||
SS.showToolbar = prevShowToolbar;
|
||||
|
||||
FILE *f = fopen(filename.c_str(), "wb");
|
||||
FILE *f = ssfopen(filename, "wb");
|
||||
if(!f) goto err;
|
||||
|
||||
png_struct *png_ptr; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
|
|
|
@ -305,7 +305,7 @@ void StepFileWriter::ExportSurfacesTo(const std::string &filename) {
|
|||
return;
|
||||
}
|
||||
|
||||
f = fopen(filename.c_str(), "wb");
|
||||
f = ssfopen(filename, "wb");
|
||||
if(!f) {
|
||||
Error("Couldn't write to '%s'", filename.c_str());
|
||||
return;
|
||||
|
|
10
src/file.cpp
10
src/file.cpp
|
@ -258,7 +258,7 @@ bool SolveSpaceUI::SaveToFile(const std::string &filename) {
|
|||
SS.ReloadAllImported();
|
||||
SS.GenerateAll(0, INT_MAX);
|
||||
|
||||
fh = fopen(filename.c_str(), "wb");
|
||||
fh = ssfopen(filename, "wb");
|
||||
if(!fh) {
|
||||
Error("Couldn't write to file '%s'", filename.c_str());
|
||||
return false;
|
||||
|
@ -424,7 +424,7 @@ bool SolveSpaceUI::LoadFromFile(const std::string &filename) {
|
|||
allConsistent = false;
|
||||
fileLoadError = false;
|
||||
|
||||
fh = fopen(filename.c_str(), "rb");
|
||||
fh = ssfopen(filename, "rb");
|
||||
if(!fh) {
|
||||
Error("Couldn't read from file '%s'", filename.c_str());
|
||||
return false;
|
||||
|
@ -509,7 +509,7 @@ bool SolveSpaceUI::LoadEntitiesFromFile(const std::string &filename, EntityList
|
|||
SSurface srf = {};
|
||||
SCurve crv = {};
|
||||
|
||||
fh = fopen(filename.c_str(), "rb");
|
||||
fh = ssfopen(filename, "rb");
|
||||
if(!fh) return false;
|
||||
|
||||
le->Clear();
|
||||
|
@ -787,7 +787,7 @@ void SolveSpaceUI::ReloadAllImported(void)
|
|||
g->impMesh.Clear();
|
||||
g->impShell.Clear();
|
||||
|
||||
FILE *test = fopen(g->impFile.c_str(), "rb");
|
||||
FILE *test = ssfopen(g->impFile, "rb");
|
||||
if(test) {
|
||||
fclose(test); // okay, exists
|
||||
} else {
|
||||
|
@ -796,7 +796,7 @@ void SolveSpaceUI::ReloadAllImported(void)
|
|||
if(!SS.saveFile.empty()) {
|
||||
std::string rel = PathSepUNIXToPlatform(g->impFileRel);
|
||||
std::string fromRel = MakePathAbsolute(SS.saveFile, rel);
|
||||
test = fopen(fromRel.c_str(), "rb");
|
||||
test = ssfopen(fromRel, "rb");
|
||||
if(test) {
|
||||
fclose(test);
|
||||
// It worked, this is our new absolute path
|
||||
|
|
|
@ -105,7 +105,7 @@ void SolveSpaceUI::Init() {
|
|||
bool SolveSpaceUI::LoadAutosaveFor(const std::string &filename) {
|
||||
std::string autosaveFile = filename + AUTOSAVE_SUFFIX;
|
||||
|
||||
FILE *f = fopen(autosaveFile.c_str(), "r");
|
||||
FILE *f = ssfopen(autosaveFile, "rb");
|
||||
if(!f)
|
||||
return false;
|
||||
fclose(f);
|
||||
|
@ -387,7 +387,7 @@ bool SolveSpaceUI::Autosave()
|
|||
void SolveSpaceUI::RemoveAutosave()
|
||||
{
|
||||
std::string autosaveFile = saveFile + AUTOSAVE_SUFFIX;
|
||||
remove(autosaveFile.c_str());
|
||||
ssremove(autosaveFile.c_str());
|
||||
}
|
||||
|
||||
bool SolveSpaceUI::OkayToStartNewFile(void) {
|
||||
|
@ -727,7 +727,7 @@ void SolveSpaceUI::MenuAnalyze(int id) {
|
|||
case GraphicsWindow::MNU_STOP_TRACING: {
|
||||
std::string exportFile;
|
||||
if(GetSaveFile(exportFile, CSV_EXT, CSV_PATTERN)) {
|
||||
FILE *f = fopen(exportFile.c_str(), "wb");
|
||||
FILE *f = ssfopen(exportFile, "wb");
|
||||
if(f) {
|
||||
int i;
|
||||
SContour *sc = &(SS.traced.path);
|
||||
|
|
|
@ -131,6 +131,9 @@ class RgbaColor;
|
|||
#define PATH_SEP "/"
|
||||
#endif
|
||||
|
||||
FILE *ssfopen(const std::string &filename, const char *mode);
|
||||
void ssremove(const std::string &filename);
|
||||
|
||||
#define MAX_RECENT 8
|
||||
#define RECENT_OPEN (0xf000)
|
||||
#define RECENT_IMPORT (0xf100)
|
||||
|
|
|
@ -376,7 +376,7 @@ void TextWindow::ScreenBackgroundImage(int link, uint32_t v) {
|
|||
|
||||
std::string importFile;
|
||||
if(!GetOpenFile(importFile, PNG_EXT, PNG_PATTERN)) goto err;
|
||||
f = fopen(importFile.c_str(), "rb");
|
||||
f = ssfopen(importFile, "rb");
|
||||
if(!f) goto err;
|
||||
|
||||
uint8_t header[8];
|
||||
|
|
|
@ -246,7 +246,7 @@ bool TtfFont::LoadFontFromFile(bool nameOnly) {
|
|||
|
||||
int i;
|
||||
|
||||
fh = fopen(fontFile.c_str(), "rb");
|
||||
fh = ssfopen(fontFile, "rb");
|
||||
if(!fh) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,18 @@ void dbp(const char *str, ...)
|
|||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
FILE *ssfopen(const std::string &filename, const char *mode)
|
||||
{
|
||||
if(filename.length() != strlen(filename.c_str())) oops();
|
||||
return fopen(filename.c_str(), mode);
|
||||
}
|
||||
|
||||
void ssremove(const std::string &filename)
|
||||
{
|
||||
if(filename.length() != strlen(filename.c_str())) oops();
|
||||
remove(filename.c_str());
|
||||
}
|
||||
|
||||
int64_t GetUnixTime(void)
|
||||
{
|
||||
time_t ret;
|
||||
|
|
|
@ -67,6 +67,26 @@ std::wstring Widen(const std::string &in)
|
|||
return out;
|
||||
}
|
||||
|
||||
FILE *ssfopen(const std::string &filename, const char *mode)
|
||||
{
|
||||
// Prepend \\?\ UNC prefix unless already an UNC path.
|
||||
// We never try to fopen paths that are not absolute or
|
||||
// contain separators inappropriate for the platform;
|
||||
// thus, it is always safe to prepend this prefix.
|
||||
std::string uncFilename = filename;
|
||||
if(uncFilename.substr(0, 2) != "\\\\")
|
||||
uncFilename = "\\\\?\\" + uncFilename;
|
||||
|
||||
if(filename.length() != strlen(filename.c_str())) oops();
|
||||
return _wfopen(Widen(uncFilename).c_str(), Widen(mode).c_str());
|
||||
}
|
||||
|
||||
void ssremove(const std::string &filename)
|
||||
{
|
||||
if(filename.length() != strlen(filename.c_str())) oops();
|
||||
_wremove(Widen(filename).c_str());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// A separate heap, on which we allocate expressions. Maybe a bit faster,
|
||||
// since no fragmentation issues whatsoever, and it also makes it possible
|
||||
|
|
Loading…
Reference in New Issue