Skip to content

Commit afc89a0

Browse files
committed
Various fixes:
* ucstat for wide filename support in Windows * True time_t stored in TCUserDefaults * Check for overrides of files in ldrawunf.zip
1 parent d94e13e commit afc89a0

17 files changed

+431
-70
lines changed

LDExporter/LDPovExporter.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <LDLoader/LDLCommentLine.h>
1212
#include <LDLoader/LDLPalette.h>
1313
#include <time.h>
14-
#include <sys/stat.h>
1514
#include <tinyxml.h>
1615
#include <TRE/TREGL.h>
1716
#include <TRE/TREShapeGroup.h>
@@ -1800,9 +1799,9 @@ std::string LDPovExporter::findInclude(const std::string &filename)
18001799
it != m_searchPath.end(); ++it)
18011800
{
18021801
std::string path = *it + filename;
1803-
struct stat statData;
1802+
TCStat statData;
18041803

1805-
if (stat(path.c_str(), &statData) == 0)
1804+
if (ucstat(path.c_str(), &statData) == 0)
18061805
{
18071806
if ((statData.st_mode & S_IFDIR) == 0)
18081807
{

LDLib/LDLibraryUpdater.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#include <TCFoundation/TCUnzip.h>
3333
#include <TCFoundation/TCLocalStrings.h>
3434
#include <fstream>
35-
#include <sys/stat.h>
3635

3736
#ifndef WIN32
3837
#include <sys/types.h>

LDLib/LDSnapshotTaker.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include <LDLoader/LDLModel.h>
1515
#include <TRE/TREGLExtensions.h>
1616
#include <gl2ps.h>
17-
#include <sys/stat.h>
1817
#include <cstdlib>
1918

2019
#ifdef WIN32
@@ -1421,8 +1420,8 @@ bool LDSnapshotTaker::writeImage(
14211420
std::string srcFilename = pathFromFileUri(m_fileUri);
14221421
comment += ":!:!:Thumb::URI:!:!:";
14231422
comment += m_fileUri;
1424-
struct stat statbuf;
1425-
if (stat(srcFilename.c_str(), &statbuf) == 0)
1423+
TCStat statbuf;
1424+
if (ucstat(srcFilename.c_str(), &statbuf) == 0)
14261425
{
14271426
comment += ":!:!:Thumb::MTime:!:!:";
14281427
char buf[1024];

LDLib/LDrawModelViewer.cpp

+8-18
Original file line numberDiff line numberDiff line change
@@ -4189,8 +4189,8 @@ void LDrawModelViewer::findFileAlertCallback(LDLFindFileAlert *alert)
41894189
webClient->release();
41904190
if (!tooManyRequests)
41914191
{
4192-
key = "UnofficialPartChecks/" + lfilename + "/LastUpdateCheckTime";
4193-
TCUserDefaults::setLongForKey((long)time(NULL), key.c_str(), false);
4192+
key = "UnofficialPartChecks/" + lfilename + "/LastUpdateCheckTimeS";
4193+
TCUserDefaults::setTimetForKey(time(NULL), key.c_str(), false);
41944194
if (!found)
41954195
{
41964196
unofficialPartNotFound(lfilename);
@@ -4230,17 +4230,7 @@ LDPartsList *LDrawModelViewer::getPartsList(void)
42304230
// NOTE: static function
42314231
bool LDrawModelViewer::fileExists(const std::string &filename)
42324232
{
4233-
FILE* file = ucfopen(filename.c_str(), "r");
4234-
4235-
if (file)
4236-
{
4237-
fclose(file);
4238-
return true;
4239-
}
4240-
else
4241-
{
4242-
return false;
4243-
}
4233+
return LDLModel::fileExists(filename);
42444234
}
42454235

42464236
// NOTE: static function
@@ -4341,15 +4331,15 @@ bool LDrawModelViewer::canCheckForUnofficialPart(const std::string &lfilename,
43414331

43424332
if (exists)
43434333
{
4344-
key = "UnofficialPartChecks/" + lfilename + "/LastUpdateCheckTime";
4334+
key = "UnofficialPartChecks/" + lfilename + "/LastUpdateCheckTimeS";
43454335
days = updatedPartWait;
43464336
}
43474337
else
43484338
{
4349-
key = "UnofficialPartChecks/" + lfilename + "/LastCheckTime";
4339+
key = "UnofficialPartChecks/" + lfilename + "/LastCheckTimeS";
43504340
days = missingPartWait;
43514341
}
4352-
lastCheck = (time_t)TCUserDefaults::longForKey(key.c_str(), 0, false);
4342+
lastCheck = TCUserDefaults::timetForKey(key.c_str(), 0, false);
43534343
if (days < 1)
43544344
{
43554345
days = 1;
@@ -4367,9 +4357,9 @@ void LDrawModelViewer::unofficialPartNotFound(const std::string &lfilename)
43674357
if (flags.checkPartTracker)
43684358
{
43694359
time_t now = time(NULL);
4370-
std::string key = "UnofficialPartChecks/" + lfilename + "/LastCheckTime";
4360+
std::string key = "UnofficialPartChecks/" + lfilename + "/LastCheckTimeS";
43714361

4372-
TCUserDefaults::setLongForKey((long)now, key.c_str(), false);
4362+
TCUserDefaults::setTimetForKey(now, key.c_str(), false);
43734363
}
43744364
}
43754365

LDLoader/LDLMainModel.cpp

+3-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <TCFoundation/TCStringArray.h>
55
#include <stdio.h>
66
#include <string.h>
7-
#include <sys/stat.h>
87
#include <TCFoundation/TCLocalStrings.h>
98
#include <TCFoundation/TCUserDefaults.h>
109
#include "LDrawIni.h"
@@ -113,9 +112,9 @@ bool LDLMainModel::load(const char *filename)
113112
{
114113
std::string lDrawDirString = lDrawDir();
115114
bool failed = false;
116-
struct stat statData;
115+
TCStat statData;
117116

118-
if (stat((lDrawDirString + "/P").c_str(), &statData) != 0)
117+
if (ucstat((lDrawDirString + "/P").c_str(), &statData) != 0)
119118
{
120119
// Check to see if we can access the P directory inside the
121120
// LDraw directory. If not, then we have a problem that
@@ -124,7 +123,7 @@ bool LDLMainModel::load(const char *filename)
124123
}
125124
if (!failed)
126125
{
127-
if (stat((lDrawDirString + "/PARTS").c_str(), &statData) != 0)
126+
if (ucstat((lDrawDirString + "/PARTS").c_str(), &statData) != 0)
128127
{
129128
// Check to see if we can access the PARTS directory
130129
// inside the LDraw directory. If not, then we have a

LDLoader/LDLModel.cpp

+165-15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <TCFoundation/TCUserDefaults.h>
1414
#include <TCFoundation/TCImage.h>
1515
#include <TCFoundation/TCUnzipStream.h>
16+
#include <TCFoundation/TCWebClient.h>
1617
#include <math.h>
1718

1819
#ifdef WIN32
@@ -81,11 +82,13 @@ LDLModel::LDLModel(void)
8182
m_texmapImage(NULL),
8283
m_dataLine(NULL)
8384
{
85+
memset(&m_flags, 0, sizeof(m_flags));
8486
// Initialize Private flags
8587
m_flags.loadingPart = false;
8688
m_flags.loadingSubPart = false;
8789
m_flags.loadingPrimitive = false;
8890
m_flags.loadingUnoffic = false;
91+
m_flags.loadingFoundFile = false;
8992
m_flags.mainModelLoaded = false;
9093
m_flags.mainModelParsed = false;
9194
m_flags.started = false;
@@ -325,8 +328,10 @@ LDLModel *LDLModel::subModelNamed(const char *subModelName, bool lowRes,
325328
TCAlertManager::sendAlert(alert, this);
326329
if (alert->getFileFound())
327330
{
331+
m_flags.loadingFoundFile = true;
328332
subModel = subModelNamed(alert->getFilename().c_str(), lowRes,
329333
true, fileLine, alert->getPartFlag());
334+
m_flags.loadingFoundFile = false;
330335
if (subModel)
331336
{
332337
// The following is necessary in order for primitive
@@ -405,11 +410,110 @@ bool LDLModel::isInLDrawDir(const std::string& filename)
405410
#endif // WIN32
406411
}
407412

413+
// NOTE: static function
414+
bool LDLModel::fileExists(const std::string &filename)
415+
{
416+
#ifdef HAVE_MINIZIP
417+
if (sm_ldrawZip != NULL &&
418+
sm_systemLDrawDir != NULL &&
419+
isInLDrawDir(filename))
420+
{
421+
std::string lfilename = lowerCaseString(filename);
422+
TCUnzipStream zipStream;
423+
std::string partPath = &lfilename[strlen(sm_systemLDrawDir) + 1];
424+
if (stringHasPrefix(partPath, "unofficial/"))
425+
{
426+
if (sm_unoffZip != NULL)
427+
{
428+
partPath = partPath.substr(11);
429+
time_t localTimestamp = getLocalTimestamp(partPath);
430+
if (zipStream.getTimestamp(sm_unoffZipPath, sm_unoffZip, partPath) >= localTimestamp)
431+
{
432+
return true;
433+
}
434+
}
435+
}
436+
else
437+
{
438+
if (zipStream.getTimestamp(sm_ldrawZipPath, sm_ldrawZip, partPath) != 0)
439+
{
440+
return true;
441+
}
442+
}
443+
}
444+
#endif // HAVE_MINIZIP
445+
FILE* file = ucfopen(filename.c_str(), "r");
446+
447+
if (file)
448+
{
449+
fclose(file);
450+
return true;
451+
}
452+
else
453+
{
454+
return false;
455+
}
456+
}
457+
458+
// NOTE: static function
459+
std::string LDLModel::getLastModifiedKey(const std::string& lfilename)
460+
{
461+
size_t slashSpot = lfilename.find('/');
462+
std::string partName = lfilename;
463+
if (slashSpot != lfilename.npos)
464+
{
465+
partName = lfilename.substr(slashSpot + 1);
466+
}
467+
return "UnofficialPartChecks/" + partName + "/LastModified";
468+
}
469+
470+
time_t LDLModel::getFileTimestamp(const std::string& path)
471+
{
472+
time_t result = 0;
473+
TCStat statBuf;
474+
if (ucstat(path.c_str(), &statBuf) == 0)
475+
{
476+
#if (!defined(_POSIX_C_SOURCE) && !defined(_POSIX_SOURCE) && !defined(WIN32)) || defined(_DARWIN_C_SOURCE)
477+
result = statBuf.st_mtimespec.tv_sec;
478+
#else
479+
result = statBuf.st_mtime;
480+
#endif
481+
}
482+
return result;
483+
}
484+
485+
// NOTE: static function
486+
time_t LDLModel::getLocalTimestamp(const std::string& lfilename)
487+
{
488+
std::string lastModifiedKey = getLastModifiedKey(lfilename);
489+
char *localLastModified = TCUserDefaults::stringForKey(lastModifiedKey.c_str(), NULL, false);
490+
time_t localTimestamp = 0;
491+
if (localLastModified != NULL)
492+
{
493+
localTimestamp = TCWebClient::scanDateString(localLastModified);
494+
delete[] localLastModified;
495+
}
496+
if (localTimestamp == 0)
497+
{
498+
std::string base;
499+
combinePath(lDrawDir(), "Unofficial", base);
500+
std::string path;
501+
combinePath(base, lfilename, path);
502+
localTimestamp = getFileTimestamp(path);
503+
if (localTimestamp == 0 && fileCaseCallback != NULL && fileCaseCallback(&path[0]))
504+
{
505+
localTimestamp = getFileTimestamp(path);
506+
}
507+
}
508+
return localTimestamp;
509+
}
510+
408511
// NOTE: static function
409512
bool LDLModel::openFile(
410513
std::string &filename,
411514
std::ifstream &modelStream,
412-
TCUnzipStream *zipStream)
515+
TCUnzipStream *zipStream,
516+
bool canLoadUnofficial)
413517
{
414518
std::string lfilename = lowerCaseString(filename);
415519
#ifdef HAVE_MINIZIP
@@ -419,22 +523,66 @@ bool LDLModel::openFile(
419523
isInLDrawDir(filename))
420524
{
421525
std::string partPath = &lfilename[strlen(sm_systemLDrawDir) + 1];
422-
std::string zipPath = std::string("ldraw/") + partPath;
423-
if (zipStream->load(sm_ldrawZipPath, sm_ldrawZip, zipPath))
526+
if (stringHasPrefix(partPath, "unofficial/"))
424527
{
425-
filename = sm_ldrawZipPath + ":" + zipPath;
426-
return true;
427-
}
428-
if (sm_unoffZip != NULL &&
429-
zipStream->load(sm_unoffZipPath, sm_unoffZip, partPath))
430-
{
431-
filename = sm_unoffZipPath + ":" + partPath;
432-
return true;
528+
if (sm_unoffZip != NULL)
529+
{
530+
partPath = partPath.substr(11);
531+
time_t zipTimestamp = zipStream->getTimestamp(sm_unoffZipPath, sm_unoffZip, partPath);
532+
if (zipTimestamp != 0)
533+
{
534+
time_t localTimestamp = getLocalTimestamp(partPath);
535+
std::string origPartPath = &filename[strlen(sm_systemLDrawDir) + 1];
536+
// The main part loading calls this function with
537+
// canLoadUnofficial set to false if unofficial downloads
538+
// are enabled. We then look in ldrawunf.zip to see if it
539+
// contains the file. If it does, and we don't already have
540+
// a downloaded file in the Unofficial directory that is
541+
// newer, we store the timestamp from the zip in
542+
// TCUserDefaults and return.
543+
// Later on, the Unofficial download code calls this with
544+
// canLoadUnofficial set to true. At that point we'll load
545+
// the file from the zip if it is at least as new as the
546+
// stored timestamp for the file, or load the file from the
547+
// disk otherwise.
548+
if (!canLoadUnofficial)
549+
{
550+
if (zipTimestamp > localTimestamp)
551+
{
552+
char* rfc822 = TCWebClient::toRfc822(zipTimestamp);
553+
if (rfc822 != NULL)
554+
{
555+
std::string lastModifiedKey = getLastModifiedKey(partPath);
556+
TCUserDefaults::setStringForKey(rfc822, lastModifiedKey.c_str(), false);
557+
delete[] rfc822;
558+
}
559+
}
560+
return false;
561+
}
562+
else if (zipTimestamp >= localTimestamp)
563+
{
564+
if (zipStream->load(sm_unoffZipPath, sm_unoffZip, partPath))
565+
{
566+
filename = sm_unoffZipPath + ":" + partPath;
567+
return true;
568+
}
569+
}
570+
}
571+
}
433572
}
434-
if (stringHasPrefix(partPath, "p/") ||
435-
stringHasPrefix(partPath, "parts/"))
573+
else
436574
{
437-
return false;
575+
std::string zipPath = std::string("ldraw/") + partPath;
576+
if (zipStream->load(sm_ldrawZipPath, sm_ldrawZip, zipPath))
577+
{
578+
filename = sm_ldrawZipPath + ":" + zipPath;
579+
return true;
580+
}
581+
if (stringHasPrefix(partPath, "p/") ||
582+
stringHasPrefix(partPath, "parts/"))
583+
{
584+
return false;
585+
}
438586
}
439587
}
440588
#endif // HAVE_MINIZIP
@@ -473,7 +621,7 @@ bool LDLModel::openModelFile(
473621
bool isText,
474622
bool knownPart /*= false*/)
475623
{
476-
if (openFile(filename, modelStream, zipStream))
624+
if (openFile(filename, modelStream, zipStream, m_flags.loadingFoundFile || !m_mainModel->getCheckPartTracker()))
477625
{
478626
if (knownPart)
479627
{
@@ -554,6 +702,8 @@ bool LDLModel::openSubModelNamed(
554702
dirs.push_back(std::make_pair<std::string, LDrawSearchDirS*>(root + "/p", NULL));
555703
dirs.push_back(std::make_pair<std::string, LDrawSearchDirS*>(root + "/parts", NULL));
556704
dirs.push_back(std::make_pair<std::string, LDrawSearchDirS*>(root + "/models", NULL));
705+
dirs.push_back(std::make_pair<std::string, LDrawSearchDirS*>(root + "/unofficial/p", NULL));
706+
dirs.push_back(std::make_pair<std::string, LDrawSearchDirS*>(root + "/unofficial/parts", NULL));
557707
}
558708
#endif // HAVE_MINIZIP
559709
if (sm_lDrawIni != NULL && sm_lDrawIni->nSearchDirs > 0)

0 commit comments

Comments
 (0)