@@ -495,11 +495,9 @@ void FArchive::Printf(const char *fmt, ...)
495
495
FFileArchive::FFileArchive (const char *Filename, unsigned InOptions)
496
496
: Options(InOptions)
497
497
, f(NULL )
498
- , FileSize(-1 )
499
498
, Buffer(NULL )
500
499
, BufferPos(0 )
501
500
, BufferSize(0 )
502
- , ArPos64(0 )
503
501
{
504
502
// process the filename
505
503
FullName = appStrdup (Filename);
@@ -514,40 +512,13 @@ FFileArchive::~FFileArchive()
514
512
appFree (const_cast <char *>(FullName));
515
513
}
516
514
517
- void FFileArchive::Seek (int Pos)
518
- {
519
- ArPos64 = Pos;
520
- }
521
-
522
- void FFileArchive::Seek64 (int64 Pos)
523
- {
524
- ArPos64 = Pos;
525
- }
526
-
527
- int FFileArchive::Tell () const
528
- {
529
- guard (FFileArchive::Tell ());
530
- return (int )ArPos64;
531
- unguard;
532
- }
533
-
534
- int64 FFileArchive::Tell64 () const
535
- {
536
- return ArPos64;
537
- }
538
-
539
515
int FFileArchive::GetFileSize () const
540
516
{
541
517
int64 size = GetFileSize64 ();
542
518
if (size >= (1LL << 31 )) appError (" GetFileSize returns 0x%llX" , size);
543
519
return (int )size;
544
520
}
545
521
546
- bool FFileArchive::IsEof () const
547
- {
548
- return ArPos64 >= GetFileSize64 ();
549
- }
550
-
551
522
// this function is useful only for FRO_NoOpenError mode
552
523
bool FFileArchive::IsOpen () const
553
524
{
@@ -570,7 +541,7 @@ bool FFileArchive::OpenFile()
570
541
guard (FFileArchive::OpenFile);
571
542
assert (!IsOpen ());
572
543
573
- ArPos64 = FilePos = 0 ;
544
+ FilePos = 0 ;
574
545
Buffer = (byte*)appMalloc (FILE_BUFFER_SIZE);
575
546
BufferPos = 0 ;
576
547
BufferSize = 0 ;
@@ -597,6 +568,10 @@ bool FFileArchive::OpenFile()
597
568
598
569
FFileReader::FFileReader (const char *Filename, unsigned InOptions)
599
570
: FFileArchive(Filename, InOptions)
571
+ , SeekPos(-1 )
572
+ , FileSize(-1 )
573
+ , BufferBytesLeft(0 )
574
+ , LocalReadPos(0 )
600
575
{
601
576
guard (FFileReader::FFileReader);
602
577
IsLoading = true ;
@@ -615,62 +590,79 @@ void FFileReader::Serialize(void *data, int size)
615
590
616
591
assert (data);
617
592
618
- if (ArStopper > 0 && ArPos64 + size > ArStopper)
619
- appError (" Serializing behind stopper (%llX+%X > %X)" , ArPos64 , size, ArStopper);
593
+ if (ArStopper > 0 && LocalReadPos + size > ArStopper - BufferPos )
594
+ appError (" Serializing behind stopper (%llX+%X > %X)" , BufferPos + LocalReadPos , size, ArStopper);
620
595
596
+ // The function is optimized for calling frequently with reading data from buffer
621
597
while (size > 0 )
622
598
{
623
- int64 LocalPos64 = ArPos64 - BufferPos;
624
- if (LocalPos64 < 0 || LocalPos64 >= BufferSize)
599
+ if (BufferBytesLeft > 0 )
625
600
{
626
- // seek to desired position if needed
627
- if (ArPos64 != FilePos)
601
+ // Use the buffer
602
+ byte* BufferPtr = Buffer + LocalReadPos;
603
+ int CanCopy = size > BufferBytesLeft ? BufferBytesLeft : size;
604
+ // Copy data. If we're copying 1-2-4 bytes, "special" code works faster than the case with memcpy.
605
+ switch (CanCopy)
628
606
{
629
- if (fseeko64 (f, ArPos64, SEEK_SET) != 0 )
630
- appError (" Error seeking to position 0x%llX" , ArPos64);
631
- FilePos = ArPos64;
607
+ case 1 :
608
+ *(byte*)data = *(BufferPtr);
609
+ break ;
610
+ case 2 :
611
+ *(uint16*)data = *(uint16*)BufferPtr;
612
+ break ;
613
+ case 4 :
614
+ *(uint32*)data = *(uint32*)BufferPtr;
615
+ break ;
616
+ default :
617
+ memcpy (data, BufferPtr, CanCopy);
632
618
}
633
- // the requested data is not in buffer
634
- if (size >= FILE_BUFFER_SIZE)
619
+ // Advance pointers
620
+ BufferBytesLeft -= CanCopy;
621
+ data = OffsetPointer (data, CanCopy);
622
+ size -= CanCopy;
623
+ LocalReadPos += CanCopy;
624
+ }
625
+ else
626
+ {
627
+ // Buffer is empty
628
+ if (SeekPos >= 0 )
629
+ {
630
+ // Seek to desired position
631
+ if (SeekPos != FilePos)
632
+ {
633
+ if (fseeko64 (f, SeekPos, SEEK_SET) != 0 )
634
+ appError (" Error seeking to position 0x%llX" , SeekPos);
635
+ FilePos = SeekPos;
636
+ }
637
+ SeekPos = -1 ;
638
+ }
639
+ if (size >= FILE_BUFFER_SIZE / 2 )
635
640
{
636
- // large block, read directly from file
641
+ // Large block, read directly to destination skipping buffer
637
642
int res = fread (data, size, 1 , f);
638
643
if (res != 1 )
639
- appError (" Unable to read %d bytes at pos=0x%llX" , size, ArPos64 );
644
+ appError (" Unable to read %d bytes at pos=0x%llX" , size, FilePos );
640
645
#if PROFILE
641
646
GNumSerialize++;
642
647
GSerializeBytes += size;
643
648
#endif
644
- ArPos64 += size;
645
649
FilePos += size;
646
650
return ;
647
651
}
648
- // fill buffer
652
+ // Fill buffer
649
653
int ReadBytes = fread (Buffer, 1 , FILE_BUFFER_SIZE, f);
650
654
if (ReadBytes == 0 )
651
- appError (" Unable to read %d bytes at pos=0x%llX" , 1 , ArPos64 );
655
+ appError (" Unable to read %d bytes at pos=0x%llX" , 1 , FilePos );
652
656
#if PROFILE
653
657
GNumSerialize++;
654
658
GSerializeBytes += ReadBytes;
655
659
#endif
656
660
BufferPos = FilePos;
657
661
BufferSize = ReadBytes;
658
662
FilePos += ReadBytes;
659
- // update LocalPos
660
- LocalPos64 = ArPos64 - BufferPos;
661
- assert (LocalPos64 >= 0 && LocalPos64 < BufferSize);
663
+ BufferBytesLeft = ReadBytes;
664
+ LocalReadPos = 0 ;
662
665
}
663
-
664
- // here we have 32-bit position in buffer
665
- int LocalPos = (int )LocalPos64;
666
-
667
- // have something in buffer
668
- int CanCopy = BufferSize - LocalPos;
669
- if (CanCopy > size) CanCopy = size;
670
- memcpy (data, Buffer + LocalPos, CanCopy);
671
- data = OffsetPointer (data, CanCopy);
672
- size -= CanCopy;
673
- ArPos64 += CanCopy;
674
666
}
675
667
676
668
unguardf (" File=%s" , ShortName);
@@ -681,6 +673,41 @@ bool FFileReader::Open()
681
673
return OpenFile ();
682
674
}
683
675
676
+ void FFileReader::Seek (int Pos)
677
+ {
678
+ Seek64 (Pos);
679
+ }
680
+
681
+ void FFileReader::Seek64 (int64 Pos)
682
+ {
683
+ // Check for buffer validity
684
+ int64 LocalPos64 = Pos - BufferPos;
685
+ if (LocalPos64 < 0 || LocalPos64 >= BufferSize)
686
+ {
687
+ // Outside of the buffer
688
+ BufferBytesLeft = 0 ;
689
+ // SeekPos will be reset to -1 after actual seek
690
+ SeekPos = Pos;
691
+ }
692
+ else
693
+ {
694
+ // Inside of the buffer, recompute number of bytes to the end
695
+ LocalReadPos = (int )LocalPos64;
696
+ BufferBytesLeft = BufferSize - LocalReadPos;
697
+ }
698
+ }
699
+
700
+ int FFileReader::Tell () const
701
+ {
702
+ assert ((BufferPos >> 32 ) == 0 );
703
+ return (int )BufferPos + LocalReadPos;
704
+ }
705
+
706
+ int64 FFileReader::Tell64 () const
707
+ {
708
+ return BufferPos + LocalReadPos;
709
+ }
710
+
684
711
int64 FFileReader::GetFileSize64 () const
685
712
{
686
713
// lazy file size computation
@@ -700,10 +727,17 @@ int64 FFileReader::GetFileSize64() const
700
727
return FileSize;
701
728
}
702
729
730
+ bool FFileReader::IsEof () const
731
+ {
732
+ return (BufferBytesLeft == 0 ) && (FilePos == GetFileSize64 ());
733
+ }
734
+
703
735
static TArray<FFileWriter*> GFileWriters;
704
736
705
737
FFileWriter::FFileWriter (const char *Filename, unsigned InOptions)
706
738
: FFileArchive(Filename, InOptions)
739
+ , FileSize(0 )
740
+ , ArPos64(0 )
707
741
{
708
742
guard (FFileWriter::FFileWriter);
709
743
IsLoading = false ;
@@ -798,6 +832,7 @@ bool FFileWriter::Open()
798
832
Buffer = (byte*)appMalloc (FILE_BUFFER_SIZE);
799
833
BufferPos = 0 ;
800
834
BufferSize = 0 ;
835
+ ArPos64 = 0 ;
801
836
return OpenFile ();
802
837
}
803
838
@@ -830,11 +865,36 @@ void FFileWriter::FlushBuffer()
830
865
}
831
866
}
832
867
868
+ void FFileWriter::Seek (int Pos)
869
+ {
870
+ ArPos64 = Pos;
871
+ }
872
+
873
+ void FFileWriter::Seek64 (int64 Pos)
874
+ {
875
+ ArPos64 = Pos;
876
+ }
877
+
878
+ int FFileWriter::Tell () const
879
+ {
880
+ return (int )ArPos64;
881
+ }
882
+
883
+ int64 FFileWriter::Tell64 () const
884
+ {
885
+ return ArPos64;
886
+ }
887
+
833
888
int64 FFileWriter::GetFileSize64 () const
834
889
{
835
890
return max (FileSize, FilePos + BufferSize);
836
891
}
837
892
893
+ bool FFileWriter::IsEof () const
894
+ {
895
+ return ArPos64 >= GetFileSize64 ();
896
+ }
897
+
838
898
839
899
/* -----------------------------------------------------------------------------
840
900
Dummy archive class
0 commit comments