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