@@ -401,32 +401,63 @@ public PackagePartCollection GetParts()
401
401
402
402
PackUriHelper . ValidatedPartUri partUri ;
403
403
404
+ var uriComparer = Comparer < PackUriHelper . ValidatedPartUri > . Default ;
405
+
406
+ //Sorting the parts array which takes O(n log n) time.
407
+ Array . Sort ( parts , Comparer < PackagePart > . Create ( ( partA , partB ) => uriComparer . Compare ( ( PackUriHelper . ValidatedPartUri ) partA . Uri , ( PackUriHelper . ValidatedPartUri ) partB . Uri ) ) ) ;
408
+
404
409
//We need this dictionary to detect any collisions that might be present in the
405
410
//list of parts that was given to us from the underlying physical layer, as more than one
406
411
//partnames can be mapped to the same normalized part.
407
412
//Note: We cannot use the _partList member variable, as that gets updated incrementally and so its
408
413
//not possible to find the collisions using that list.
409
414
//PackUriHelper.ValidatedPartUri implements the IComparable interface.
410
- Dictionary < PackUriHelper . ValidatedPartUri , PackagePart > seenPartUris = new Dictionary < PackUriHelper . ValidatedPartUri , PackagePart > ( parts . Length ) ;
415
+ Dictionary < string , KeyValuePair < PackUriHelper . ValidatedPartUri , PackagePart > > partDictionary = new Dictionary < string , KeyValuePair < PackUriHelper . ValidatedPartUri , PackagePart > > ( parts . Length ) ;
416
+ List < string > partIndex = new List < string > ( parts . Length ) ;
411
417
412
418
for ( int i = 0 ; i < parts . Length ; i ++ )
413
419
{
414
420
partUri = ( PackUriHelper . ValidatedPartUri ) parts [ i ] . Uri ;
415
421
416
- if ( seenPartUris . ContainsKey ( partUri ) )
422
+ string normalizedPartName = partUri . NormalizedPartUriString ;
423
+
424
+ if ( partDictionary . ContainsKey ( normalizedPartName ) )
425
+ {
417
426
throw new FileFormatException ( SR . BadPackageFormat ) ;
427
+ }
418
428
else
419
429
{
420
- // Add the part to the list of URIs that we have already seen
421
- seenPartUris . Add ( partUri , parts [ i ] ) ;
430
+ //since we will arive to this line of code after the parts are already sorted
431
+ string ? precedingPartName = null ;
432
+
433
+ if ( partIndex . Count > 0 )
434
+ {
435
+ precedingPartName = ( partIndex [ partIndex . Count - 1 ] ) ;
436
+ }
437
+
438
+ // Add the part to the dictionary
439
+ partDictionary . Add ( normalizedPartName , new KeyValuePair < PackUriHelper . ValidatedPartUri , PackagePart > ( partUri , parts [ i ] ) ) ;
422
440
423
- if ( ! _partList . ContainsKey ( partUri ) )
441
+ if ( precedingPartName != null
442
+ && normalizedPartName . StartsWith ( precedingPartName , StringComparison . Ordinal )
443
+ && normalizedPartName . Length > precedingPartName . Length
444
+ && normalizedPartName [ precedingPartName . Length ] == PackUriHelper . ForwardSlashChar )
424
445
{
425
- // Add the part to the _partList if there is no prefix collision
426
- AddIfNoPrefixCollisionDetected ( partUri , parts [ i ] ) ;
446
+ //Removing the invalid entry from the _partList.
447
+ partDictionary . Remove ( normalizedPartName ) ;
448
+
449
+ throw new InvalidOperationException ( SR . PartNamePrefixExists ) ;
427
450
}
451
+
452
+ //adding entry to partIndex to keep track of last element being added.
453
+ //since parts are already sorted, last element in partIndex list will point to preceeding element to the current.
454
+ partIndex . Add ( partUri . NormalizedPartUriString ) ;
428
455
}
429
456
}
457
+
458
+ //copying parts from partdictionary to partlist
459
+ CopyPartDicitonaryToPartList ( partDictionary , partIndex ) ;
460
+
430
461
_partCollection = new PackagePartCollection ( _partList ) ;
431
462
}
432
463
return _partCollection ;
@@ -1173,6 +1204,23 @@ private PackageRelationshipCollection GetRelationshipsHelper(string? filterStrin
1173
1204
return new PackageRelationshipCollection ( _relationships , filterString ) ;
1174
1205
}
1175
1206
1207
+ private void CopyPartDicitonaryToPartList ( Dictionary < string , KeyValuePair < PackUriHelper . ValidatedPartUri , PackagePart > > partDictionary , List < string > partIndex )
1208
+ {
1209
+ //Clearing _partList before copying in new data. Reassigning the variable, assuming the previous object to be garbage collected.
1210
+ //ideally addition to sortedlist takes O(n) but since we have sorted data and also we defined the size, it will take O(log n) per addition
1211
+ //total time complexity for this function will be O(n log n)
1212
+ _partList = new SortedList < PackUriHelper . ValidatedPartUri , PackagePart > ( partDictionary . Count ) ;
1213
+
1214
+ //Since partIndex is created from a sorted parts array we are sure that partIndex
1215
+ //will have items in same order
1216
+ foreach ( var id in partIndex )
1217
+ {
1218
+ //retrieving object from partDictionary hashtable
1219
+ var keyValue = partDictionary [ id ] ;
1220
+ _partList . Add ( keyValue . Key , keyValue . Value ) ;
1221
+ }
1222
+ }
1223
+
1176
1224
#endregion Private Methods
1177
1225
1178
1226
#region Private Members
0 commit comments