xref: /reactos/drivers/serial/serenum/misc.c (revision 3e1f4074)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Serial enumerator driver
4  * FILE:            drivers/dd/serenum/misc.c
5  * PURPOSE:         Miscellaneous operations
6  *
7  * PROGRAMMERS:     Herv� Poussineau (hpoussin@reactos.com)
8  */
9 
10 #include "serenum.h"
11 
12 #include <debug.h>
13 
14 /* I really want PCSZ strings as last arguments because
15  * PnP ids are ANSI-encoded in PnP device string
16  * identification */
17 NTSTATUS
18 SerenumInitMultiSzString(
19 	OUT PUNICODE_STRING Destination,
20 	... /* list of PCSZ */)
21 {
22 	va_list args;
23 	PCSZ Source;
24 	ANSI_STRING AnsiString;
25 	UNICODE_STRING UnicodeString;
26 	ULONG DestinationSize = 0;
27 	NTSTATUS Status = STATUS_SUCCESS;
28 
29 	ASSERT(Destination);
30 
31 	/* Calculate length needed for destination unicode string */
32 	va_start(args, Destination);
33 	Source = va_arg(args, PCSZ);
34 	while (Source != NULL)
35 	{
36 		RtlInitAnsiString(&AnsiString, Source);
37 		DestinationSize += RtlAnsiStringToUnicodeSize(&AnsiString)
38 			+ sizeof(WCHAR) /* final NULL */;
39 		Source = va_arg(args, PCSZ);
40 	}
41 	va_end(args);
42 	if (DestinationSize == 0)
43 	{
44 		RtlInitUnicodeString(Destination, NULL);
45 		return STATUS_SUCCESS;
46 	}
47 
48 	/* Initialize destination string */
49 	DestinationSize += sizeof(WCHAR); // final NULL
50 	Destination->Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, DestinationSize, SERENUM_TAG);
51 	if (!Destination->Buffer)
52 		return STATUS_INSUFFICIENT_RESOURCES;
53 	Destination->Length = 0;
54 	Destination->MaximumLength = (USHORT)DestinationSize;
55 
56 	/* Copy arguments to destination string */
57 	/* Use a temporary unicode string, which buffer is shared with
58 	 * destination string, to copy arguments */
59 	UnicodeString.Length = Destination->Length;
60 	UnicodeString.MaximumLength = Destination->MaximumLength;
61 	UnicodeString.Buffer = Destination->Buffer;
62 	va_start(args, Destination);
63 	Source = va_arg(args, PCSZ);
64 	while (Source != NULL)
65 	{
66 		RtlInitAnsiString(&AnsiString, Source);
67 		Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
68 		if (!NT_SUCCESS(Status))
69 		{
70 			ExFreePoolWithTag(Destination->Buffer, SERENUM_TAG);
71 			break;
72 		}
73 		Destination->Length += UnicodeString.Length + sizeof(WCHAR);
74 		UnicodeString.MaximumLength -= UnicodeString.Length + sizeof(WCHAR);
75 		UnicodeString.Buffer += UnicodeString.Length / sizeof(WCHAR) + 1;
76 		UnicodeString.Length = 0;
77 		Source = va_arg(args, PCSZ);
78 	}
79 	va_end(args);
80 	if (NT_SUCCESS(Status))
81 	{
82 		/* Finish multi-sz string */
83 		Destination->Buffer[Destination->Length / sizeof(WCHAR)] = L'\0';
84 		Destination->Length += sizeof(WCHAR);
85 	}
86 	return Status;
87 }
88 
89 NTSTATUS NTAPI
90 ForwardIrpToLowerDeviceAndForget(
91 	IN PDEVICE_OBJECT DeviceObject,
92 	IN PIRP Irp)
93 {
94 	PFDO_DEVICE_EXTENSION DeviceExtension;
95 	PDEVICE_OBJECT LowerDevice;
96 
97 	DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
98 	ASSERT(DeviceExtension->Common.IsFDO);
99 
100 	LowerDevice = DeviceExtension->LowerDevice;
101 	ASSERT(LowerDevice);
102 	TRACE_(SERENUM, "Calling lower device 0x%p\n", LowerDevice);
103 	IoSkipCurrentIrpStackLocation(Irp);
104 	return IoCallDriver(LowerDevice, Irp);
105 }
106 
107 NTSTATUS NTAPI
108 ForwardIrpToAttachedFdoAndForget(
109 	IN PDEVICE_OBJECT DeviceObject,
110 	IN PIRP Irp)
111 {
112 	PPDO_DEVICE_EXTENSION DeviceExtension;
113 	PDEVICE_OBJECT Fdo;
114 
115 	DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
116 	ASSERT(!DeviceExtension->Common.IsFDO);
117 
118 	Fdo = DeviceExtension->AttachedFdo;
119 	ASSERT(Fdo);
120 	TRACE_(SERENUM, "Calling attached Fdo 0x%p\n", Fdo);
121 	IoSkipCurrentIrpStackLocation(Irp);
122 	return IoCallDriver(Fdo, Irp);
123 }
124 
125 NTSTATUS NTAPI
126 ForwardIrpAndForget(
127 	IN PDEVICE_OBJECT DeviceObject,
128 	IN PIRP Irp)
129 {
130 	PDEVICE_OBJECT LowerDevice;
131 
132 	ASSERT(((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO);
133 	LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
134 	ASSERT(LowerDevice);
135 
136 	IoSkipCurrentIrpStackLocation(Irp);
137 	return IoCallDriver(LowerDevice, Irp);
138 }
139 
140 NTSTATUS
141 DuplicateUnicodeString(
142 	IN ULONG Flags,
143 	IN PCUNICODE_STRING SourceString,
144 	OUT PUNICODE_STRING DestinationString)
145 {
146 	if (SourceString == NULL || DestinationString == NULL
147 	 || SourceString->Length > SourceString->MaximumLength
148 	 || (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL)
149 	 || Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
150 	{
151 		return STATUS_INVALID_PARAMETER;
152 	}
153 
154 
155 	if ((SourceString->Length == 0)
156 	 && (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
157 	               RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
158 	{
159 		DestinationString->Length = 0;
160 		DestinationString->MaximumLength = 0;
161 		DestinationString->Buffer = NULL;
162 	}
163 	else
164 	{
165 		USHORT DestMaxLength = SourceString->Length;
166 
167 		if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
168 			DestMaxLength += sizeof(UNICODE_NULL);
169 
170 		DestinationString->Buffer = ExAllocatePoolWithTag(PagedPool, DestMaxLength, SERENUM_TAG);
171 		if (DestinationString->Buffer == NULL)
172 			return STATUS_NO_MEMORY;
173 
174 		RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
175 		DestinationString->Length = SourceString->Length;
176 		DestinationString->MaximumLength = DestMaxLength;
177 
178 		if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
179 			DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
180 	}
181 
182 	return STATUS_SUCCESS;
183 }
184