1 /*
2 * PROJECT: ReactOS Spooler Router
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Functions for allocating and freeing memory
5 * COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
6 */
7
8 #include "precomp.h"
9
10
11 /**
12 * @name AlignRpcPtr
13 *
14 * Checks if the input buffer and buffer size are 4-byte aligned.
15 * If the buffer size is not 4-byte aligned, it is aligned down.
16 * If the input buffer is not 4-byte aligned, a 4-byte aligned buffer of the aligned down buffer size is allocated and returned.
17 *
18 * @param pBuffer
19 * The buffer to check.
20 *
21 * @param pcbBuffer
22 * Pointer to the buffer size to check. Its value is aligned down if needed.
23 *
24 * @return
25 * pBuffer if pBuffer is already 4-byte aligned, or a newly allocated 4-byte aligned buffer of the aligned down buffer size otherwise.
26 * If a buffer was allocated, you have to free it using UndoAlignRpcPtr.
27 */
28 PVOID WINAPI
AlignRpcPtr(PVOID pBuffer,PDWORD pcbBuffer)29 AlignRpcPtr(PVOID pBuffer, PDWORD pcbBuffer)
30 {
31 ASSERT(pcbBuffer);
32
33 // Align down the buffer size in pcbBuffer to a 4-byte boundary.
34 *pcbBuffer -= *pcbBuffer % sizeof(DWORD);
35
36 // Check if pBuffer is 4-byte aligned. If not, allocate a 4-byte aligned buffer.
37 if ((ULONG_PTR)pBuffer % sizeof(DWORD))
38 pBuffer = DllAllocSplMem(*pcbBuffer);
39
40 return pBuffer;
41 }
42
43 /**
44 * @name AllocSplStr
45 *
46 * Allocates memory for a Unicode string and copies the input string into it.
47 * Equivalent of wcsdup, but the returned buffer is allocated from the spooler heap and must be freed with DllFreeSplStr.
48 *
49 * @param pwszInput
50 * The input string to copy
51 *
52 * @return
53 * Pointer to the copied string or NULL if no memory could be allocated.
54 */
55 PWSTR WINAPI
AllocSplStr(PCWSTR pwszInput)56 AllocSplStr(PCWSTR pwszInput)
57 {
58 DWORD cbInput;
59 PWSTR pwszOutput;
60
61 // Sanity check
62 if (!pwszInput)
63 return NULL;
64
65 // Get the length of the input string.
66 cbInput = (wcslen(pwszInput) + 1) * sizeof(WCHAR);
67
68 // Allocate it. We don't use DllAllocSplMem here, because it unnecessarily zeroes the memory.
69 pwszOutput = HeapAlloc(hProcessHeap, 0, cbInput);
70 if (!pwszOutput)
71 {
72 ERR("HeapAlloc failed!\n");
73 return NULL;
74 }
75
76 // Copy the string and return it.
77 CopyMemory(pwszOutput, pwszInput, cbInput);
78 return pwszOutput;
79 }
80
81 /**
82 * @name DllAllocSplMem
83 *
84 * Allocate a block of zeroed memory.
85 * Windows allocates from a separate spooler heap here while we just use the process heap.
86 *
87 * @param dwBytes
88 * Number of bytes to allocate.
89 *
90 * @return
91 * A pointer to the allocated memory or NULL in case of an error.
92 * You have to free this memory using DllFreeSplMem.
93 */
94 PVOID WINAPI
DllAllocSplMem(DWORD dwBytes)95 DllAllocSplMem(DWORD dwBytes)
96 {
97 return HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwBytes);
98 }
99
100 /**
101 * @name DllFreeSplMem
102 *
103 * Frees the memory allocated with DllAllocSplMem.
104 *
105 * @param pMem
106 * Pointer to the allocated memory.
107 *
108 * @return
109 * TRUE in case of success, FALSE otherwise.
110 */
111 BOOL WINAPI
DllFreeSplMem(PVOID pMem)112 DllFreeSplMem(PVOID pMem)
113 {
114 if ( !pMem ) return TRUE;
115 return HeapFree(hProcessHeap, 0, pMem);
116 }
117
118 /**
119 * @name DllFreeSplStr
120 *
121 * Frees the string allocated with AllocSplStr.
122 *
123 * @param pwszString
124 * Pointer to the allocated string.
125 *
126 * @return
127 * TRUE in case of success, FALSE otherwise.
128 */
129 BOOL WINAPI
DllFreeSplStr(PWSTR pwszString)130 DllFreeSplStr(PWSTR pwszString)
131 {
132 if ( pwszString )
133 return HeapFree(hProcessHeap, 0, pwszString);
134 return FALSE;
135 }
136
137 /**
138 * @name ReallocSplMem
139 *
140 * Allocates a new block of memory and copies the contents of the old block into the new one.
141 *
142 * @param pOldMem
143 * Pointer to the old block of memory.
144 * If this parameter is NULL, ReallocSplMem behaves exactly like DllAllocSplMem.
145 *
146 * @param cbOld
147 * Number of bytes to copy from the old block into the new one.
148 *
149 * @param cbNew
150 * Number of bytes to allocate for the new block.
151 *
152 * @return
153 * A pointer to the allocated new block or NULL in case of an error.
154 * You have to free this memory using DllFreeSplMem.
155 */
156 PVOID WINAPI
ReallocSplMem(PVOID pOldMem,DWORD cbOld,DWORD cbNew)157 ReallocSplMem(PVOID pOldMem, DWORD cbOld, DWORD cbNew)
158 {
159 PVOID pNewMem;
160
161 // Always allocate the new block of memory.
162 pNewMem = DllAllocSplMem(cbNew);
163 if (!pNewMem)
164 {
165 ERR("DllAllocSplMem failed!\n");
166 return NULL;
167 }
168
169 // Copy the old memory into the new block and free it.
170 if (pOldMem)
171 {
172 CopyMemory(pNewMem, pOldMem, min(cbOld, cbNew));
173 DllFreeSplMem(pOldMem);
174 }
175
176 return pNewMem;
177 }
178
179 /**
180 * @name ReallocSplStr
181 *
182 * Frees a string allocated by AllocSplStr and copies the given Unicode string into a newly allocated block of memory.
183 *
184 * @param ppwszString
185 * Pointer to the string pointer allocated by AllocSplStr.
186 * When the function returns, the variable receives the pointer to the copied string.
187 *
188 * @param pwszInput
189 * The Unicode string to copy into the new block of memory.
190 *
191 * @return
192 * Returns TRUE in any case.
193 */
194 BOOL WINAPI
ReallocSplStr(PWSTR * ppwszString,PCWSTR pwszInput)195 ReallocSplStr(PWSTR* ppwszString, PCWSTR pwszInput)
196 {
197 if (*ppwszString)
198 DllFreeSplStr(*ppwszString);
199
200 *ppwszString = AllocSplStr(pwszInput);
201
202 return TRUE;
203 }
204
205 /**
206 * @name UndoAlignRpcPtr
207 *
208 * Copies the data from the aligned buffer previously allocated by AlignRpcPtr back to the original unaligned buffer.
209 * The aligned buffer is freed.
210 *
211 * Also aligns up the returned required buffer size of a function to a 4-byte boundary.
212 *
213 * @param pDestinationBuffer
214 * The original unaligned buffer, which you input as pBuffer to AlignRpcPtr.
215 * The data from pSourceBuffer is copied into this buffer before pSourceBuffer is freed.
216 * If AlignRpcPtr did not allocate a buffer, pDestinationBuffer equals pSourceBuffer and no memory is copied or freed.
217 * This parameter may be NULL if pSourceBuffer is NULL or cbBuffer is 0.
218 *
219 * @param pSourceBuffer
220 * The aligned buffer, which is returned by AlignRpcPtr.
221 * Its data is copied into pDestinationBuffer and then pSourceBuffer is freed.
222 * If AlignRpcPtr did not allocate a buffer, pDestinationBuffer equals pSourceBuffer and no memory is copied or freed.
223 * This parameter may be NULL.
224 *
225 * @param cbBuffer
226 * Number of bytes to copy.
227 * Set this to the size returned by AlignRpcPtr's pcbBuffer or less.
228 *
229 * @param pcbNeeded
230 * Let this parameter point to your variable calculating the needed bytes for a buffer and returning this value to the user.
231 * It is then aligned up to a 4-byte boundary, so that the user supplies a large enough buffer in the next call.
232 * Otherwise, AlignRpcPtr would align down the buffer size in the next call and your buffer would be smaller than intended.
233 * This parameter may be NULL.
234 *
235 * @return
236 * pcbNeeded
237 */
238 PDWORD WINAPI
UndoAlignRpcPtr(PVOID pDestinationBuffer,PVOID pSourceBuffer,DWORD cbBuffer,PDWORD pcbNeeded)239 UndoAlignRpcPtr(PVOID pDestinationBuffer, PVOID pSourceBuffer, DWORD cbBuffer, PDWORD pcbNeeded)
240 {
241 // pDestinationBuffer is accessed unless pSourceBuffer equals pDestinationBuffer or cbBuffer is 0.
242 ASSERT(pDestinationBuffer || pSourceBuffer == pDestinationBuffer || cbBuffer == 0);
243
244 // If pSourceBuffer is given, and source and destination pointers don't match,
245 // we assume that pSourceBuffer is the buffer allocated by AlignRpcPtr.
246 if (pSourceBuffer && pSourceBuffer != pDestinationBuffer)
247 {
248 // Copy back the buffer data to the (usually unaligned) destination buffer
249 // and free the buffer allocated by AlignRpcPtr.
250 CopyMemory(pDestinationBuffer, pSourceBuffer, cbBuffer);
251 DllFreeSplMem(pSourceBuffer);
252 }
253
254 // If pcbNeeded is given, align it up to a 4-byte boundary.
255 if (pcbNeeded && *pcbNeeded % sizeof(DWORD))
256 *pcbNeeded += sizeof(DWORD) - *pcbNeeded % sizeof(DWORD);
257
258 return pcbNeeded;
259 }
260