@@ -92,27 +92,59 @@ private static void ResolveNetworkLink(NetworkLink networkLink, List<Coordinates
9292 if ( string . IsNullOrWhiteSpace ( href ) )
9393 return ;
9494
95+ // Step 1: URI-based detection — check AbsolutePath for .kmz/.kml suffix
96+ bool ? isKmzFromUri = null ;
97+ if ( Uri . TryCreate ( href , UriKind . Absolute , out Uri uri ) )
98+ {
99+ var path = uri . AbsolutePath ;
100+ if ( path . EndsWith ( ".kmz" , StringComparison . OrdinalIgnoreCase ) )
101+ isKmzFromUri = true ;
102+ else if ( path . EndsWith ( ".kml" , StringComparison . OrdinalIgnoreCase ) )
103+ isKmzFromUri = false ;
104+ }
105+
95106 using ( var httpClient = new HttpClient { Timeout = System . TimeSpan . FromSeconds ( 30 ) } )
107+ using ( var response = httpClient . GetAsync ( href ) . GetAwaiter ( ) . GetResult ( ) )
96108 {
97- var response = httpClient . GetAsync ( href ) . GetAwaiter ( ) . GetResult ( ) ;
98109 if ( ! response . IsSuccessStatusCode )
99110 return ;
100111
101- using ( var stream = response . Content . ReadAsStreamAsync ( ) . GetAwaiter ( ) . GetResult ( ) )
112+ // Step 2: Content-Type detection — fallback when URI is inconclusive
113+ bool ? isKmzFromContentType = null ;
114+ var contentType = response . Content . Headers . ContentType ? . MediaType ;
115+ if ( string . Equals ( contentType , "application/vnd.google-earth.kmz" , StringComparison . OrdinalIgnoreCase ) )
116+ isKmzFromContentType = true ;
117+ else if ( string . Equals ( contentType , "application/vnd.google-earth.kml+xml" , StringComparison . OrdinalIgnoreCase ) )
118+ isKmzFromContentType = false ;
119+
120+ // Download into memory so we can peek bytes and re-read for parsing
121+ var contentBytes = response . Content . ReadAsByteArrayAsync ( ) . GetAwaiter ( ) . GetResult ( ) ;
122+
123+ // Step 3: ZIP magic-byte detection — final fallback
124+ bool ? isKmzFromMagic = null ;
125+ if ( contentBytes . Length >= 4 )
102126 {
103- bool isKmz = href . EndsWith ( ".kmz" , StringComparison . OrdinalIgnoreCase ) ;
127+ // PK\x03\x04 is the ZIP magic number
128+ isKmzFromMagic = contentBytes [ 0 ] == 0x50 && contentBytes [ 1 ] == 0x4B
129+ && contentBytes [ 2 ] == 0x03 && contentBytes [ 3 ] == 0x04 ;
130+ }
104131
132+ // Precedence: URI suffix > Content-Type header > magic bytes; default to false
133+ bool isKmz = isKmzFromUri ?? isKmzFromContentType ?? isKmzFromMagic ?? false ;
134+
135+ using ( var ms = new MemoryStream ( contentBytes ) )
136+ {
105137 KmlFile file ;
106138 if ( isKmz )
107139 {
108- var kmz = KmzFile . Open ( stream ) ;
140+ var kmz = KmzFile . Open ( ms ) ;
109141 file = kmz ? . GetDefaultKmlFile ( ) ;
110142 if ( file == null )
111143 return ;
112144 }
113145 else
114146 {
115- file = KmlFile . Load ( stream ) ;
147+ file = KmlFile . Load ( ms ) ;
116148 }
117149
118150 if ( file ? . Root is Kml kml )
0 commit comments