xref: /reactos/win32ss/printing/base/spoolss/tools.c (revision 595b846d)
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 }
71