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