13
13
#include < TCFoundation/TCUserDefaults.h>
14
14
#include < TCFoundation/TCImage.h>
15
15
#include < TCFoundation/TCUnzipStream.h>
16
+ #include < TCFoundation/TCWebClient.h>
16
17
#include < math.h>
17
18
18
19
#ifdef WIN32
@@ -81,11 +82,13 @@ LDLModel::LDLModel(void)
81
82
m_texmapImage(NULL ),
82
83
m_dataLine(NULL )
83
84
{
85
+ memset (&m_flags, 0 , sizeof (m_flags));
84
86
// Initialize Private flags
85
87
m_flags.loadingPart = false ;
86
88
m_flags.loadingSubPart = false ;
87
89
m_flags.loadingPrimitive = false ;
88
90
m_flags.loadingUnoffic = false ;
91
+ m_flags.loadingFoundFile = false ;
89
92
m_flags.mainModelLoaded = false ;
90
93
m_flags.mainModelParsed = false ;
91
94
m_flags.started = false ;
@@ -325,8 +328,10 @@ LDLModel *LDLModel::subModelNamed(const char *subModelName, bool lowRes,
325
328
TCAlertManager::sendAlert (alert, this );
326
329
if (alert->getFileFound ())
327
330
{
331
+ m_flags.loadingFoundFile = true ;
328
332
subModel = subModelNamed (alert->getFilename ().c_str (), lowRes,
329
333
true , fileLine, alert->getPartFlag ());
334
+ m_flags.loadingFoundFile = false ;
330
335
if (subModel)
331
336
{
332
337
// The following is necessary in order for primitive
@@ -405,11 +410,110 @@ bool LDLModel::isInLDrawDir(const std::string& filename)
405
410
#endif // WIN32
406
411
}
407
412
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
+
408
511
// NOTE: static function
409
512
bool LDLModel::openFile (
410
513
std::string &filename,
411
514
std::ifstream &modelStream,
412
- TCUnzipStream *zipStream)
515
+ TCUnzipStream *zipStream,
516
+ bool canLoadUnofficial)
413
517
{
414
518
std::string lfilename = lowerCaseString (filename);
415
519
#ifdef HAVE_MINIZIP
@@ -419,22 +523,66 @@ bool LDLModel::openFile(
419
523
isInLDrawDir (filename))
420
524
{
421
525
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/" ))
424
527
{
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
+ }
433
572
}
434
- if (stringHasPrefix (partPath, " p/" ) ||
435
- stringHasPrefix (partPath, " parts/" ))
573
+ else
436
574
{
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
+ }
438
586
}
439
587
}
440
588
#endif // HAVE_MINIZIP
@@ -473,7 +621,7 @@ bool LDLModel::openModelFile(
473
621
bool isText,
474
622
bool knownPart /* = false*/ )
475
623
{
476
- if (openFile (filename, modelStream, zipStream))
624
+ if (openFile (filename, modelStream, zipStream, m_flags. loadingFoundFile || !m_mainModel-> getCheckPartTracker () ))
477
625
{
478
626
if (knownPart)
479
627
{
@@ -554,6 +702,8 @@ bool LDLModel::openSubModelNamed(
554
702
dirs.push_back (std::make_pair<std::string, LDrawSearchDirS*>(root + " /p" , NULL ));
555
703
dirs.push_back (std::make_pair<std::string, LDrawSearchDirS*>(root + " /parts" , NULL ));
556
704
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 ));
557
707
}
558
708
#endif // HAVE_MINIZIP
559
709
if (sm_lDrawIni != NULL && sm_lDrawIni->nSearchDirs > 0 )
0 commit comments