xref: /reactos/win32ss/printing/base/spoolss/memory.c (revision 84ccccab)
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
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
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
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
112 DllFreeSplMem(PVOID pMem)
113 {
114     return HeapFree(hProcessHeap, 0, pMem);
115 }
116 
117 /**
118  * @name DllFreeSplStr
119  *
120  * Frees the string allocated with AllocSplStr.
121  *
122  * @param pwszString
123  * Pointer to the allocated string.
124  *
125  * @return
126  * TRUE in case of success, FALSE otherwise.
127  */
128 BOOL WINAPI
129 DllFreeSplStr(PWSTR pwszString)
130 {
131     return HeapFree(hProcessHeap, 0, pwszString);
132 }
133 
134 /**
135  * @name ReallocSplMem
136  *
137  * Allocates a new block of memory and copies the contents of the old block into the new one.
138  *
139  * @param pOldMem
140  * Pointer to the old block of memory.
141  * If this parameter is NULL, ReallocSplMem behaves exactly like DllAllocSplMem.
142  *
143  * @param cbOld
144  * Number of bytes to copy from the old block into the new one.
145  *
146  * @param cbNew
147  * Number of bytes to allocate for the new block.
148  *
149  * @return
150  * A pointer to the allocated new block or NULL in case of an error.
151  * You have to free this memory using DllFreeSplMem.
152  */
153 PVOID WINAPI
154 ReallocSplMem(PVOID pOldMem, DWORD cbOld, DWORD cbNew)
155 {
156     PVOID pNewMem;
157 
158     // Always allocate the new block of memory.
159     pNewMem = DllAllocSplMem(cbNew);
160     if (!pNewMem)
161     {
162         ERR("DllAllocSplMem failed!\n");
163         return NULL;
164     }
165 
166     // Copy the old memory into the new block and free it.
167     if (pOldMem)
168     {
169         CopyMemory(pNewMem, pOldMem, min(cbOld, cbNew));
170         DllFreeSplMem(pOldMem);
171     }
172 
173     return pNewMem;
174 }
175 
176 /**
177  * @name ReallocSplStr
178  *
179  * Frees a string allocated by AllocSplStr and copies the given Unicode string into a newly allocated block of memory.
180  *
181  * @param ppwszString
182  * Pointer to the string pointer allocated by AllocSplStr.
183  * When the function returns, the variable receives the pointer to the copied string.
184  *
185  * @param pwszInput
186  * The Unicode string to copy into the new block of memory.
187  *
188  * @return
189  * Returns TRUE in any case.
190 */
191 BOOL WINAPI
192 ReallocSplStr(PWSTR* ppwszString, PCWSTR pwszInput)
193 {
194     if (*ppwszString)
195         DllFreeSplStr(*ppwszString);
196 
197     *ppwszString = AllocSplStr(pwszInput);
198 
199     return TRUE;
200 }
201 
202 /**
203  * @name UndoAlignRpcPtr
204  *
205  * Copies the data from the aligned buffer previously allocated by AlignRpcPtr back to the original unaligned buffer.
206  * The aligned buffer is freed.
207  *
208  * Also aligns up the returned required buffer size of a function to a 4-byte boundary.
209  *
210  * @param pDestinationBuffer
211  * The original unaligned buffer, which you input as pBuffer to AlignRpcPtr.
212  * The data from pSourceBuffer is copied into this buffer before pSourceBuffer is freed.
213  * If AlignRpcPtr did not allocate a buffer, pDestinationBuffer equals pSourceBuffer and no memory is copied or freed.
214  * This parameter may be NULL if pSourceBuffer is NULL or cbBuffer is 0.
215  *
216  * @param pSourceBuffer
217  * The aligned buffer, which is returned by AlignRpcPtr.
218  * Its data is copied into pDestinationBuffer and then pSourceBuffer is freed.
219  * If AlignRpcPtr did not allocate a buffer, pDestinationBuffer equals pSourceBuffer and no memory is copied or freed.
220  * This parameter may be NULL.
221  *
222  * @param cbBuffer
223  * Number of bytes to copy.
224  * Set this to the size returned by AlignRpcPtr's pcbBuffer or less.
225  *
226  * @param pcbNeeded
227  * Let this parameter point to your variable calculating the needed bytes for a buffer and returning this value to the user.
228  * It is then aligned up to a 4-byte boundary, so that the user supplies a large enough buffer in the next call.
229  * Otherwise, AlignRpcPtr would align down the buffer size in the next call and your buffer would be smaller than intended.
230  * This parameter may be NULL.
231  *
232  * @return
233  * pcbNeeded
234  */
235 PDWORD WINAPI
236 UndoAlignRpcPtr(PVOID pDestinationBuffer, PVOID pSourceBuffer, DWORD cbBuffer, PDWORD pcbNeeded)
237 {
238     // pDestinationBuffer is accessed unless pSourceBuffer equals pDestinationBuffer or cbBuffer is 0.
239     ASSERT(pDestinationBuffer || pSourceBuffer == pDestinationBuffer || cbBuffer == 0);
240 
241     // If pSourceBuffer is given, and source and destination pointers don't match,
242     // we assume that pSourceBuffer is the buffer allocated by AlignRpcPtr.
243     if (pSourceBuffer && pSourceBuffer != pDestinationBuffer)
244     {
245         // Copy back the buffer data to the (usually unaligned) destination buffer
246         // and free the buffer allocated by AlignRpcPtr.
247         CopyMemory(pDestinationBuffer, pSourceBuffer, cbBuffer);
248         DllFreeSplMem(pSourceBuffer);
249     }
250 
251     // If pcbNeeded is given, align it up to a 4-byte boundary.
252     if (pcbNeeded && *pcbNeeded % sizeof(DWORD))
253         *pcbNeeded += sizeof(DWORD) - *pcbNeeded % sizeof(DWORD);
254 
255     return pcbNeeded;
256 }
257