@@ -784,6 +784,144 @@ public async Task<XivTex> GetType4Data(string internalPath, bool forceOriginal)
784
784
}
785
785
786
786
787
+ public async Task < int > GetCompressedFileSize ( int offset , XivDataFile dataFile )
788
+ {
789
+
790
+ var xivTex = new XivTex ( ) ;
791
+
792
+ var decompressedData = new List < byte > ( ) ;
793
+
794
+ // This formula is used to obtain the dat number in which the offset is located
795
+ var datNum = ( ( offset / 8 ) & 0x0F ) / 2 ;
796
+
797
+ await _semaphoreSlim . WaitAsync ( ) ;
798
+
799
+ try
800
+ {
801
+ offset = OffsetCorrection ( datNum , offset ) ;
802
+
803
+ var datPath = Path . Combine ( _gameDirectory . FullName , $ "{ dataFile . GetDataFileName ( ) } { DatExtension } { datNum } ") ;
804
+
805
+ return await Task . Run ( async ( ) =>
806
+ {
807
+ using ( var br = new BinaryReader ( File . OpenRead ( datPath ) ) )
808
+ {
809
+ br . BaseStream . Seek ( offset , SeekOrigin . Begin ) ;
810
+ var headerLength = br . ReadInt32 ( ) ;
811
+ var fileType = br . ReadInt32 ( ) ;
812
+ var uncompSize = br . ReadInt32 ( ) ;
813
+ var unknown = br . ReadInt32 ( ) ;
814
+ var maxBufferSize = br . ReadInt32 ( ) ;
815
+ var blockCount = br . ReadInt16 ( ) ;
816
+
817
+ var endOfHeader = offset + headerLength ;
818
+
819
+ if ( fileType != 2 && fileType != 3 && fileType != 4 )
820
+ {
821
+ throw new NotSupportedException ( "Cannot get compressed file size of unknown type." ) ;
822
+ }
823
+
824
+ int compSize = 0 ;
825
+ // Ok, time to parse the block headers and figure out how long the compressed data runs.
826
+ if ( fileType == 2 )
827
+ {
828
+ br . BaseStream . Seek ( endOfHeader + 4 , SeekOrigin . Begin ) ;
829
+ var lastSize = 0 ;
830
+ var lastOffset = 0 ;
831
+ for ( int i = 0 ; i < blockCount ; i ++ )
832
+ {
833
+ br . BaseStream . Seek ( offset + ( 24 + ( 8 * i ) ) , SeekOrigin . Begin ) ;
834
+ var blockOffset = br . ReadInt32 ( ) ;
835
+ var blockCompressedSize = br . ReadUInt16 ( ) ;
836
+
837
+ lastOffset = blockOffset ;
838
+ lastSize = blockCompressedSize ;
839
+ }
840
+
841
+ // Pretty straight forward. Header + Total size of the compressed data.
842
+ compSize = headerLength + lastOffset + lastSize ;
843
+
844
+ } else if ( fileType == 3 )
845
+ {
846
+
847
+ // 24 byte header, then 88 bytes to the first chunk offset.
848
+ br . BaseStream . Seek ( offset + 112 , SeekOrigin . Begin ) ;
849
+ var firstOffset = br . ReadInt32 ( ) ;
850
+
851
+ // 24 byte header, then 178 bytes to the start of the block count.
852
+ br . BaseStream . Seek ( offset + 178 , SeekOrigin . Begin ) ;
853
+
854
+ var totalBlocks = 0 ;
855
+ for ( var i = 0 ; i < 11 ; i ++ )
856
+ {
857
+ totalBlocks += br . ReadUInt16 ( ) ;
858
+ }
859
+
860
+
861
+ // 24 byte header, then 208 bytes to the list of block sizes.
862
+ br . BaseStream . Seek ( offset + 208 , SeekOrigin . Begin ) ;
863
+
864
+ var blockSizes = new int [ totalBlocks ] ;
865
+ for ( var i = 0 ; i < totalBlocks ; i ++ )
866
+ {
867
+ blockSizes [ i ] = br . ReadUInt16 ( ) ;
868
+ }
869
+
870
+ int totalCompressedSize = 0 ;
871
+ foreach ( var size in blockSizes )
872
+ {
873
+ totalCompressedSize += size ;
874
+ }
875
+
876
+
877
+ // Header + Chunk headers + compressed data.
878
+ compSize = headerLength + firstOffset + totalCompressedSize ;
879
+ } else if ( fileType == 4 )
880
+ {
881
+ br . BaseStream . Seek ( endOfHeader + 4 , SeekOrigin . Begin ) ;
882
+ // Textures.
883
+ var lastOffset = 0 ;
884
+ var lastSize = 0 ;
885
+ var mipMapInfoOffset = offset + 24 ;
886
+ for ( int i = 0 , j = 0 ; i < blockCount ; i ++ )
887
+ {
888
+ br . BaseStream . Seek ( mipMapInfoOffset + j , SeekOrigin . Begin ) ;
889
+
890
+ j = j + 20 ;
891
+
892
+ var offsetFromHeaderEnd = br . ReadInt32 ( ) ;
893
+ var mipMapCompressedSize = br . ReadInt32 ( ) ;
894
+
895
+
896
+ lastOffset = offsetFromHeaderEnd ;
897
+ lastSize = mipMapCompressedSize ;
898
+ }
899
+
900
+ // Pretty straight forward. Header + Total size of the compressed data.
901
+ compSize = headerLength + lastOffset + lastSize ;
902
+
903
+ }
904
+
905
+ // Fundamentally all files in the dat are padded out to the nearest 256 bytes.
906
+ // The DAT import functions actually add this for us normally, so it's not really
907
+ // necessary to treat it as part of the 'file size', but for completeness, it doesn't
908
+ // hurt to do so, and then it makes our file size match with the modlist entry file sizes.
909
+ if ( compSize % 256 != 0 )
910
+ {
911
+ var padding = 256 - ( compSize % 256 ) ;
912
+ compSize += padding ;
913
+ }
914
+ return compSize ;
915
+
916
+ }
917
+ } ) ;
918
+ }
919
+ finally
920
+ {
921
+ _semaphoreSlim . Release ( ) ;
922
+ }
923
+ }
924
+
787
925
/// <summary>
788
926
/// Gets the data for Type 4 (Texture) files.
789
927
/// </summary>
0 commit comments