[KS]
[reactos.git] / reactos / 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 "priv.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->FilterFactory.FilterDescriptor = Descriptor;
242 This->Header.KsDevice = &DeviceExtension->DeviceHeader->KsDevice;
243 This->Header.Type = KsObjectTypeFilterFactory;
244 This->Header.Parent.KsDevice = &DeviceExtension->DeviceHeader->KsDevice;
245 This->DeviceHeader = DeviceExtension->DeviceHeader;
246
247 /* initialize filter factory control mutex */
248 This->Header.ControlMutex = &This->ControlMutex;
249 KeInitializeMutex(This->Header.ControlMutex, 0);
250
251 /* unused fields */
252 InitializeListHead(&This->Header.EventList);
253 KeInitializeSpinLock(&This->Header.EventListLock);
254
255 InitializeListHead(&This->SymbolicLinkList);
256
257 /* does the device use a reference string */
258 if (RefString || !Descriptor->ReferenceGuid)
259 {
260 /* use device reference string */
261 RtlInitUnicodeString(&ReferenceString, RefString);
262 }
263 else
264 {
265 /* create reference string from descriptor guid */
266 Status = RtlStringFromGUID(Descriptor->ReferenceGuid, &ReferenceString);
267
268 /* check for success */
269 if (!NT_SUCCESS(Status))
270 {
271 /* omg, we failed */
272 return Status;
273 }
274
275 FreeString = TRUE;
276 }
277
278 DPRINT("IKsFilterFactory_fnInitialize CategoriesCount %u ReferenceString '%S'\n", Descriptor->CategoriesCount,ReferenceString.Buffer);
279
280 /* now register the device interface */
281 Status = KspRegisterDeviceInterfaces(DeviceExtension->DeviceHeader->KsDevice.PhysicalDeviceObject,
282 Descriptor->CategoriesCount,
283 Descriptor->Categories,
284 &ReferenceString,
285 &This->SymbolicLinkList);
286 /* check for success */
287 if (!NT_SUCCESS(Status))
288 {
289 DPRINT1("KspRegisterDeviceInterfaces failed with %x\n", Status);
290
291 if (FreeString)
292 {
293 /* free unicode string */
294 RtlFreeUnicodeString(&ReferenceString);
295 }
296
297 return Status;
298 }
299
300 /* now setup the create item */
301 CreateItem.SecurityDescriptor = SecurityDescriptor;
302 CreateItem.Flags = CreateItemFlags;
303 CreateItem.Create = IKsFilterFactory_Create;
304 CreateItem.Context = (PVOID)&This->FilterFactory;
305 RtlInitUnicodeString(&CreateItem.ObjectClass, ReferenceString.Buffer);
306
307 /* insert create item to device header */
308 Status = KsAllocateObjectCreateItem((KSDEVICE_HEADER)DeviceExtension->DeviceHeader, &CreateItem, TRUE, IKsFilterFactory_ItemFreeCb);
309
310 if (FreeString)
311 {
312 /* free unicode string */
313 RtlFreeUnicodeString(&ReferenceString);
314 }
315
316 if (FilterFactory)
317 {
318 /* return filterfactory */
319 *FilterFactory = &This->FilterFactory;
320
321 /* create a object bag for the filter factory */
322 This->FilterFactory.Bag = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_BAG));
323 if (This->FilterFactory.Bag)
324 {
325 /* initialize object bag */
326 KsDevice = (IKsDevice*)&DeviceExtension->DeviceHeader->BasicHeader.OuterUnknown;
327 KsDevice->lpVtbl->InitializeObjectBag(KsDevice, (PKSIOBJECT_BAG)This->FilterFactory.Bag, NULL);
328 }
329 }
330
331 /* attach filterfactory to device header */
332 IKsFilterFactory_AttachFilterFactoryToDeviceHeader(This, DeviceExtension->DeviceHeader);
333
334 /* return result */
335 return Status;
336 }
337
338 static IKsFilterFactoryVtbl vt_IKsFilterFactoryVtbl =
339 {
340 IKsFilterFactory_fnQueryInterface,
341 IKsFilterFactory_fnAddRef,
342 IKsFilterFactory_fnRelease,
343 IKsFilterFactory_fnGetStruct,
344 IKsFilterFactory_fnSetDeviceClassesState,
345 IKsFilterFactory_fnInitialize
346 };
347
348
349 NTSTATUS
350 NTAPI
351 KspCreateFilterFactory(
352 IN PDEVICE_OBJECT DeviceObject,
353 IN const KSFILTER_DESCRIPTOR *Descriptor,
354 IN PWSTR RefString OPTIONAL,
355 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
356 IN ULONG CreateItemFlags,
357 IN PFNKSFILTERFACTORYPOWER SleepCallback OPTIONAL,
358 IN PFNKSFILTERFACTORYPOWER WakeCallback OPTIONAL,
359 OUT PKSFILTERFACTORY *FilterFactory OPTIONAL)
360 {
361 IKsFilterFactoryImpl * This;
362 IKsFilterFactory * Filter;
363 NTSTATUS Status;
364
365 DPRINT("KsCreateFilterFactory\n");
366
367 /* Lets allocate a filterfactory */
368 This = AllocateItem(NonPagedPool, sizeof(IKsFilterFactoryImpl));
369 if (!This)
370 {
371 /* not enough memory */
372 return STATUS_INSUFFICIENT_RESOURCES;
373 }
374
375 /* initialize struct */
376 This->ref = 1;
377 This->Header.OuterUnknown = (PUNKNOWN)&vt_IKsFilterFactoryVtbl;
378
379 /* map to com object */
380 Filter = (IKsFilterFactory*)&This->Header.OuterUnknown;
381
382 /* initialize filter */
383 Status = Filter->lpVtbl->Initialize(Filter, DeviceObject, Descriptor, RefString, SecurityDescriptor, CreateItemFlags, SleepCallback, WakeCallback, FilterFactory);
384 /* did we succeed */
385 if (!NT_SUCCESS(Status))
386 {
387 /* destroy filterfactory */
388 Filter->lpVtbl->Release(Filter);
389 }
390
391 /* return result */
392 DPRINT("KsCreateFilterFactory %x\n", Status);
393 /* sanity check */
394 ASSERT(Status == STATUS_SUCCESS);
395
396 return Status;
397 }
398
399 /*
400 @implemented
401 */
402 KSDDKAPI
403 NTSTATUS
404 NTAPI
405 KsCreateFilterFactory(
406 IN PDEVICE_OBJECT DeviceObject,
407 IN const KSFILTER_DESCRIPTOR *Descriptor,
408 IN PWSTR RefString OPTIONAL,
409 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
410 IN ULONG CreateItemFlags,
411 IN PFNKSFILTERFACTORYPOWER SleepCallback OPTIONAL,
412 IN PFNKSFILTERFACTORYPOWER WakeCallback OPTIONAL,
413 OUT PKSFILTERFACTORY *FilterFactory OPTIONAL)
414 {
415 return KspCreateFilterFactory(DeviceObject, Descriptor, RefString, SecurityDescriptor, CreateItemFlags, SleepCallback, WakeCallback, FilterFactory);
416
417 }
418
419 /*
420 @implemented
421 */
422 KSDDKAPI
423 NTSTATUS
424 NTAPI
425 KsFilterFactorySetDeviceClassesState(
426 IN PKSFILTERFACTORY FilterFactory,
427 IN BOOLEAN NewState)
428 {
429 IKsFilterFactory * Factory;
430 IKsFilterFactoryImpl * This = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
431
432 Factory = (IKsFilterFactory*)&This->Header.OuterUnknown;
433 return Factory->lpVtbl->SetDeviceClassesState(Factory, NewState);
434 }
435
436
437 /*
438 @implemented
439 */
440 KSDDKAPI
441 PUNICODE_STRING
442 NTAPI
443 KsFilterFactoryGetSymbolicLink(
444 IN PKSFILTERFACTORY FilterFactory)
445 {
446 PSYMBOLIC_LINK_ENTRY LinkEntry;
447 IKsFilterFactoryImpl * Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
448
449 if (IsListEmpty(&Factory->SymbolicLinkList))
450 {
451 /* device has not registered any interfaces */
452 return NULL;
453 }
454
455 /* get first entry */
456 LinkEntry = (PSYMBOLIC_LINK_ENTRY)CONTAINING_RECORD(Factory->SymbolicLinkList.Flink, SYMBOLIC_LINK_ENTRY, Entry);
457
458 /* return first link */
459 return &LinkEntry->SymbolicLink;
460 }
461
462 /*
463 @implemented
464 */
465 KSDDKAPI
466 NTSTATUS
467 NTAPI
468 KsFilterFactoryAddCreateItem(
469 IN PKSFILTERFACTORY FilterFactory,
470 IN PWSTR RefString,
471 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
472 IN ULONG CreateItemFlags)
473 {
474 KSOBJECT_CREATE_ITEM CreateItem;
475
476 IKsFilterFactoryImpl * Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
477
478 /* initialize create item */
479 CreateItem.Context = (PVOID)&Factory->FilterFactory;
480 CreateItem.Create = IKsFilterFactory_Create;
481 CreateItem.Flags = CreateItemFlags;
482 CreateItem.SecurityDescriptor = SecurityDescriptor;
483 RtlInitUnicodeString(&CreateItem.ObjectClass, RefString);
484
485 /* insert create item to device header */
486 return KsAllocateObjectCreateItem((KSDEVICE_HEADER)Factory->DeviceHeader, &CreateItem, TRUE, IKsFilterFactory_ItemFreeCb);
487 }
488
489 ULONG
490 KspCacheAddData(
491 PKSPCACHE_DESCRIPTOR Descriptor,
492 LPCVOID Data,
493 ULONG Length)
494 {
495 ULONG Index;
496
497 for(Index = 0; Index < Descriptor->DataOffset; Index++)
498 {
499 if (RtlCompareMemory(Descriptor->DataCache, Data, Length) == Length)
500 {
501 if (Index + Length > Descriptor->DataOffset)
502 {
503 /* adjust used space */
504 Descriptor->DataOffset = Index + Length;
505 /* return absolute offset */
506 return Descriptor->DataLength + Index;
507 }
508 }
509 }
510
511 /* sanity check */
512 ASSERT(Descriptor->DataOffset + Length < Descriptor->DataLength);
513
514 /* copy to data blob */
515 RtlMoveMemory((Descriptor->DataCache + Descriptor->DataOffset), Data, Length);
516
517 /* backup offset */
518 Index = Descriptor->DataOffset;
519
520 /* adjust used space */
521 Descriptor->DataOffset += Length;
522
523 /* return absolute offset */
524 return Descriptor->DataLength + Index;
525 }
526
527 /*
528 @implemented
529 */
530 KSDDKAPI
531 NTSTATUS
532 NTAPI
533 KsFilterFactoryUpdateCacheData(
534 IN PKSFILTERFACTORY FilterFactory,
535 IN const KSFILTER_DESCRIPTOR* FilterDescriptor OPTIONAL)
536 {
537 KSPCACHE_DESCRIPTOR Descriptor;
538 PKSPCACHE_FILTER_HEADER FilterHeader;
539 UNICODE_STRING FilterData = RTL_CONSTANT_STRING(L"FilterData");
540 PKSPCACHE_PIN_HEADER PinHeader;
541 ULONG Index, SubIndex;
542 PLIST_ENTRY Entry;
543 PSYMBOLIC_LINK_ENTRY SymEntry;
544 BOOLEAN Found;
545 HKEY hKey;
546 NTSTATUS Status = STATUS_SUCCESS;
547
548 IKsFilterFactoryImpl * Factory = (IKsFilterFactoryImpl*)CONTAINING_RECORD(FilterFactory, IKsFilterFactoryImpl, FilterFactory);
549
550 DPRINT("KsFilterFactoryUpdateCacheData %p\n", FilterDescriptor);
551
552 if (!FilterDescriptor)
553 FilterDescriptor = Factory->FilterFactory.FilterDescriptor;
554
555 ASSERT(FilterDescriptor);
556
557 /* initialize cache descriptor */
558 RtlZeroMemory(&Descriptor, sizeof(KSPCACHE_DESCRIPTOR));
559
560 /* calculate filter data size */
561 Descriptor.FilterLength = sizeof(KSPCACHE_FILTER_HEADER);
562
563 /* FIXME support variable size pin descriptors */
564 ASSERT(FilterDescriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
565
566 for(Index = 0; Index < FilterDescriptor->PinDescriptorsCount; Index++)
567 {
568 /* add filter descriptor */
569 Descriptor.FilterLength += sizeof(KSPCACHE_PIN_HEADER);
570
571 if (FilterDescriptor->PinDescriptors[Index].PinDescriptor.Category)
572 {
573 /* add extra ULONG for offset to category */
574 Descriptor.FilterLength += sizeof(ULONG);
575
576 /* add size for clsid */
577 Descriptor.DataLength += sizeof(CLSID);
578 }
579
580 /* add space for formats */
581 Descriptor.FilterLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount * sizeof(KSPCACHE_DATARANGE);
582
583 /* add space for MajorFormat / MinorFormat */
584 Descriptor.DataLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount * sizeof(CLSID) * 2;
585
586 /* add space for mediums */
587 Descriptor.FilterLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount * sizeof(ULONG);
588
589 /* add space for the data */
590 Descriptor.DataLength += FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount * sizeof(KSPCACHE_MEDIUM);
591 }
592
593 /* now allocate the space */
594 Descriptor.FilterData = (PUCHAR)AllocateItem(NonPagedPool, Descriptor.DataLength + Descriptor.FilterLength);
595 if (!Descriptor.FilterData)
596 {
597 /* no memory */
598 return STATUS_INSUFFICIENT_RESOURCES;
599 }
600
601 /* initialize data cache */
602 Descriptor.DataCache = (PUCHAR)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterLength);
603
604 /* setup filter header */
605 FilterHeader = (PKSPCACHE_FILTER_HEADER)Descriptor.FilterData;
606
607 FilterHeader->dwVersion = 2;
608 FilterHeader->dwMerit = MERIT_DO_NOT_USE;
609 FilterHeader->dwUnused = 0;
610 FilterHeader->dwPins = FilterDescriptor->PinDescriptorsCount;
611
612 Descriptor.FilterOffset = sizeof(KSPCACHE_FILTER_HEADER);
613
614 /* write pin headers */
615 for(Index = 0; Index < FilterDescriptor->PinDescriptorsCount; Index++)
616 {
617 /* get offset to pin */
618 PinHeader = (PKSPCACHE_PIN_HEADER)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterOffset);
619
620 /* write pin header */
621 PinHeader->Signature = 0x33697030 + Index;
622 PinHeader->Flags = 0;
623 PinHeader->Instances = FilterDescriptor->PinDescriptors[Index].InstancesPossible;
624 if (PinHeader->Instances > 1)
625 PinHeader->Flags |= REG_PINFLAG_B_MANY;
626
627
628 PinHeader->MediaTypes = FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount;
629 PinHeader->Mediums = FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount;
630 PinHeader->Category = (FilterDescriptor->PinDescriptors[Index].PinDescriptor.Category ? TRUE : FALSE);
631
632 Descriptor.FilterOffset += sizeof(KSPCACHE_PIN_HEADER);
633
634 if (PinHeader->Category)
635 {
636 /* get category offset */
637 PULONG Category = (PULONG)(PinHeader + 1);
638
639 /* write category offset */
640 *Category = KspCacheAddData(&Descriptor, FilterDescriptor->PinDescriptors[Index].PinDescriptor.Category, sizeof(CLSID));
641
642 /* adjust offset */
643 Descriptor.FilterOffset += sizeof(ULONG);
644 }
645
646 /* add dataranges */
647 for(SubIndex = 0; SubIndex < FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRangesCount; SubIndex++)
648 {
649 /* get datarange offset */
650 PKSPCACHE_DATARANGE DataRange = (PKSPCACHE_DATARANGE)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterOffset);
651
652 /* initialize data range */
653 DataRange->Signature = 0x33797430 + SubIndex;
654 DataRange->dwUnused = 0;
655 DataRange->OffsetMajor = KspCacheAddData(&Descriptor, &FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRanges[SubIndex]->MajorFormat, sizeof(CLSID));
656 DataRange->OffsetMinor = KspCacheAddData(&Descriptor, &FilterDescriptor->PinDescriptors[Index].PinDescriptor.DataRanges[SubIndex]->SubFormat, sizeof(CLSID));
657
658 /* adjust offset */
659 Descriptor.FilterOffset += sizeof(KSPCACHE_DATARANGE);
660 }
661
662 /* add mediums */
663 for(SubIndex = 0; SubIndex < FilterDescriptor->PinDescriptors[Index].PinDescriptor.MediumsCount; SubIndex++)
664 {
665 KSPCACHE_MEDIUM Medium;
666 PULONG MediumOffset;
667
668 /* get pin medium offset */
669 MediumOffset = (PULONG)((ULONG_PTR)Descriptor.FilterData + Descriptor.FilterOffset);
670
671 /* copy medium guid */
672 RtlMoveMemory(&Medium.Medium, &FilterDescriptor->PinDescriptors[Index].PinDescriptor.Mediums[SubIndex].Set, sizeof(GUID));
673 Medium.dw1 = FilterDescriptor->PinDescriptors[Index].PinDescriptor.Mediums[SubIndex].Id; /* FIXME verify */
674 Medium.dw2 = 0;
675
676 *MediumOffset = KspCacheAddData(&Descriptor, &Medium, sizeof(KSPCACHE_MEDIUM));
677
678 /* adjust offset */
679 Descriptor.FilterOffset += sizeof(ULONG);
680 }
681 }
682
683 /* sanity checks */
684 ASSERT(Descriptor.FilterOffset == Descriptor.FilterLength);
685 ASSERT(Descriptor.DataOffset <= Descriptor.DataLength);
686
687
688 /* now go through all entries and update 'FilterData' key */
689 for(Index = 0; Index < FilterDescriptor->CategoriesCount; Index++)
690 {
691 /* get first entry */
692 Entry = Factory->SymbolicLinkList.Flink;
693
694 /* set status to not found */
695 Found = FALSE;
696 /* loop list until the the current category is found */
697 while(Entry != &Factory->SymbolicLinkList)
698 {
699 /* fetch symbolic link entry */
700 SymEntry = (PSYMBOLIC_LINK_ENTRY)CONTAINING_RECORD(Entry, SYMBOLIC_LINK_ENTRY, Entry);
701
702 if (IsEqualGUIDAligned(&SymEntry->DeviceInterfaceClass, &FilterDescriptor->Categories[Index]))
703 {
704 /* found category */
705 Found = TRUE;
706 break;
707 }
708
709 /* move to next entry */
710 Entry = Entry->Flink;
711 }
712
713 if (!Found)
714 {
715 /* filter category is not present */
716 Status = STATUS_INVALID_PARAMETER;
717 break;
718 }
719
720 /* now open device interface */
721 Status = IoOpenDeviceInterfaceRegistryKey(&SymEntry->SymbolicLink, KEY_WRITE, &hKey);
722 if (!NT_SUCCESS(Status))
723 {
724 /* failed to open interface key */
725 break;
726 }
727
728 /* update filterdata key */
729 Status = ZwSetValueKey(hKey, &FilterData, 0, REG_BINARY, Descriptor.FilterData, Descriptor.FilterLength + Descriptor.DataOffset);
730
731 /* close filterdata key */
732 ZwClose(hKey);
733
734 if (!NT_SUCCESS(Status))
735 {
736 /* failed to set key value */
737 break;
738 }
739 }
740 /* free filter data */
741 FreeItem(Descriptor.FilterData);
742
743 /* done */
744 return Status;
745 }
746