2020// DEALINGS IN THE SOFTWARE.
2121//
2222
23+ using DiscUtils . Internal ;
24+ using DiscUtils . Streams ;
2325using System ;
2426using System . Collections . Generic ;
27+ using System . Collections . Immutable ;
28+ using System . Diagnostics . CodeAnalysis ;
2529using System . IO ;
26- using DiscUtils . Internal ;
27- using DiscUtils . Streams ;
30+ using System . Xml . Linq ;
31+ using System . Xml . XPath ;
32+ using static System . Net . WebRequestMethods ;
2833
2934namespace DiscUtils . Wim ;
3035
@@ -103,10 +108,45 @@ public string Manifest
103108 /// method is zero-based.</remarks>
104109 public WimFileSystem GetImage ( int index )
105110 {
106- return new WimFileSystem ( this , index ) ;
111+ var metaDataFileInfo = LocateImage ( index )
112+ ?? throw new ArgumentException ( $ "No such image: { index } ", nameof ( index ) ) ;
113+
114+ var metaDataStream = OpenResourceStream ( metaDataFileInfo ) ;
115+
116+ var volumeLabel = XDocument . Parse ( Manifest ) ? . XPathSelectElement ( $ "WIM/IMAGE[@INDEX=\" { index + 1 } \" ]/NAME") ? . Value ;
117+
118+ return new WimFileSystem ( this , metaDataStream , volumeLabel ) ;
119+ }
120+
121+ /// <summary>
122+ /// Gets a particular image within the file (zero-based index).
123+ /// </summary>
124+ /// <param name="index">The index of the image to retrieve.</param>
125+ /// <param name="wimFileSystem">The image as a file system.</param>
126+ /// <returns>True if index was found in the image and a file system
127+ /// was returned in <paramref name="wimFileSystem"/>, otherwise false.</returns>
128+ /// <remarks>The XML manifest file uses a one-based index, whereas this
129+ /// method is zero-based.</remarks>
130+ public bool TryGetImage ( int index , [ NotNullWhen ( true ) ] out WimFileSystem ? wimFileSystem )
131+ {
132+ var metaDataFileInfo = LocateImage ( index ) ;
133+
134+ if ( metaDataFileInfo is null )
135+ {
136+ wimFileSystem = null ;
137+ return false ;
138+ }
139+
140+ var metaDataStream = OpenResourceStream ( metaDataFileInfo ) ;
141+
142+ var volumeLabel = XDocument . Parse ( Manifest ) ? . XPathSelectElement ( $ "WIM/IMAGE[@INDEX=\" { index + 1 } \" ]/NAME") ? . Value ;
143+
144+ wimFileSystem = new WimFileSystem ( this , metaDataStream , volumeLabel ) ;
145+
146+ return true ;
107147 }
108148
109- internal ShortResourceHeader LocateImage ( int index )
149+ internal ShortResourceHeader ? LocateImage ( int index )
110150 {
111151 var i = 0 ;
112152
@@ -135,9 +175,9 @@ internal ShortResourceHeader LocateImage(int index)
135175 return null ;
136176 }
137177
138- internal ShortResourceHeader LocateResource ( byte [ ] hash )
178+ internal ShortResourceHeader ? LocateResource ( ImmutableArray < byte > hash )
139179 {
140- var hashHash = EndianUtilities . ToUInt32LittleEndian ( hash , 0 ) ;
180+ var hashHash = EndianUtilities . ToUInt32LittleEndian ( hash . AsSpan ( ) ) ;
141181
142182 if ( ! _resources . TryGetValue ( hashHash , out var headers ) )
143183 {
@@ -168,6 +208,7 @@ internal SparseStream OpenResourceStream(ShortResourceHeader hdr)
168208 _fileHeader . CompressionSize ) ;
169209 }
170210
211+ [ MemberNotNull ( nameof ( _resources ) ) ]
171212 private void ReadResourceTable ( )
172213 {
173214 _resources = [ ] ;
@@ -182,7 +223,7 @@ private void ReadResourceTable()
182223 var info = new ResourceInfo ( ) ;
183224 info . Read ( resBuffer ) ;
184225
185- var hashHash = EndianUtilities . ToUInt32LittleEndian ( info . Hash , 0 ) ;
226+ var hashHash = EndianUtilities . ToUInt32LittleEndian ( info . Hash . AsSpan ( ) ) ;
186227
187228 if ( ! _resources . TryGetValue ( hashHash , out var res ) )
188229 {
0 commit comments