[FASTFAT] Lock DirResource when modifying an entry on disk.
[reactos.git] / drivers / ksfilter / ks / filterfactory.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/ksfilter/ks/filterfactory.c
5 * PURPOSE: KS IKsFilterFactory interface functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "precomp.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 typedef struct
15 {
16 KSBASIC_HEADER Header;
17 KSFILTERFACTORY FilterFactory;
18
19 LONG ref;
20 PKSIDEVICE_HEADER DeviceHeader;
21 PFNKSFILTERFACTORYPOWER SleepCallback;
22 PFNKSFILTERFACTORYPOWER WakeCallback;
23
24 LIST_ENTRY SymbolicLinkList;
25 KMUTEX ControlMutex;
26
27 }IKsFilterFactoryImpl;
28
29 VOID
30 NTAPI
31 IKsFilterFactory_ItemFreeCb(
32 IN PKSOBJECT_CREATE_ITEM CreateItem)
33 {
34 /* callback when create item is freed in the device header */
35 IKsFilterFactory * iface = (IKsFilterFactory*)CONTAINING_RECORD(CreateItem->Context, IKsFilterFactoryImpl, FilterFactory);
36
37 iface->lpVtbl->Release(iface);
38 }
39
40 NTSTATUS
41 NTAPI
42 IKsFilterFactory_Create(
43 IN PDEVICE_OBJECT DeviceObject,
44 IN PIRP Irp)
45 {
46 PKSOBJECT_CREATE_ITEM CreateItem;
47 IKsFilterFactoryImpl * Factory;
48 IKsFilterFactory * iface;
49 NTSTATUS Status;
50
51 /* access the create item */
52 CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
53 if (!CreateItem)
54 {
55 DPRINT1("IKsFilterFactory_Create no CreateItem\n");
56 return STATUS_UNSUCCESSFUL;
57 }
58
59 /* get filter factory interface */
60 Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(CreateItem->Context, IKsFilterFactoryImpl, FilterFactory);
61
62 /* get interface */
63 iface = (IKsFilterFactory*)&Factory->Header.OuterUnknown;
64
65 /* create a filter instance */
66 Status = KspCreateFilter(DeviceObject, Irp, iface);
67
68 DPRINT("KspCreateFilter Status %x\n", Status);
69
70 if (Status != STATUS_PENDING)
71 {
72 Irp->IoStatus.Information = 0;
73 Irp->IoStatus.Status = Status;
74 CompleteRequest(Irp, IO_NO_INCREMENT);
75 }
76
77 return Status;
78 }
79
80
81 NTSTATUS
82 NTAPI
83 IKsFilterFactory_fnQueryInterface(
84 IKsFilterFactory * iface,
85 IN REFIID refiid,
86 OUT PVOID* Output)
87 {
88 NTSTATUS Status;
89
90 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
91
92 if (IsEqualGUIDAligned(refiid, &IID_IUnknown))
93 {
94 *Output = &This->Header.OuterUnknown;
95 _InterlockedIncrement(&This->ref);
96 return STATUS_SUCCESS;
97 }
98
99 if (This->Header.ClientAggregate)
100 {
101 /* using client aggregate */
102 Status = This->Header.ClientAggregate->lpVtbl->QueryInterface(This->Header.ClientAggregate, refiid, Output);
103
104 if (NT_SUCCESS(Status))
105 {
106 /* client aggregate supports interface */
107 return Status;
108 }
109 }
110
111 DPRINT("IKsFilterFactory_fnQueryInterface no interface\n");
112 return STATUS_NOT_SUPPORTED;
113 }
114
115 ULONG
116 NTAPI
117 IKsFilterFactory_fnAddRef(
118 IKsFilterFactory * iface)
119 {
120 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
121
122 return InterlockedIncrement(&This->ref);
123 }
124
125 ULONG
126 NTAPI
127 IKsFilterFactory_fnRelease(
128 IKsFilterFactory * iface)
129 {
130 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
131
132 InterlockedDecrement(&This->ref);
133
134 if (This->ref == 0)
135 {
136 if (!IsListEmpty(&This->SymbolicLinkList))
137 {
138 /* disable device interfaces */
139 KspSetDeviceInterfacesState(&This->SymbolicLinkList, FALSE);
140 /* free device interface strings */
141 KspFreeDeviceInterfaces(&This->SymbolicLinkList);
142 }
143
144 FreeItem(This);
145 return 0;
146 }
147 /* Return new reference count */
148 return This->ref;
149 }
150
151 KSFILTERFACTORY*
152 NTAPI
153 IKsFilterFactory_fnGetStruct(
154 IKsFilterFactory * iface)
155 {
156 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
157
158 return &This->FilterFactory;
159 }
160
161 NTSTATUS
162 NTAPI
163 IKsFilterFactory_fnSetDeviceClassesState(
164 IKsFilterFactory * iface,
165 IN BOOLEAN Enable)
166 {
167 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
168
169 return KspSetDeviceInterfacesState(&This->SymbolicLinkList, Enable);
170 }
171
172 VOID
173 IKsFilterFactory_AttachFilterFactoryToDeviceHeader(
174 IKsFilterFactoryImpl * This,
175 PKSIDEVICE_HEADER DeviceHeader)
176 {
177 PKSBASIC_HEADER BasicHeader;
178 PKSFILTERFACTORY FilterFactory;
179
180 if (DeviceHeader->BasicHeader.FirstChild.FilterFactory == NULL)
181 {
182 /* first attached filter factory */
183 DeviceHeader->BasicHeader.FirstChild.FilterFactory = &This->FilterFactory;
184 return;
185 }
186
187 /* set to first entry */
188 FilterFactory = DeviceHeader->BasicHeader.FirstChild.FilterFactory;
189
190 do
191 {
192 /* get basic header */
193 BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)FilterFactory - sizeof(KSBASIC_HEADER));
194 /* sanity check */
195 ASSERT(BasicHeader->Type == KsObjectTypeFilterFactory);
196
197 if (BasicHeader->Next.FilterFactory)
198 {
199 /* iterate to next filter factory */
200 FilterFactory = BasicHeader->Next.FilterFactory;
201 }
202 else
203 {
204 /* found last entry */
205 break;
206 }
207 }while(FilterFactory);
208
209 /* attach filter factory */
210 BasicHeader->Next.FilterFactory = &This->FilterFactory;
211 }
212
213 NTSTATUS
214 NTAPI
215 IKsFilterFactory_fnInitialize(
216 IKsFilterFactory * iface,
217 IN PDEVICE_OBJECT DeviceObject,
218 IN const KSFILTER_DESCRIPTOR *Descriptor,
219 IN PWSTR RefString OPTIONAL,
220 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
221 IN ULONG CreateItemFlags,
222 IN PFNKSFILTERFACTORYPOWER SleepCallback OPTIONAL,
223 IN PFNKSFILTERFACTORYPOWER WakeCallback OPTIONAL,
224 OUT PKSFILTERFACTORY *FilterFactory OPTIONAL)
225 {
226 UNICODE_STRING ReferenceString;
227 NTSTATUS Status;
228 PDEVICE_EXTENSION DeviceExtension;
229 KSOBJECT_CREATE_ITEM CreateItem;
230 BOOL FreeString = FALSE;
231 IKsDevice * KsDevice;
232
233 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(iface, IKsFilterFactoryImpl, Header.OuterUnknown);
234
235 /* get device extension */
236 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
237
238 /* initialize filterfactory */
239 This->SleepCallback = SleepCallback;
240 This->WakeCallback = WakeCallback;
241 This->Header.KsDevice = &DeviceExtension->DeviceHeader->KsDevice;
242 This->Header.Type = KsObjectTypeFilterFactory;
243 This->Header.Parent.KsDevice = &DeviceExtension->DeviceHeader->KsDevice;
244 This->DeviceHeader = DeviceExtension->DeviceHeader;
245
246 /* copy descriptor */
247 This->FilterFactory.FilterDescriptor = AllocateItem(NonPagedPool, sizeof(KSFILTER_DESCRIPTOR));
248 if (!This->FilterFactory.FilterDescriptor)
249 {
250 DPRINT("out of memory");
251 return STATUS_INSUFFICIENT_RESOURCES;
252 }
253 RtlMoveMemory((PVOID)This->FilterFactory.FilterDescriptor, (PVOID)Descriptor, sizeof(KSFILTER_DESCRIPTOR));
254
255 /* initialize filter factory control mutex */
256 This->Header.ControlMutex = &This->ControlMutex;
257 KeInitializeMutex(This->Header.ControlMutex, 0);
258
259 /* unused fields */
260 InitializeListHead(&This->Header.EventList);
261 KeInitializeSpinLock(&This->Header.EventListLock);
262
263 InitializeListHead(&This->SymbolicLinkList);
264
265 /* does the device use a reference string */
266 if (RefString || !Descriptor->ReferenceGuid)
267 {
268 /* use device reference string */
269 RtlInitUnicodeString(&ReferenceString, RefString);
270 }
271 else
272 {
273 /* create reference string from descriptor guid */
274 Status = RtlStringFromGUID(Descriptor->ReferenceGuid, &ReferenceString);
275
276 /* check for success */
277 if (!NT_SUCCESS(Status))
278 {
279 /* omg, we failed */
280 return Status;
281 }
282
283 FreeString = TRUE;
284 }
285
286 DPRINT("IKsFilterFactory_fnInitialize CategoriesCount %u ReferenceString '%S'\n", Descriptor->CategoriesCount,ReferenceString.Buffer);
287
288 /* now register the device interface */
289 Status = KspRegisterDeviceInterfaces(DeviceExtension->DeviceHeader->KsDevice.PhysicalDeviceObject,
290 Descriptor->CategoriesCount,
291 Descriptor->Categories,
292 &ReferenceString,
293 &This->SymbolicLinkList);
294 /* check for success */
295 if (!NT_SUCCESS(Status))
296 {
297 DPRINT1("KspRegisterDeviceInterfaces failed with %x\n", Status);
298
299 if (FreeString)
300 {
301 /* free unicode string */
302 RtlFreeUnicodeString(&ReferenceString);
303 }
304
305 return Status;
306 }
307
308 /* now setup the create item */
309 CreateItem.SecurityDescriptor = SecurityDescriptor;
310 CreateItem.Flags = CreateItemFlags;
311 CreateItem.Create = IKsFilterFactory_Create;
312 CreateItem.Context = (PVOID)&This->FilterFactory;
313 RtlInitUnicodeString(&CreateItem.ObjectClass, ReferenceString.Buffer);
314
315 /* insert create item to device header */
316 Status = KsAllocateObjectCreateItem((KSDEVICE_HEADER)DeviceExtension->DeviceHeader, &CreateItem, TRUE, IKsFilterFactory_ItemFreeCb);
317
318 if (FreeString)
319 {
320 /* free unicode string */
321 RtlFreeUnicodeString(&ReferenceString);
322 }
323
324 /* create a object bag for the filter factory */
325 This->FilterFactory.Bag = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_BAG));
326 if (This->FilterFactory.Bag)
327 {
328 /* initialize object bag */
329 KsDevice = (IKsDevice*)&DeviceExtension->DeviceHeader->BasicHeader.OuterUnknown;
330 KsDevice->lpVtbl->InitializeObjectBag(KsDevice, (PKSIOBJECT_BAG)This->FilterFactory.Bag, NULL);
331 }
332
333 if (FilterFactory)
334 {
335 /* return filterfactory */
336 *FilterFactory = &This->FilterFactory;
337 }
338
339 /* attach filterfactory to device header */
340 IKsFilterFactory_AttachFilterFactoryToDeviceHeader(This, DeviceExtension->DeviceHeader);
341
342 /* return result */
343 return Status;
344 }
345
346 static IKsFilterFactoryVtbl vt_IKsFilterFactoryVtbl =
347 {
348 IKsFilterFactory_fnQueryInterface,
349 IKsFilterFactory_fnAddRef,
350 IKsFilterFactory_fnRelease,
351 IKsFilterFactory_fnGetStruct,
352 IKsFilterFactory_fnSetDeviceClassesState,
353 IKsFilterFactory_fnInitialize
354 };
355
356
357 NTSTATUS
358 NTAPI
359 KspCreateFilterFactory(
360 IN PDEVICE_OBJECT DeviceObject,
361 IN const KSFILTER_DESCRIPTOR *Descriptor,
362 IN PWSTR RefString OPTIONAL,
363 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
364 IN ULONG CreateItemFlags,
365 IN PFNKSFILTERFACTORYPOWER SleepCallback OPTIONAL,
366 IN PFNKSFILTERFACTORYPOWER WakeCallback OPTIONAL,
367 OUT PKSFILTERFACTORY *FilterFactory OPTIONAL)
368 {
369 IKsFilterFactoryImpl * This;
370 IKsFilterFactory * Filter;
371 NTSTATUS Status;
372
373 DPRINT("KsCreateFilterFactory\n");
374
375 /* Lets allocate a filterfactory */
376 This = AllocateItem(NonPagedPool, sizeof(IKsFilterFactoryImpl));
377 if (!This)
378 {
379 /* not enough memory */
380 return STATUS_INSUFFICIENT_RESOURCES;
381 }
382
383 /* initialize struct */
384 This->ref = 1;
385 This->Header.OuterUnknown = (PUNKNOWN)&vt_IKsFilterFactoryVtbl;
386
387 /* map to com object */
388 Filter = (IKsFilterFactory*)&This->Header.OuterUnknown;
389
390 /* initialize filter */
391 Status = Filter->lpVtbl->Initialize(Filter, DeviceObject, Descriptor, RefString, SecurityDescriptor, CreateItemFlags, SleepCallback, WakeCallback, FilterFactory);
392 /* did we succeed */
393 if (!NT_SUCCESS(Status))
394 {
395 /* destroy filterfactory */
396 Filter->lpVtbl->Release(Filter);
397 }
398
399 /* return result */
400 DPRINT("KsCreateFilterFactory %x\n", Status);
401 /* sanity check */
402 ASSERT(Status == STATUS_SUCCESS);
403
404 return Status;
405 }
406
407 /*
408 @implemented
409 */
410 KSDDKAPI
411 NTSTATUS
412 NTAPI
413 KsCreateFilterFactory(
414 IN PDEVICE_OBJECT DeviceObject,
415 IN const KSFILTER_DESCRIPTOR *Descriptor,
416 IN PWSTR RefString OPTIONAL,
417 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
418 IN ULONG CreateItemFlags,
419 IN PFNKSFILTERFACTORYPOWER SleepCallback OPTIONAL,
420 IN PFNKSFILTERFACTORYPOWER WakeCallback OPTIONAL,
421 OUT PKSFILTERFACTORY *FilterFactory OPTIONAL)
422 {
423 return KspCreateFilterFactory(DeviceObject, Descriptor, RefString, SecurityDescriptor, CreateItemFlags, SleepCallback, WakeCallback, FilterFactory);
424
425 }
426
427 /*
428 @implemented
429 */
430 KSDDKAPI
431 NTSTATUS
432 NTAPI
433 KsFilterFactorySetDeviceClassesState(
434 IN PKSFILTERFACTORY FilterFactory,
435 IN BOOLEAN NewState)
436 {
437 IKsFilterFactory * Factory;
438 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
439
440 Factory = (IKsFilterFactory*)&This->Header.OuterUnknown;
441 return Factory->lpVtbl->SetDeviceClassesState(Factory, NewState);
442 }
443
444
445 /*
446 @implemented
447 */
448 KSDDKAPI
449 PUNICODE_STRING
450 NTAPI
451 KsFilterFactoryGetSymbolicLink(
452 IN PKSFILTERFACTORY FilterFactory)
453 {
454 PSYMBOLIC_LINK_ENTRY LinkEntry;
455 IKsFilterFactoryImpl * Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
456
457 if (IsListEmpty(&Factory->SymbolicLinkList))
458 {
459 /* device has not registered any interfaces */
460 return NULL;
461 }
462
463 /* get first entry */
464 LinkEntry = (PSYMBOLIC_LINK_ENTRY)CONTAINING_RECORD(Factory->SymbolicLinkList.Flink, SYMBOLIC_LINK_ENTRY, Entry);
465
466 /* return first link */
467 return &LinkEntry->SymbolicLink;
468 }
469
470 /*
471 @implemented
472 */
473 KSDDKAPI
474 NTSTATUS
475 NTAPI
476 KsFilterFactoryAddCreateItem(
477 IN PKSFILTERFACTORY FilterFactory,
478 IN PWSTR RefString,
479 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
480 IN ULONG CreateItemFlags)
481 {
482 KSOBJECT_CREATE_ITEM CreateItem;
483
484 IKsFilterFactoryImpl * Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
485
486 /* initialize create item */
487 CreateItem.Context = (PVOID)&Factory->FilterFactory;
488 CreateItem.Create = IKsFilterFactory_Create;
489 CreateItem.Flags = CreateItemFlags;
490 CreateItem.SecurityDescriptor = SecurityDescriptor;
491 RtlInitUnicodeString(&CreateItem.ObjectClass, RefString);
492
493 /* insert create item to device header */
494 return KsAllocateObjectCreateItem((KSDEVICE_HEADER)Factory->DeviceHeader, &CreateItem, TRUE, IKsFilterFactory_ItemFreeCb);
495 }
496
497 ULONG
498 KspCacheAddData(
499 PKSPCACHE_DESCRIPTOR Descriptor,
500 LPCVOID Data,
501 ULONG Length)
502 {
503 ULONG Index;
504
505 for(Index = 0; Index < Descriptor->DataOffset; Index++)
506 {
507 if (RtlCompareMemory(Descriptor->DataCache, Data, Length) == Length)
508 {
509 if (Index + Length > Descriptor->DataOffset)
510 {
511 /* adjust used space */
512 Descriptor->DataOffset = Index + Length;
513 /* return absolute offset */
514 return Descriptor->DataLength + Index;
515 }
516 }
517 }
518
519 /* sanity check */
520 ASSERT(Descriptor->DataOffset + Length < Descriptor->DataLength);
521
522 /* copy to data blob */
523 RtlMoveMemory((Descriptor->DataCache + Descriptor->DataOffset), Data, Length);
524
525 /* backup offset */
526 Index = Descriptor->DataOffset;
527
528 /* adjust used space */
529 Descriptor->DataOffset += Length;
530
531 /* return absolute offset */
532 return Descriptor->DataLength + Index;
533 }
534
535 /*
536 @implemented
537 */
538 KSDDKAPI
539 NTSTATUS
540 NTAPI
541 KsFilterFactoryUpdateCacheData(
542 IN PKSFILTERFACTORY FilterFactory,
543 IN const KSFILTER_DESCRIPTOR* FilterDescriptor OPTIONAL)
544 {
545 KSPCACHE_DESCRIPTOR Descriptor;
546 PKSPCACHE_FILTER_HEADER FilterHeader;
547 UNICODE_STRING FilterData = RTL_CONSTANT_STRING(L"FilterData");
548 PKSPCACHE_PIN_HEADER PinHeader;
549 ULONG Index, SubIndex;
550 PLIST_ENTRY Entry;
551 PSYMBOLIC_LINK_ENTRY SymEntry;
552 BOOLEAN Found;
553 HANDLE hKey;
554 NTSTATUS Status = STATUS_SUCCESS;
555
556 IKsFilterFactoryImpl * Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
557
558 DPRINT("KsFilterFactoryUpdateCacheData %p\n", FilterDescriptor);
559
560 if (!FilterDescriptor)
561 FilterDescriptor = Factory->FilterFactory.FilterDescriptor;
562
563 ASSERT(FilterDescriptor);
564
565 /* initialize cache descriptor */
566 RtlZeroMemory(&Descriptor, sizeof(KSPCACHE_DESCRIPTOR));
567
568 /* calculate filter data size */
569 Descriptor.FilterLength = sizeof(KSPCACHE_FILTER_HEADER);
570
571 /* FIXME support variable size pin descriptors */
572 ASSERT(FilterDescriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
573
574 for(Index = 0; Index < FilterDescriptor->PinDescriptorsCount; Index++)
575 {
576 /* add filter descriptor */
577 Descriptor.FilterLength += sizeof(KSPCACHE_PIN_HEADER);
578
579 if (FilterDescriptor->PinDescriptors[Index].PinDescriptor.Category)
580 {
581 /* add extra ULONG for offset to category */
582 Descriptor.FilterLength += sizeof(ULONG);
583
584 /* add size for clsid */
585 Descriptor.DataLength += sizeof(CLSID);
586 }
587
588 /* add space for formats */
589 Descriptor.FilterLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount * sizeof(KSPCACHE_DATARANGE);
590
591 /* add space for MajorFormat / MinorFormat */
592 Descriptor.DataLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount * sizeof(CLSID) * 2;
593
594 /* add space for mediums */
595 Descriptor.FilterLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount * sizeof(ULONG);
596
597 /* add space for the data */
598 Descriptor.DataLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount * sizeof(KSPCACHE_MEDIUM);
599 }
600
601 /* now allocate the space */
602 Descriptor.FilterData = (PUCHAR)AllocateItem(NonPagedPool, Descriptor.DataLength + Descriptor.FilterLength);
603 if (!Descriptor.FilterData)
604 {
605 /* no memory */
606 return STATUS_INSUFFICIENT_RESOURCES;
607 }
608
609 /* initialize data cache */
610 Descriptor.DataCache = (PUCHAR)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterLength);
611
612 /* setup filter header */
613 FilterHeader = (PKSPCACHE_FILTER_HEADER)Descriptor.FilterData;
614
615 FilterHeader->dwVersion = 2;
616 FilterHeader->dwMerit = MERIT_DO_NOT_USE;
617 FilterHeader->dwUnused = 0;
618 FilterHeader->dwPins = FilterDescriptor->PinDescriptorsCount;
619
620 Descriptor.FilterOffset = sizeof(KSPCACHE_FILTER_HEADER);
621
622 /* write pin headers */
623 for(Index = 0; Index < FilterDescriptor->PinDescriptorsCount; Index++)
624 {
625 /* get offset to pin */
626 PinHeader = (PKSPCACHE_PIN_HEADER)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterOffset);
627
628 /* write pin header */
629 PinHeader->Signature = 0x33697030 + Index;
630 PinHeader->Flags = 0;
631 PinHeader->Instances = FilterDescriptor->PinDescriptors[Index].InstancesPossible;
632 if (PinHeader->Instances > 1)
633 PinHeader->Flags |= REG_PINFLAG_B_MANY;
634
635
636 PinHeader->MediaTypes = FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount;
637 PinHeader->Mediums = FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount;
638 PinHeader->Category = (FilterDescriptor->PinDescriptors[Index].PinDescriptor.Category ? TRUE : FALSE);
639
640 Descriptor.FilterOffset += sizeof(KSPCACHE_PIN_HEADER);
641
642 if (PinHeader->Category)
643 {
644 /* get category offset */
645 PULONG Category = (PULONG)(PinHeader + 1);
646
647 /* write category offset */
648 *Category = KspCacheAddData(&Descriptor, FilterDescriptor->PinDescriptors[Index].PinDescriptor.Category, sizeof(CLSID));
649
650 /* adjust offset */
651 Descriptor.FilterOffset += sizeof(ULONG);
652 }
653
654 /* add dataranges */
655 for(SubIndex = 0; SubIndex < FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount; SubIndex++)
656 {
657 /* get datarange offset */
658 PKSPCACHE_DATARANGE DataRange = (PKSPCACHE_DATARANGE)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterOffset);
659
660 /* initialize data range */
661 DataRange->Signature = 0x33797430 + SubIndex;
662 DataRange->dwUnused = 0;
663 DataRange->OffsetMajor = KspCacheAddData(&Descriptor, &FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRanges[SubIndex]->MajorFormat, sizeof(CLSID));
664 DataRange->OffsetMinor = KspCacheAddData(&Descriptor, &FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRanges[SubIndex]->SubFormat, sizeof(CLSID));
665
666 /* adjust offset */
667 Descriptor.FilterOffset += sizeof(KSPCACHE_DATARANGE);
668 }
669
670 /* add mediums */
671 for(SubIndex = 0; SubIndex < FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount; SubIndex++)
672 {
673 KSPCACHE_MEDIUM Medium;
674 PULONG MediumOffset;
675
676 /* get pin medium offset */
677 MediumOffset = (PULONG)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterOffset);
678
679 /* copy medium guid */
680 RtlMoveMemory(&Medium.Medium, &FilterDescriptor->PinDescriptors[Index].PinDescriptor.Mediums[SubIndex].Set, sizeof(GUID));
681 Medium.dw1 = FilterDescriptor->PinDescriptors[Index].PinDescriptor.Mediums[SubIndex].Id; /* FIXME verify */
682 Medium.dw2 = 0;
683
684 *MediumOffset = KspCacheAddData(&Descriptor, &Medium, sizeof(KSPCACHE_MEDIUM));
685
686 /* adjust offset */
687 Descriptor.FilterOffset += sizeof(ULONG);
688 }
689 }
690
691 /* sanity checks */
692 ASSERT(Descriptor.FilterOffset == Descriptor.FilterLength);
693 ASSERT(Descriptor.DataOffset <= Descriptor.DataLength);
694
695
696 /* now go through all entries and update 'FilterData' key */
697 for(Index = 0; Index < FilterDescriptor->CategoriesCount; Index++)
698 {
699 /* get first entry */
700 Entry = Factory->SymbolicLinkList.Flink;
701
702 /* set status to not found */
703 Found = FALSE;
704 /* loop list until the the current category is found */
705 while(Entry != &Factory->SymbolicLinkList)
706 {
707 /* fetch symbolic link entry */
708 SymEntry = (PSYMBOLIC_LINK_ENTRY)CONTAINING_RECORD(Entry, SYMBOLIC_LINK_ENTRY, Entry);
709
710 if (IsEqualGUIDAligned(&SymEntry->DeviceInterfaceClass, &FilterDescriptor->Categories[Index]))
711 {
712 /* found category */
713 Found = TRUE;
714 break;
715 }
716
717 /* move to next entry */
718 Entry = Entry->Flink;
719 }
720
721 if (!Found)
722 {
723 /* filter category is not present */
724 Status = STATUS_INVALID_PARAMETER;
725 break;
726 }
727
728 /* now open device interface */
729 Status = IoOpenDeviceInterfaceRegistryKey(&SymEntry->SymbolicLink, KEY_WRITE, &hKey);
730 if (!NT_SUCCESS(Status))
731 {
732 /* failed to open interface key */
733 break;
734 }
735
736 /* update filterdata key */
737 Status = ZwSetValueKey(hKey, &FilterData, 0, REG_BINARY, Descriptor.FilterData, Descriptor.FilterLength + Descriptor.DataOffset);
738
739 /* close filterdata key */
740 ZwClose(hKey);
741
742 if (!NT_SUCCESS(Status))
743 {
744 /* failed to set key value */
745 break;
746 }
747 }
748 /* free filter data */
749 FreeItem(Descriptor.FilterData);
750
751 /* done */
752 return Status;
753 }
754