[PRINTING] Implement the undocumented MarshallDownStructure, MarshallDownStructuresAr...
[reactos.git] / win32ss / printing / base / spoolss / tools.c
1 /*
2 * PROJECT: ReactOS Spooler Router
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Miscellaneous tool functions
5 * COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
6 */
7
8 #include "precomp.h"
9
10
11 /**
12 * @name PackStrings
13 *
14 * Takes an array of Unicode strings and fills an output buffer with these strings at the end and pointers to each string at specific offsets.
15 * Useful helper for functions that copy an information structure including strings into a given buffer (like PRINTER_INFO_1).
16 *
17 * @param pSource
18 * The array of Unicode strings to copy. Needs to have at least as many elements as the DestOffsets array.
19 *
20 * @param pDest
21 * Pointer to the beginning of the output buffer.
22 * The caller is responsible for verifying that this buffer is large enough to hold all strings and pointers.
23 *
24 * @param DestOffsets
25 * Array of byte offsets in the output buffer. For each element of DestOffsets, the function will copy the address of the corresponding copied
26 * string of pSource to this location in the output buffer. If a string in pSource is NULL, the function will set the pointer address to NULL
27 * in the output buffer.
28 * Use macros like FIELD_OFFSET to calculate the offsets for this array.
29 * The last element of the array must have the value MAXDWORD to let the function detect the end of the array.
30 *
31 * @param pEnd
32 * Pointer to the end of the output buffer. That means the first element outside of the buffer given in pDest.
33 *
34 * @return
35 * Returns a pointer to the beginning of the strings in pDest.
36 * The strings are copied in reverse order, so this pointer will point to the last copied string of pSource.
37 */
38 PBYTE WINAPI
39 PackStrings(PWSTR* pSource, PBYTE pDest, const DWORD* DestOffsets, PBYTE pEnd)
40 {
41 DWORD cbString;
42 ULONG_PTR StringAddress;
43
44 // Loop until we reach an element with offset set to MAXDWORD.
45 while (*DestOffsets != MAXDWORD)
46 {
47 StringAddress = 0;
48
49 if (*pSource)
50 {
51 // Determine the length of the source string.
52 cbString = (wcslen(*pSource) + 1) * sizeof(WCHAR);
53
54 // Copy it before the last string.
55 pEnd -= cbString;
56 StringAddress = (ULONG_PTR)pEnd;
57 CopyMemory(pEnd, *pSource, cbString);
58 }
59
60 // Copy the address of the copied string to the location given by the offset.
61 CopyMemory(&pDest[*DestOffsets], &StringAddress, sizeof(ULONG_PTR));
62
63 // Advance to the next source string and destination offset.
64 pSource++;
65 DestOffsets++;
66 }
67
68 // pEnd is now at the last string we copied. Return this value as a pointer to the beginning of all strings in the output buffer.
69 return pEnd;
70 }