@@ -626,7 +626,7 @@ public byte[] GetBytes(string entryName, ReadSource readSource)
626626 /// <param name="entryName">The name of the entry to get the stream for.</param>
627627 /// <param name="readSource">The source from which to read the data.</param>
628628 /// <returns>A read-only stream for the entry.</returns>
629- public Stream GetStream ( string entryName , ReadSource readSource = ReadSource . Both )
629+ public Stream GetStream ( string entryName , ReadSource readSource = ReadSource . Automatic )
630630 {
631631 Ensure . String . IsNotNullOrEmpty ( entryName . Trim ( ) , nameof ( entryName ) ) ;
632632
@@ -642,14 +642,11 @@ public Stream GetStream(string entryName, ReadSource readSource = ReadSource.Bot
642642 Logger . LogDebug ( "Entry {name} not found in cache" , entryName ) ;
643643 }
644644
645- if ( ! CheckEntryNameSecurity ( entryName , false ) )
646- {
647- readSource = ReadSource . Bundle ;
648- }
645+ readSource = GetReadSource ( entryName , readSource ) ;
649646
650647 Stream stream ;
651648
652- if ( readSource != ReadSource . Disk && ( readSource == ReadSource . Bundle || Manifest . StoreOriginalFiles ) )
649+ if ( readSource == ReadSource . Bundle )
653650 {
654651 Logger . LogDebug ( "Reading file: {name} from the bundle" , entryName ) ;
655652
@@ -669,6 +666,71 @@ public Stream GetStream(string entryName, ReadSource readSource = ReadSource.Bot
669666 return stream ;
670667 }
671668
669+ /// <summary>
670+ /// Checks whether an entry exists in the bundle or on the disk.
671+ /// </summary>
672+ /// <param name="entryName">
673+ /// The name of the entry to check.
674+ /// </param>
675+ /// <param name="readSource">
676+ /// The source from which to check the entry.
677+ /// </param>
678+ /// <returns>
679+ /// <see langword="true"/> if the entry exists; otherwise, <see langword="false"/>.
680+ /// </returns>
681+ public bool Exists ( string entryName , ReadSource readSource = ReadSource . Automatic )
682+ {
683+ Ensure . String . IsNotNullOrEmpty ( entryName , nameof ( entryName ) ) ;
684+
685+ Logger . LogInformation ( "Checking if entry {entryName} exists" , entryName ) ;
686+
687+ bool result ;
688+ readSource = GetReadSource ( entryName , readSource ) ;
689+
690+ if ( readSource == ReadSource . Bundle )
691+ {
692+ using ZipArchive zip = GetZipArchive ( ) ;
693+ result = zip . GetEntry ( entryName ) != null ;
694+ }
695+ else
696+ {
697+ string path = Path . GetFullPath ( entryName , RootPath ) ;
698+ result = File . Exists ( path ) ;
699+ }
700+
701+ Logger . LogInformation ( "Entry {entryName} exists: {result}" , entryName , result ) ;
702+ return result ;
703+ }
704+
705+ /// <summary>
706+ /// Gets the read source for an entry name.
707+ /// </summary>
708+ /// <param name="entryName">
709+ /// The name of the entry to get the read source for.
710+ /// </param>
711+ /// <param name="readSource">
712+ /// The suggested read source.
713+ /// </param>
714+ /// <returns>
715+ /// The read source for the entry name based on protected entry names and bundle properties.
716+ /// </returns>
717+ protected ReadSource GetReadSource ( string entryName , ReadSource readSource = ReadSource . Automatic )
718+ {
719+ Ensure . String . IsNotNullOrEmpty ( entryName , nameof ( entryName ) ) ;
720+
721+ if ( ! CheckEntryNameSecurity ( entryName , false ) )
722+ {
723+ readSource = ReadSource . Bundle ;
724+ }
725+
726+ if ( readSource == ReadSource . Automatic )
727+ {
728+ readSource = Manifest . StoreOriginalFiles ? ReadSource . Bundle : ReadSource . Disk ;
729+ }
730+
731+ return readSource ;
732+ }
733+
672734 /// <summary>
673735 /// Writes changes to the bundle file.
674736 /// </summary>
0 commit comments