105b261ecSmrg/*
205b261ecSmrg   Copyright (c) 2002  XFree86 Inc
305b261ecSmrg*/
405b261ecSmrg
505b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
605b261ecSmrg#include <dix-config.h>
705b261ecSmrg#endif
805b261ecSmrg
905b261ecSmrg#include <stdio.h>
1005b261ecSmrg#include <string.h>
1105b261ecSmrg#include <X11/X.h>
1205b261ecSmrg#include <X11/Xproto.h>
1335c4bbdfSmrg#include <assert.h>
1405b261ecSmrg#include "misc.h"
1505b261ecSmrg#include "os.h"
1605b261ecSmrg#include "dixstruct.h"
1705b261ecSmrg#include "extnsionst.h"
1805b261ecSmrg#include "swaprep.h"
194642e01fSmrg#include "registry.h"
2005b261ecSmrg#include <X11/extensions/XResproto.h>
2105b261ecSmrg#include "pixmapstr.h"
2205b261ecSmrg#include "windowstr.h"
2305b261ecSmrg#include "gcstruct.h"
2435c4bbdfSmrg#include "extinit.h"
256747b715Smrg#include "protocol-versions.h"
2635c4bbdfSmrg#include "client.h"
2735c4bbdfSmrg#include "list.h"
2835c4bbdfSmrg#include "misc.h"
2935c4bbdfSmrg#include <string.h>
3035c4bbdfSmrg#include "hashtable.h"
3135c4bbdfSmrg#include "picturestr.h"
3235c4bbdfSmrg
3335c4bbdfSmrg#ifdef COMPOSITE
3435c4bbdfSmrg#include "compint.h"
3535c4bbdfSmrg#endif
3635c4bbdfSmrg
3735c4bbdfSmrg/** @brief Holds fragments of responses for ConstructClientIds.
3835c4bbdfSmrg *
3935c4bbdfSmrg *  note: there is no consideration for data alignment */
4035c4bbdfSmrgtypedef struct {
4135c4bbdfSmrg    struct xorg_list l;
4235c4bbdfSmrg    int   bytes;
4335c4bbdfSmrg    /* data follows */
4435c4bbdfSmrg} FragmentList;
4535c4bbdfSmrg
4635c4bbdfSmrg#define FRAGMENT_DATA(ptr) ((void*) ((char*) (ptr) + sizeof(FragmentList)))
4735c4bbdfSmrg
4835c4bbdfSmrg/** @brief Holds structure for the generated response to
4935c4bbdfSmrg           ProcXResQueryClientIds; used by ConstructClientId* -functions */
5035c4bbdfSmrgtypedef struct {
5135c4bbdfSmrg    int           numIds;
5235c4bbdfSmrg    int           resultBytes;
5335c4bbdfSmrg    struct xorg_list   response;
5435c4bbdfSmrg    int           sentClientMasks[MAXCLIENTS];
5535c4bbdfSmrg} ConstructClientIdCtx;
5635c4bbdfSmrg
5735c4bbdfSmrg/** @brief Holds the structure for information required to
5835c4bbdfSmrg           generate the response to XResQueryResourceBytes. In addition
5935c4bbdfSmrg           to response it contains information on the query as well,
6035c4bbdfSmrg           as well as some volatile information required by a few
6135c4bbdfSmrg           functions that cannot take that information directly
6235c4bbdfSmrg           via a parameter, as they are called via already-existing
6335c4bbdfSmrg           higher order functions. */
6435c4bbdfSmrgtypedef struct {
6535c4bbdfSmrg    ClientPtr     sendClient;
6635c4bbdfSmrg    int           numSizes;
6735c4bbdfSmrg    int           resultBytes;
6835c4bbdfSmrg    struct xorg_list response;
6935c4bbdfSmrg    int           status;
7035c4bbdfSmrg    long          numSpecs;
7135c4bbdfSmrg    xXResResourceIdSpec *specs;
7235c4bbdfSmrg    HashTable     visitedResources;
7335c4bbdfSmrg
7435c4bbdfSmrg    /* Used by AddSubResourceSizeSpec when AddResourceSizeValue is
755a112b11Smrg       handling cross-references */
7635c4bbdfSmrg    HashTable     visitedSubResources;
7735c4bbdfSmrg
7835c4bbdfSmrg    /* used when ConstructResourceBytesCtx is passed to
7935c4bbdfSmrg       AddResourceSizeValue2 via FindClientResourcesByType */
8035c4bbdfSmrg    RESTYPE       resType;
8135c4bbdfSmrg
8235c4bbdfSmrg    /* used when ConstructResourceBytesCtx is passed to
8335c4bbdfSmrg       AddResourceSizeValueByResource from ConstructResourceBytesByResource */
8435c4bbdfSmrg    xXResResourceIdSpec       *curSpec;
8535c4bbdfSmrg
8635c4bbdfSmrg    /** Used when iterating through a single resource's subresources
8735c4bbdfSmrg
8835c4bbdfSmrg        @see AddSubResourceSizeSpec */
8935c4bbdfSmrg    xXResResourceSizeValue    *sizeValue;
9035c4bbdfSmrg} ConstructResourceBytesCtx;
9135c4bbdfSmrg
9235c4bbdfSmrg/** @brief Allocate and add a sequence of bytes at the end of a fragment list.
9335c4bbdfSmrg           Call DestroyFragments to release the list.
9435c4bbdfSmrg
9535c4bbdfSmrg    @param frags A pointer to head of an initialized linked list
9635c4bbdfSmrg    @param bytes Number of bytes to allocate
9735c4bbdfSmrg    @return Returns a pointer to the allocated non-zeroed region
9835c4bbdfSmrg            that is to be filled by the caller. On error (out of memory)
9935c4bbdfSmrg            returns NULL and makes no changes to the list.
10035c4bbdfSmrg*/
10135c4bbdfSmrgstatic void *
10235c4bbdfSmrgAddFragment(struct xorg_list *frags, int bytes)
10335c4bbdfSmrg{
10435c4bbdfSmrg    FragmentList *f = malloc(sizeof(FragmentList) + bytes);
10535c4bbdfSmrg    if (!f) {
10635c4bbdfSmrg        return NULL;
10735c4bbdfSmrg    } else {
10835c4bbdfSmrg        f->bytes = bytes;
10935c4bbdfSmrg        xorg_list_add(&f->l, frags->prev);
11035c4bbdfSmrg        return (char*) f + sizeof(*f);
11135c4bbdfSmrg    }
11235c4bbdfSmrg}
11335c4bbdfSmrg
11435c4bbdfSmrg/** @brief Sends all fragments in the list to the client. Does not
11535c4bbdfSmrg           free anything.
11635c4bbdfSmrg
11735c4bbdfSmrg    @param client The client to send the fragments to
11835c4bbdfSmrg    @param frags The head of the list of fragments
11935c4bbdfSmrg*/
12035c4bbdfSmrgstatic void
12135c4bbdfSmrgWriteFragmentsToClient(ClientPtr client, struct xorg_list *frags)
12235c4bbdfSmrg{
12335c4bbdfSmrg    FragmentList *it;
12435c4bbdfSmrg    xorg_list_for_each_entry(it, frags, l) {
12535c4bbdfSmrg        WriteToClient(client, it->bytes, (char*) it + sizeof(*it));
12635c4bbdfSmrg    }
12735c4bbdfSmrg}
12835c4bbdfSmrg
12935c4bbdfSmrg/** @brief Frees a list of fragments. Does not free() root node.
13035c4bbdfSmrg
13135c4bbdfSmrg    @param frags The head of the list of fragments
13235c4bbdfSmrg*/
13335c4bbdfSmrgstatic void
13435c4bbdfSmrgDestroyFragments(struct xorg_list *frags)
13535c4bbdfSmrg{
13635c4bbdfSmrg    FragmentList *it, *tmp;
13735c4bbdfSmrg    xorg_list_for_each_entry_safe(it, tmp, frags, l) {
13835c4bbdfSmrg        xorg_list_del(&it->l);
13935c4bbdfSmrg        free(it);
14035c4bbdfSmrg    }
14135c4bbdfSmrg}
14235c4bbdfSmrg
14335c4bbdfSmrg/** @brief Constructs a context record for ConstructClientId* functions
14435c4bbdfSmrg           to use */
14535c4bbdfSmrgstatic void
14635c4bbdfSmrgInitConstructClientIdCtx(ConstructClientIdCtx *ctx)
14735c4bbdfSmrg{
14835c4bbdfSmrg    ctx->numIds = 0;
14935c4bbdfSmrg    ctx->resultBytes = 0;
15035c4bbdfSmrg    xorg_list_init(&ctx->response);
15135c4bbdfSmrg    memset(ctx->sentClientMasks, 0, sizeof(ctx->sentClientMasks));
15235c4bbdfSmrg}
15335c4bbdfSmrg
15435c4bbdfSmrg/** @brief Destroys a context record, releases all memory (except the storage
15535c4bbdfSmrg           for *ctx itself) */
15635c4bbdfSmrgstatic void
15735c4bbdfSmrgDestroyConstructClientIdCtx(ConstructClientIdCtx *ctx)
15835c4bbdfSmrg{
15935c4bbdfSmrg    DestroyFragments(&ctx->response);
16035c4bbdfSmrg}
16135c4bbdfSmrg
16235c4bbdfSmrgstatic Bool
16335c4bbdfSmrgInitConstructResourceBytesCtx(ConstructResourceBytesCtx *ctx,
16435c4bbdfSmrg                              ClientPtr                  sendClient,
16535c4bbdfSmrg                              long                       numSpecs,
16635c4bbdfSmrg                              xXResResourceIdSpec       *specs)
16735c4bbdfSmrg{
16835c4bbdfSmrg    ctx->sendClient = sendClient;
16935c4bbdfSmrg    ctx->numSizes = 0;
17035c4bbdfSmrg    ctx->resultBytes = 0;
17135c4bbdfSmrg    xorg_list_init(&ctx->response);
17235c4bbdfSmrg    ctx->status = Success;
17335c4bbdfSmrg    ctx->numSpecs = numSpecs;
17435c4bbdfSmrg    ctx->specs = specs;
17535c4bbdfSmrg    ctx->visitedResources = ht_create(sizeof(XID), 0,
17635c4bbdfSmrg                                      ht_resourceid_hash, ht_resourceid_compare,
17735c4bbdfSmrg                                      NULL);
17835c4bbdfSmrg
17935c4bbdfSmrg    if (!ctx->visitedResources) {
18035c4bbdfSmrg        return FALSE;
18135c4bbdfSmrg    } else {
18235c4bbdfSmrg        return TRUE;
18335c4bbdfSmrg    }
18435c4bbdfSmrg}
18535c4bbdfSmrg
18635c4bbdfSmrgstatic void
18735c4bbdfSmrgDestroyConstructResourceBytesCtx(ConstructResourceBytesCtx *ctx)
18835c4bbdfSmrg{
18935c4bbdfSmrg    DestroyFragments(&ctx->response);
19035c4bbdfSmrg    ht_destroy(ctx->visitedResources);
19135c4bbdfSmrg}
19205b261ecSmrg
19305b261ecSmrgstatic int
19435c4bbdfSmrgProcXResQueryVersion(ClientPtr client)
19535c4bbdfSmrg{
19635c4bbdfSmrg    xXResQueryVersionReply rep = {
19735c4bbdfSmrg        .type = X_Reply,
19835c4bbdfSmrg        .sequenceNumber = client->sequence,
19935c4bbdfSmrg        .length = 0,
20035c4bbdfSmrg        .server_major = SERVER_XRES_MAJOR_VERSION,
20135c4bbdfSmrg        .server_minor = SERVER_XRES_MINOR_VERSION
20235c4bbdfSmrg    };
20335c4bbdfSmrg
20435c4bbdfSmrg    REQUEST_SIZE_MATCH(xXResQueryVersionReq);
20535c4bbdfSmrg
20635c4bbdfSmrg    if (client->swapped) {
20735c4bbdfSmrg        swaps(&rep.sequenceNumber);
20835c4bbdfSmrg        swapl(&rep.length);
20935c4bbdfSmrg        swaps(&rep.server_major);
21035c4bbdfSmrg        swaps(&rep.server_minor);
21135c4bbdfSmrg    }
21235c4bbdfSmrg    WriteToClient(client, sizeof(xXResQueryVersionReply), &rep);
2136747b715Smrg    return Success;
21405b261ecSmrg}
21505b261ecSmrg
21605b261ecSmrgstatic int
21735c4bbdfSmrgProcXResQueryClients(ClientPtr client)
21805b261ecSmrg{
21905b261ecSmrg    /* REQUEST(xXResQueryClientsReq); */
22005b261ecSmrg    xXResQueryClientsReply rep;
22105b261ecSmrg    int *current_clients;
22205b261ecSmrg    int i, num_clients;
22305b261ecSmrg
22405b261ecSmrg    REQUEST_SIZE_MATCH(xXResQueryClientsReq);
22505b261ecSmrg
22635c4bbdfSmrg    current_clients = xallocarray(currentMaxClients, sizeof(int));
22705b261ecSmrg
22805b261ecSmrg    num_clients = 0;
22935c4bbdfSmrg    for (i = 0; i < currentMaxClients; i++) {
23035c4bbdfSmrg        if (clients[i]) {
23135c4bbdfSmrg            current_clients[num_clients] = i;
23235c4bbdfSmrg            num_clients++;
23335c4bbdfSmrg        }
23405b261ecSmrg    }
23505b261ecSmrg
23635c4bbdfSmrg    rep = (xXResQueryClientsReply) {
23735c4bbdfSmrg        .type = X_Reply,
23835c4bbdfSmrg        .sequenceNumber = client->sequence,
23935c4bbdfSmrg        .length = bytes_to_int32(num_clients * sz_xXResClient),
24035c4bbdfSmrg        .num_clients = num_clients
24135c4bbdfSmrg    };
24205b261ecSmrg    if (client->swapped) {
24335c4bbdfSmrg        swaps(&rep.sequenceNumber);
24435c4bbdfSmrg        swapl(&rep.length);
24535c4bbdfSmrg        swapl(&rep.num_clients);
24635c4bbdfSmrg    }
24735c4bbdfSmrg    WriteToClient(client, sizeof(xXResQueryClientsReply), &rep);
24835c4bbdfSmrg
24935c4bbdfSmrg    if (num_clients) {
25005b261ecSmrg        xXResClient scratch;
25105b261ecSmrg
25235c4bbdfSmrg        for (i = 0; i < num_clients; i++) {
25305b261ecSmrg            scratch.resource_base = clients[current_clients[i]]->clientAsMask;
25405b261ecSmrg            scratch.resource_mask = RESOURCE_ID_MASK;
25535c4bbdfSmrg
25635c4bbdfSmrg            if (client->swapped) {
25735c4bbdfSmrg                swapl(&scratch.resource_base);
25835c4bbdfSmrg                swapl(&scratch.resource_mask);
25905b261ecSmrg            }
26035c4bbdfSmrg            WriteToClient(client, sz_xXResClient, &scratch);
26105b261ecSmrg        }
26205b261ecSmrg    }
26305b261ecSmrg
2646747b715Smrg    free(current_clients);
26505b261ecSmrg
2666747b715Smrg    return Success;
26705b261ecSmrg}
26805b261ecSmrg
26905b261ecSmrgstatic void
27035c4bbdfSmrgResFindAllRes(void *value, XID id, RESTYPE type, void *cdata)
27105b261ecSmrg{
27235c4bbdfSmrg    int *counts = (int *) cdata;
27305b261ecSmrg
27405b261ecSmrg    counts[(type & TypeMask) - 1]++;
27505b261ecSmrg}
27605b261ecSmrg
2777e31ba66Smrgstatic CARD32
2787e31ba66SmrgresourceTypeAtom(int i)
2797e31ba66Smrg{
2807e31ba66Smrg    CARD32 ret;
2817e31ba66Smrg
2827e31ba66Smrg    const char *name = LookupResourceName(i);
2837e31ba66Smrg    if (strcmp(name, XREGISTRY_UNKNOWN))
2847e31ba66Smrg        ret = MakeAtom(name, strlen(name), TRUE);
2857e31ba66Smrg    else {
2867e31ba66Smrg        char buf[40];
2877e31ba66Smrg
2887e31ba66Smrg        snprintf(buf, sizeof(buf), "Unregistered resource %i", i + 1);
2897e31ba66Smrg        ret = MakeAtom(buf, strlen(buf), TRUE);
2907e31ba66Smrg    }
2917e31ba66Smrg
2927e31ba66Smrg    return ret;
2937e31ba66Smrg}
2947e31ba66Smrg
29505b261ecSmrgstatic int
29635c4bbdfSmrgProcXResQueryClientResources(ClientPtr client)
29705b261ecSmrg{
29805b261ecSmrg    REQUEST(xXResQueryClientResourcesReq);
29905b261ecSmrg    xXResQueryClientResourcesReply rep;
30005b261ecSmrg    int i, clientID, num_types;
30105b261ecSmrg    int *counts;
30205b261ecSmrg
30305b261ecSmrg    REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq);
30405b261ecSmrg
30505b261ecSmrg    clientID = CLIENT_ID(stuff->xid);
30605b261ecSmrg
30735c4bbdfSmrg    if ((clientID >= currentMaxClients) || !clients[clientID]) {
30805b261ecSmrg        client->errorValue = stuff->xid;
30905b261ecSmrg        return BadValue;
31005b261ecSmrg    }
31105b261ecSmrg
3126747b715Smrg    counts = calloc(lastResourceType + 1, sizeof(int));
31305b261ecSmrg
31405b261ecSmrg    FindAllClientResources(clients[clientID], ResFindAllRes, counts);
31505b261ecSmrg
31605b261ecSmrg    num_types = 0;
31705b261ecSmrg
31835c4bbdfSmrg    for (i = 0; i <= lastResourceType; i++) {
31935c4bbdfSmrg        if (counts[i])
32035c4bbdfSmrg            num_types++;
32105b261ecSmrg    }
32205b261ecSmrg
32335c4bbdfSmrg    rep = (xXResQueryClientResourcesReply) {
32435c4bbdfSmrg        .type = X_Reply,
32535c4bbdfSmrg        .sequenceNumber = client->sequence,
32635c4bbdfSmrg        .length = bytes_to_int32(num_types * sz_xXResType),
32735c4bbdfSmrg        .num_types = num_types
32835c4bbdfSmrg    };
32905b261ecSmrg    if (client->swapped) {
33035c4bbdfSmrg        swaps(&rep.sequenceNumber);
33135c4bbdfSmrg        swapl(&rep.length);
33235c4bbdfSmrg        swapl(&rep.num_types);
33335c4bbdfSmrg    }
33405b261ecSmrg
33535c4bbdfSmrg    WriteToClient(client, sizeof(xXResQueryClientResourcesReply), &rep);
33605b261ecSmrg
33735c4bbdfSmrg    if (num_types) {
33805b261ecSmrg        xXResType scratch;
33905b261ecSmrg
34035c4bbdfSmrg        for (i = 0; i < lastResourceType; i++) {
34135c4bbdfSmrg            if (!counts[i])
34235c4bbdfSmrg                continue;
34305b261ecSmrg
3447e31ba66Smrg            scratch.resource_type = resourceTypeAtom(i + 1);
34505b261ecSmrg            scratch.count = counts[i];
34605b261ecSmrg
34735c4bbdfSmrg            if (client->swapped) {
34835c4bbdfSmrg                swapl(&scratch.resource_type);
34935c4bbdfSmrg                swapl(&scratch.count);
35005b261ecSmrg            }
35135c4bbdfSmrg            WriteToClient(client, sz_xXResType, &scratch);
35205b261ecSmrg        }
35305b261ecSmrg    }
35405b261ecSmrg
3556747b715Smrg    free(counts);
35635c4bbdfSmrg
3576747b715Smrg    return Success;
35805b261ecSmrg}
35905b261ecSmrg
36035c4bbdfSmrgstatic void
36135c4bbdfSmrgResFindResourcePixmaps(void *value, XID id, RESTYPE type, void *cdata)
36205b261ecSmrg{
36335c4bbdfSmrg    SizeType sizeFunc = GetResourceTypeSizeFunc(type);
36435c4bbdfSmrg    ResourceSizeRec size = { 0, 0, 0 };
36535c4bbdfSmrg    unsigned long *bytes = cdata;
36605b261ecSmrg
36735c4bbdfSmrg    sizeFunc(value, id, &size);
36835c4bbdfSmrg    *bytes += size.pixmapRefSize;
36905b261ecSmrg}
37005b261ecSmrg
37105b261ecSmrgstatic int
37235c4bbdfSmrgProcXResQueryClientPixmapBytes(ClientPtr client)
37305b261ecSmrg{
37405b261ecSmrg    REQUEST(xXResQueryClientPixmapBytesReq);
37505b261ecSmrg    xXResQueryClientPixmapBytesReply rep;
37605b261ecSmrg    int clientID;
37705b261ecSmrg    unsigned long bytes;
37805b261ecSmrg
37905b261ecSmrg    REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq);
38005b261ecSmrg
38105b261ecSmrg    clientID = CLIENT_ID(stuff->xid);
38205b261ecSmrg
38335c4bbdfSmrg    if ((clientID >= currentMaxClients) || !clients[clientID]) {
38405b261ecSmrg        client->errorValue = stuff->xid;
38505b261ecSmrg        return BadValue;
38605b261ecSmrg    }
38705b261ecSmrg
38805b261ecSmrg    bytes = 0;
38905b261ecSmrg
3907e31ba66Smrg    FindAllClientResources(clients[clientID], ResFindResourcePixmaps,
3917e31ba66Smrg                           (void *) (&bytes));
39205b261ecSmrg
39335c4bbdfSmrg    rep = (xXResQueryClientPixmapBytesReply) {
39435c4bbdfSmrg        .type = X_Reply,
39535c4bbdfSmrg        .sequenceNumber = client->sequence,
39635c4bbdfSmrg        .length = 0,
39735c4bbdfSmrg        .bytes = bytes,
39805b261ecSmrg#ifdef _XSERVER64
39935c4bbdfSmrg        .bytes_overflow = bytes >> 32
40005b261ecSmrg#else
40135c4bbdfSmrg        .bytes_overflow = 0
40205b261ecSmrg#endif
40335c4bbdfSmrg    };
40405b261ecSmrg    if (client->swapped) {
40535c4bbdfSmrg        swaps(&rep.sequenceNumber);
40635c4bbdfSmrg        swapl(&rep.length);
40735c4bbdfSmrg        swapl(&rep.bytes);
40835c4bbdfSmrg        swapl(&rep.bytes_overflow);
40905b261ecSmrg    }
41035c4bbdfSmrg    WriteToClient(client, sizeof(xXResQueryClientPixmapBytesReply), &rep);
41105b261ecSmrg
4126747b715Smrg    return Success;
41305b261ecSmrg}
41405b261ecSmrg
41535c4bbdfSmrg/** @brief Finds out if a client's information need to be put into the
41635c4bbdfSmrg    response; marks client having been handled, if that is the case.
41735c4bbdfSmrg
41835c4bbdfSmrg    @param client   The client to send information about
41935c4bbdfSmrg    @param mask     The request mask (0 to send everything, otherwise a
42035c4bbdfSmrg                    bitmask of X_XRes*Mask)
42135c4bbdfSmrg    @param ctx      The context record that tells which clients and id types
42235c4bbdfSmrg                    have been already handled
42335c4bbdfSmrg    @param sendMask Which id type are we now considering. One of X_XRes*Mask.
42435c4bbdfSmrg
42535c4bbdfSmrg    @return Returns TRUE if the client information needs to be on the
42635c4bbdfSmrg            response, otherwise FALSE.
42735c4bbdfSmrg*/
42835c4bbdfSmrgstatic Bool
42935c4bbdfSmrgWillConstructMask(ClientPtr client, CARD32 mask,
43035c4bbdfSmrg                  ConstructClientIdCtx *ctx, int sendMask)
43135c4bbdfSmrg{
43235c4bbdfSmrg    if ((!mask || (mask & sendMask))
43335c4bbdfSmrg        && !(ctx->sentClientMasks[client->index] & sendMask)) {
43435c4bbdfSmrg        ctx->sentClientMasks[client->index] |= sendMask;
43535c4bbdfSmrg        return TRUE;
43635c4bbdfSmrg    } else {
43735c4bbdfSmrg        return FALSE;
43835c4bbdfSmrg    }
43935c4bbdfSmrg}
44035c4bbdfSmrg
44135c4bbdfSmrg/** @brief Constructs a response about a single client, based on a certain
44235c4bbdfSmrg           client id spec
44335c4bbdfSmrg
44435c4bbdfSmrg    @param sendClient Which client wishes to receive this answer. Used for
4455a112b11Smrg                      byte endianness.
44635c4bbdfSmrg    @param client     Which client are we considering.
44735c4bbdfSmrg    @param mask       The client id spec mask indicating which information
44835c4bbdfSmrg                      we want about this client.
44935c4bbdfSmrg    @param ctx        The context record containing the constructed response
45035c4bbdfSmrg                      and information on which clients and masks have been
45135c4bbdfSmrg                      already handled.
45235c4bbdfSmrg
45335c4bbdfSmrg    @return Return TRUE if everything went OK, otherwise FALSE which indicates
45435c4bbdfSmrg            a memory allocation problem.
45535c4bbdfSmrg*/
45635c4bbdfSmrgstatic Bool
45735c4bbdfSmrgConstructClientIdValue(ClientPtr sendClient, ClientPtr client, CARD32 mask,
45835c4bbdfSmrg                       ConstructClientIdCtx *ctx)
45935c4bbdfSmrg{
46035c4bbdfSmrg    xXResClientIdValue rep;
46135c4bbdfSmrg
46235c4bbdfSmrg    rep.spec.client = client->clientAsMask;
46335c4bbdfSmrg    if (client->swapped) {
46435c4bbdfSmrg        swapl (&rep.spec.client);
46535c4bbdfSmrg    }
46635c4bbdfSmrg
46735c4bbdfSmrg    if (WillConstructMask(client, mask, ctx, X_XResClientXIDMask)) {
46835c4bbdfSmrg        void *ptr = AddFragment(&ctx->response, sizeof(rep));
46935c4bbdfSmrg        if (!ptr) {
47035c4bbdfSmrg            return FALSE;
47135c4bbdfSmrg        }
47235c4bbdfSmrg
47335c4bbdfSmrg        rep.spec.mask = X_XResClientXIDMask;
47435c4bbdfSmrg        rep.length = 0;
47535c4bbdfSmrg        if (sendClient->swapped) {
47635c4bbdfSmrg            swapl (&rep.spec.mask);
47735c4bbdfSmrg            /* swapl (&rep.length, n); - not required for rep.length = 0 */
47835c4bbdfSmrg        }
47935c4bbdfSmrg
48035c4bbdfSmrg        memcpy(ptr, &rep, sizeof(rep));
48135c4bbdfSmrg
48235c4bbdfSmrg        ctx->resultBytes += sizeof(rep);
48335c4bbdfSmrg        ++ctx->numIds;
48435c4bbdfSmrg    }
48535c4bbdfSmrg    if (WillConstructMask(client, mask, ctx, X_XResLocalClientPIDMask)) {
48635c4bbdfSmrg        pid_t pid = GetClientPid(client);
48735c4bbdfSmrg
48835c4bbdfSmrg        if (pid != -1) {
48935c4bbdfSmrg            void *ptr = AddFragment(&ctx->response,
49035c4bbdfSmrg                                    sizeof(rep) + sizeof(CARD32));
49135c4bbdfSmrg            CARD32 *value = (void*) ((char*) ptr + sizeof(rep));
49235c4bbdfSmrg
49335c4bbdfSmrg            if (!ptr) {
49435c4bbdfSmrg                return FALSE;
49535c4bbdfSmrg            }
49635c4bbdfSmrg
49735c4bbdfSmrg            rep.spec.mask = X_XResLocalClientPIDMask;
49835c4bbdfSmrg            rep.length = 4;
49935c4bbdfSmrg
50035c4bbdfSmrg            if (sendClient->swapped) {
50135c4bbdfSmrg                swapl (&rep.spec.mask);
50235c4bbdfSmrg                swapl (&rep.length);
50335c4bbdfSmrg            }
50435c4bbdfSmrg
50535c4bbdfSmrg            if (sendClient->swapped) {
50635c4bbdfSmrg                swapl (value);
50735c4bbdfSmrg            }
50835c4bbdfSmrg            memcpy(ptr, &rep, sizeof(rep));
50935c4bbdfSmrg            *value = pid;
51035c4bbdfSmrg
51135c4bbdfSmrg            ctx->resultBytes += sizeof(rep) + sizeof(CARD32);
51235c4bbdfSmrg            ++ctx->numIds;
51335c4bbdfSmrg        }
51435c4bbdfSmrg    }
51535c4bbdfSmrg
51635c4bbdfSmrg    /* memory allocation errors earlier may return with FALSE */
51735c4bbdfSmrg    return TRUE;
51835c4bbdfSmrg}
51935c4bbdfSmrg
52035c4bbdfSmrg/** @brief Constructs a response about all clients, based on a client id specs
52135c4bbdfSmrg
52235c4bbdfSmrg    @param client   Which client which we are constructing the response for.
52335c4bbdfSmrg    @param numSpecs Number of client id specs in specs
52435c4bbdfSmrg    @param specs    Client id specs
52535c4bbdfSmrg
52635c4bbdfSmrg    @return Return Success if everything went OK, otherwise a Bad* (currently
52735c4bbdfSmrg            BadAlloc or BadValue)
52835c4bbdfSmrg*/
52935c4bbdfSmrgstatic int
53035c4bbdfSmrgConstructClientIds(ClientPtr client,
53135c4bbdfSmrg                   int numSpecs, xXResClientIdSpec* specs,
53235c4bbdfSmrg                   ConstructClientIdCtx *ctx)
53335c4bbdfSmrg{
53435c4bbdfSmrg    int specIdx;
53535c4bbdfSmrg
53635c4bbdfSmrg    for (specIdx = 0; specIdx < numSpecs; ++specIdx) {
53735c4bbdfSmrg        if (specs[specIdx].client == 0) {
53835c4bbdfSmrg            int c;
53935c4bbdfSmrg            for (c = 0; c < currentMaxClients; ++c) {
54035c4bbdfSmrg                if (clients[c]) {
54135c4bbdfSmrg                    if (!ConstructClientIdValue(client, clients[c],
54235c4bbdfSmrg                                                specs[specIdx].mask, ctx)) {
54335c4bbdfSmrg                        return BadAlloc;
54435c4bbdfSmrg                    }
54535c4bbdfSmrg                }
54635c4bbdfSmrg            }
54735c4bbdfSmrg        } else {
54835c4bbdfSmrg            int clientID = CLIENT_ID(specs[specIdx].client);
54935c4bbdfSmrg
55035c4bbdfSmrg            if ((clientID < currentMaxClients) && clients[clientID]) {
55135c4bbdfSmrg                if (!ConstructClientIdValue(client, clients[clientID],
55235c4bbdfSmrg                                            specs[specIdx].mask, ctx)) {
55335c4bbdfSmrg                    return BadAlloc;
55435c4bbdfSmrg                }
55535c4bbdfSmrg            }
55635c4bbdfSmrg        }
55735c4bbdfSmrg    }
55835c4bbdfSmrg
55935c4bbdfSmrg    /* memory allocation errors earlier may return with BadAlloc */
56035c4bbdfSmrg    return Success;
56135c4bbdfSmrg}
56235c4bbdfSmrg
56335c4bbdfSmrg/** @brief Response to XResQueryClientIds request introduced in XResProto v1.2
56435c4bbdfSmrg
56535c4bbdfSmrg    @param client Which client which we are constructing the response for.
56635c4bbdfSmrg
56735c4bbdfSmrg    @return Returns the value returned from ConstructClientIds with the same
56835c4bbdfSmrg            semantics
56935c4bbdfSmrg*/
57035c4bbdfSmrgstatic int
57135c4bbdfSmrgProcXResQueryClientIds (ClientPtr client)
57235c4bbdfSmrg{
57335c4bbdfSmrg    REQUEST(xXResQueryClientIdsReq);
57435c4bbdfSmrg
57535c4bbdfSmrg    xXResClientIdSpec        *specs = (void*) ((char*) stuff + sizeof(*stuff));
57635c4bbdfSmrg    int                       rc;
57735c4bbdfSmrg    ConstructClientIdCtx      ctx;
57835c4bbdfSmrg
57935c4bbdfSmrg    InitConstructClientIdCtx(&ctx);
58035c4bbdfSmrg
58135c4bbdfSmrg    REQUEST_AT_LEAST_SIZE(xXResQueryClientIdsReq);
58235c4bbdfSmrg    REQUEST_FIXED_SIZE(xXResQueryClientIdsReq,
58335c4bbdfSmrg                       stuff->numSpecs * sizeof(specs[0]));
58435c4bbdfSmrg
58535c4bbdfSmrg    rc = ConstructClientIds(client, stuff->numSpecs, specs, &ctx);
58635c4bbdfSmrg
58735c4bbdfSmrg    if (rc == Success) {
58835c4bbdfSmrg        xXResQueryClientIdsReply  rep = {
58935c4bbdfSmrg            .type = X_Reply,
59035c4bbdfSmrg            .sequenceNumber = client->sequence,
59135c4bbdfSmrg            .length = bytes_to_int32(ctx.resultBytes),
59235c4bbdfSmrg            .numIds = ctx.numIds
59335c4bbdfSmrg        };
59435c4bbdfSmrg
59535c4bbdfSmrg        assert((ctx.resultBytes & 3) == 0);
59635c4bbdfSmrg
59735c4bbdfSmrg        if (client->swapped) {
59835c4bbdfSmrg            swaps (&rep.sequenceNumber);
59935c4bbdfSmrg            swapl (&rep.length);
60035c4bbdfSmrg            swapl (&rep.numIds);
60135c4bbdfSmrg        }
60235c4bbdfSmrg
60335c4bbdfSmrg        WriteToClient(client, sizeof(rep), &rep);
60435c4bbdfSmrg        WriteFragmentsToClient(client, &ctx.response);
60535c4bbdfSmrg    }
60635c4bbdfSmrg
60735c4bbdfSmrg    DestroyConstructClientIdCtx(&ctx);
60835c4bbdfSmrg
60935c4bbdfSmrg    return rc;
61035c4bbdfSmrg}
61135c4bbdfSmrg
6125a112b11Smrg/** @brief Swaps xXResResourceIdSpec endianness */
61335c4bbdfSmrgstatic void
61435c4bbdfSmrgSwapXResResourceIdSpec(xXResResourceIdSpec *spec)
61535c4bbdfSmrg{
61635c4bbdfSmrg    swapl(&spec->resource);
61735c4bbdfSmrg    swapl(&spec->type);
61835c4bbdfSmrg}
61935c4bbdfSmrg
6205a112b11Smrg/** @brief Swaps xXResResourceSizeSpec endianness */
62135c4bbdfSmrgstatic void
62235c4bbdfSmrgSwapXResResourceSizeSpec(xXResResourceSizeSpec *size)
62335c4bbdfSmrg{
62435c4bbdfSmrg    SwapXResResourceIdSpec(&size->spec);
62535c4bbdfSmrg    swapl(&size->bytes);
62635c4bbdfSmrg    swapl(&size->refCount);
62735c4bbdfSmrg    swapl(&size->useCount);
62835c4bbdfSmrg}
62935c4bbdfSmrg
6305a112b11Smrg/** @brief Swaps xXResResourceSizeValue endianness */
63135c4bbdfSmrgstatic void
63235c4bbdfSmrgSwapXResResourceSizeValue(xXResResourceSizeValue *rep)
63335c4bbdfSmrg{
63435c4bbdfSmrg    SwapXResResourceSizeSpec(&rep->size);
63535c4bbdfSmrg    swapl(&rep->numCrossReferences);
63635c4bbdfSmrg}
63735c4bbdfSmrg
63835c4bbdfSmrg/** @brief Swaps the response bytes */
63935c4bbdfSmrgstatic void
64035c4bbdfSmrgSwapXResQueryResourceBytes(struct xorg_list *response)
64135c4bbdfSmrg{
64235c4bbdfSmrg    struct xorg_list *it = response->next;
64335c4bbdfSmrg    int c;
64435c4bbdfSmrg
64535c4bbdfSmrg    while (it != response) {
64635c4bbdfSmrg        xXResResourceSizeValue *value = FRAGMENT_DATA(it);
64735c4bbdfSmrg        it = it->next;
64835c4bbdfSmrg        for (c = 0; c < value->numCrossReferences; ++c) {
64935c4bbdfSmrg            xXResResourceSizeSpec *spec = FRAGMENT_DATA(it);
65035c4bbdfSmrg            SwapXResResourceSizeSpec(spec);
65135c4bbdfSmrg            it = it->next;
65235c4bbdfSmrg        }
65335c4bbdfSmrg        SwapXResResourceSizeValue(value);
65435c4bbdfSmrg    }
65535c4bbdfSmrg}
65635c4bbdfSmrg
65735c4bbdfSmrg/** @brief Adds xXResResourceSizeSpec describing a resource's size into
65835c4bbdfSmrg           the buffer contained in the context. The resource is considered
65935c4bbdfSmrg           to be a subresource.
66035c4bbdfSmrg
66135c4bbdfSmrg   @see AddResourceSizeValue
66235c4bbdfSmrg
66335c4bbdfSmrg   @param[in] value     The X resource object on which to add information
66435c4bbdfSmrg                        about to the buffer
66535c4bbdfSmrg   @param[in] id        The ID of the X resource
66635c4bbdfSmrg   @param[in] type      The type of the X resource
66735c4bbdfSmrg   @param[in/out] cdata The context object of type ConstructResourceBytesCtx.
66835c4bbdfSmrg                        Void pointer type is used here to satisfy the type
66935c4bbdfSmrg                        FindRes
67035c4bbdfSmrg*/
67135c4bbdfSmrgstatic void
67235c4bbdfSmrgAddSubResourceSizeSpec(void *value,
67335c4bbdfSmrg                       XID id,
67435c4bbdfSmrg                       RESTYPE type,
67535c4bbdfSmrg                       void *cdata)
67635c4bbdfSmrg{
67735c4bbdfSmrg    ConstructResourceBytesCtx *ctx = cdata;
67835c4bbdfSmrg
67935c4bbdfSmrg    if (ctx->status == Success) {
68035c4bbdfSmrg        xXResResourceSizeSpec **prevCrossRef =
68135c4bbdfSmrg          ht_find(ctx->visitedSubResources, &value);
68235c4bbdfSmrg        if (!prevCrossRef) {
68335c4bbdfSmrg            Bool ok = TRUE;
68435c4bbdfSmrg            xXResResourceSizeSpec *crossRef =
68535c4bbdfSmrg                AddFragment(&ctx->response, sizeof(xXResResourceSizeSpec));
68635c4bbdfSmrg            ok = ok && crossRef != NULL;
68735c4bbdfSmrg            if (ok) {
68835c4bbdfSmrg                xXResResourceSizeSpec **p;
68935c4bbdfSmrg                p = ht_add(ctx->visitedSubResources, &value);
69035c4bbdfSmrg                if (!p) {
69135c4bbdfSmrg                    ok = FALSE;
69235c4bbdfSmrg                } else {
69335c4bbdfSmrg                    *p = crossRef;
69435c4bbdfSmrg                }
69535c4bbdfSmrg            }
69635c4bbdfSmrg            if (!ok) {
69735c4bbdfSmrg                ctx->status = BadAlloc;
69835c4bbdfSmrg            } else {
69935c4bbdfSmrg                SizeType sizeFunc = GetResourceTypeSizeFunc(type);
70035c4bbdfSmrg                ResourceSizeRec size = { 0, 0, 0 };
70135c4bbdfSmrg                sizeFunc(value, id, &size);
70235c4bbdfSmrg
70335c4bbdfSmrg                crossRef->spec.resource = id;
7047e31ba66Smrg                crossRef->spec.type = resourceTypeAtom(type);
70535c4bbdfSmrg                crossRef->bytes = size.resourceSize;
70635c4bbdfSmrg                crossRef->refCount = size.refCnt;
70735c4bbdfSmrg                crossRef->useCount = 1;
70835c4bbdfSmrg
70935c4bbdfSmrg                ++ctx->sizeValue->numCrossReferences;
71035c4bbdfSmrg
71135c4bbdfSmrg                ctx->resultBytes += sizeof(*crossRef);
71235c4bbdfSmrg            }
71335c4bbdfSmrg        } else {
71435c4bbdfSmrg            /* if we have visited the subresource earlier (from current parent
71535c4bbdfSmrg               resource), just increase its use count by one */
71635c4bbdfSmrg            ++(*prevCrossRef)->useCount;
71735c4bbdfSmrg        }
71835c4bbdfSmrg    }
71935c4bbdfSmrg}
72035c4bbdfSmrg
72135c4bbdfSmrg/** @brief Adds xXResResourceSizeValue describing a resource's size into
72235c4bbdfSmrg           the buffer contained in the context. In addition, the
72335c4bbdfSmrg           subresources are iterated and added as xXResResourceSizeSpec's
72435c4bbdfSmrg           by using AddSubResourceSizeSpec
72535c4bbdfSmrg
72635c4bbdfSmrg   @see AddSubResourceSizeSpec
72735c4bbdfSmrg
72835c4bbdfSmrg   @param[in] value     The X resource object on which to add information
72935c4bbdfSmrg                        about to the buffer
73035c4bbdfSmrg   @param[in] id        The ID of the X resource
73135c4bbdfSmrg   @param[in] type      The type of the X resource
73235c4bbdfSmrg   @param[in/out] cdata The context object of type ConstructResourceBytesCtx.
73335c4bbdfSmrg                        Void pointer type is used here to satisfy the type
73435c4bbdfSmrg                        FindRes
73535c4bbdfSmrg*/
73635c4bbdfSmrgstatic void
73735c4bbdfSmrgAddResourceSizeValue(void *ptr, XID id, RESTYPE type, void *cdata)
73835c4bbdfSmrg{
73935c4bbdfSmrg    ConstructResourceBytesCtx *ctx = cdata;
74035c4bbdfSmrg    if (ctx->status == Success &&
74135c4bbdfSmrg        !ht_find(ctx->visitedResources, &id)) {
74235c4bbdfSmrg        Bool ok = TRUE;
74335c4bbdfSmrg        HashTable ht;
74435c4bbdfSmrg        HtGenericHashSetupRec htSetup = {
74535c4bbdfSmrg            .keySize = sizeof(void*)
74635c4bbdfSmrg        };
74735c4bbdfSmrg
74835c4bbdfSmrg        /* it doesn't matter that we don't undo the work done here
74935c4bbdfSmrg         * immediately. All but ht_init will be undone at the end
75035c4bbdfSmrg         * of the request and there can happen no failure after
75135c4bbdfSmrg         * ht_init, so we don't need to clean it up here in any
75235c4bbdfSmrg         * special way */
75335c4bbdfSmrg
75435c4bbdfSmrg        xXResResourceSizeValue *value =
75535c4bbdfSmrg            AddFragment(&ctx->response, sizeof(xXResResourceSizeValue));
75635c4bbdfSmrg        if (!value) {
75735c4bbdfSmrg            ok = FALSE;
75835c4bbdfSmrg        }
75935c4bbdfSmrg        ok = ok && ht_add(ctx->visitedResources, &id);
76035c4bbdfSmrg        if (ok) {
76135c4bbdfSmrg            ht = ht_create(htSetup.keySize,
76235c4bbdfSmrg                           sizeof(xXResResourceSizeSpec*),
76335c4bbdfSmrg                           ht_generic_hash, ht_generic_compare,
76435c4bbdfSmrg                           &htSetup);
76535c4bbdfSmrg            ok = ok && ht;
76635c4bbdfSmrg        }
76735c4bbdfSmrg
76835c4bbdfSmrg        if (!ok) {
76935c4bbdfSmrg            ctx->status = BadAlloc;
77035c4bbdfSmrg        } else {
77135c4bbdfSmrg            SizeType sizeFunc = GetResourceTypeSizeFunc(type);
77235c4bbdfSmrg            ResourceSizeRec size = { 0, 0, 0 };
77335c4bbdfSmrg
77435c4bbdfSmrg            sizeFunc(ptr, id, &size);
77535c4bbdfSmrg
77635c4bbdfSmrg            value->size.spec.resource = id;
7777e31ba66Smrg            value->size.spec.type = resourceTypeAtom(type);
77835c4bbdfSmrg            value->size.bytes = size.resourceSize;
77935c4bbdfSmrg            value->size.refCount = size.refCnt;
78035c4bbdfSmrg            value->size.useCount = 1;
78135c4bbdfSmrg            value->numCrossReferences = 0;
78235c4bbdfSmrg
78335c4bbdfSmrg            ctx->sizeValue = value;
78435c4bbdfSmrg            ctx->visitedSubResources = ht;
78535c4bbdfSmrg            FindSubResources(ptr, type, AddSubResourceSizeSpec, ctx);
78635c4bbdfSmrg            ctx->visitedSubResources = NULL;
78735c4bbdfSmrg            ctx->sizeValue = NULL;
78835c4bbdfSmrg
78935c4bbdfSmrg            ctx->resultBytes += sizeof(*value);
79035c4bbdfSmrg            ++ctx->numSizes;
79135c4bbdfSmrg
79235c4bbdfSmrg            ht_destroy(ht);
79335c4bbdfSmrg        }
79435c4bbdfSmrg    }
79535c4bbdfSmrg}
79635c4bbdfSmrg
79735c4bbdfSmrg/** @brief A variant of AddResourceSizeValue that passes the resource type
79835c4bbdfSmrg           through the context object to satisfy the type FindResType
79935c4bbdfSmrg
80035c4bbdfSmrg   @see AddResourceSizeValue
80135c4bbdfSmrg
80235c4bbdfSmrg   @param[in] ptr        The resource
80335c4bbdfSmrg   @param[in] id         The resource ID
80435c4bbdfSmrg   @param[in/out] cdata  The context object that contains the resource type
80535c4bbdfSmrg*/
80635c4bbdfSmrgstatic void
80735c4bbdfSmrgAddResourceSizeValueWithResType(void *ptr, XID id, void *cdata)
80835c4bbdfSmrg{
80935c4bbdfSmrg    ConstructResourceBytesCtx *ctx = cdata;
81035c4bbdfSmrg    AddResourceSizeValue(ptr, id, ctx->resType, cdata);
81135c4bbdfSmrg}
81235c4bbdfSmrg
81335c4bbdfSmrg/** @brief Adds the information of a resource into the buffer if it matches
81435c4bbdfSmrg           the match condition.
81535c4bbdfSmrg
81635c4bbdfSmrg   @see AddResourceSizeValue
81735c4bbdfSmrg
81835c4bbdfSmrg   @param[in] ptr        The resource
81935c4bbdfSmrg   @param[in] id         The resource ID
82035c4bbdfSmrg   @param[in] type       The resource type
82135c4bbdfSmrg   @param[in/out] cdata  The context object as a void pointer to satisfy the
82235c4bbdfSmrg                         type FindAllRes
82335c4bbdfSmrg*/
82435c4bbdfSmrgstatic void
82535c4bbdfSmrgAddResourceSizeValueByResource(void *ptr, XID id, RESTYPE type, void *cdata)
82635c4bbdfSmrg{
82735c4bbdfSmrg    ConstructResourceBytesCtx *ctx = cdata;
82835c4bbdfSmrg    xXResResourceIdSpec *spec = ctx->curSpec;
82935c4bbdfSmrg
83035c4bbdfSmrg    if ((!spec->type || spec->type == type) &&
83135c4bbdfSmrg        (!spec->resource || spec->resource == id)) {
83235c4bbdfSmrg        AddResourceSizeValue(ptr, id, type, ctx);
83335c4bbdfSmrg    }
83435c4bbdfSmrg}
83535c4bbdfSmrg
83635c4bbdfSmrg/** @brief Add all resources of the client into the result buffer
83735c4bbdfSmrg           disregarding all those specifications that specify the
83835c4bbdfSmrg           resource by its ID. Those are handled by
83935c4bbdfSmrg           ConstructResourceBytesByResource
84035c4bbdfSmrg
84135c4bbdfSmrg   @see ConstructResourceBytesByResource
84235c4bbdfSmrg
84335c4bbdfSmrg   @param[in] aboutClient  Which client is being considered
84435c4bbdfSmrg   @param[in/out] ctx      The context that contains the resource id
84535c4bbdfSmrg                           specifications as well as the result buffer
84635c4bbdfSmrg*/
84735c4bbdfSmrgstatic void
84835c4bbdfSmrgConstructClientResourceBytes(ClientPtr aboutClient,
84935c4bbdfSmrg                             ConstructResourceBytesCtx *ctx)
85035c4bbdfSmrg{
85135c4bbdfSmrg    int specIdx;
85235c4bbdfSmrg    for (specIdx = 0; specIdx < ctx->numSpecs; ++specIdx) {
85335c4bbdfSmrg        xXResResourceIdSpec* spec = ctx->specs + specIdx;
85435c4bbdfSmrg        if (spec->resource) {
85535c4bbdfSmrg            /* these specs are handled elsewhere */
85635c4bbdfSmrg        } else if (spec->type) {
85735c4bbdfSmrg            ctx->resType = spec->type;
85835c4bbdfSmrg            FindClientResourcesByType(aboutClient, spec->type,
85935c4bbdfSmrg                                      AddResourceSizeValueWithResType, ctx);
86035c4bbdfSmrg        } else {
86135c4bbdfSmrg            FindAllClientResources(aboutClient, AddResourceSizeValue, ctx);
86235c4bbdfSmrg        }
86335c4bbdfSmrg    }
86435c4bbdfSmrg}
86535c4bbdfSmrg
86635c4bbdfSmrg/** @brief Add the sizes of all such resources that can are specified by
86735c4bbdfSmrg           their ID in the resource id specification. The scan can
86835c4bbdfSmrg           by limited to a client with the aboutClient parameter
86935c4bbdfSmrg
87035c4bbdfSmrg   @see ConstructResourceBytesByResource
87135c4bbdfSmrg
87235c4bbdfSmrg   @param[in] aboutClient  Which client is being considered. This may be None
87335c4bbdfSmrg                           to mean all clients.
87435c4bbdfSmrg   @param[in/out] ctx      The context that contains the resource id
87535c4bbdfSmrg                           specifications as well as the result buffer. In
87635c4bbdfSmrg                           addition this function uses the curSpec field to
87735c4bbdfSmrg                           keep a pointer to the current resource id
87835c4bbdfSmrg                           specification in it, which can be used by
87935c4bbdfSmrg                           AddResourceSizeValueByResource .
88035c4bbdfSmrg*/
88135c4bbdfSmrgstatic void
88235c4bbdfSmrgConstructResourceBytesByResource(XID aboutClient, ConstructResourceBytesCtx *ctx)
88335c4bbdfSmrg{
88435c4bbdfSmrg    int specIdx;
88535c4bbdfSmrg    for (specIdx = 0; specIdx < ctx->numSpecs; ++specIdx) {
88635c4bbdfSmrg        xXResResourceIdSpec *spec = ctx->specs + specIdx;
88735c4bbdfSmrg        if (spec->resource) {
88835c4bbdfSmrg            int cid = CLIENT_ID(spec->resource);
88935c4bbdfSmrg            if (cid < currentMaxClients &&
89035c4bbdfSmrg                (aboutClient == None || cid == aboutClient)) {
89135c4bbdfSmrg                ClientPtr client = clients[cid];
89235c4bbdfSmrg                if (client) {
89335c4bbdfSmrg                    ctx->curSpec = spec;
89435c4bbdfSmrg                    FindAllClientResources(client,
89535c4bbdfSmrg                                           AddResourceSizeValueByResource,
89635c4bbdfSmrg                                           ctx);
89735c4bbdfSmrg                }
89835c4bbdfSmrg            }
89935c4bbdfSmrg        }
90035c4bbdfSmrg    }
90135c4bbdfSmrg}
90235c4bbdfSmrg
90335c4bbdfSmrg/** @brief Build the resource size response for the given client
90435c4bbdfSmrg           (or all if not specified) per the parameters set up
90535c4bbdfSmrg           in the context object.
90635c4bbdfSmrg
90735c4bbdfSmrg  @param[in] aboutClient  Which client to consider or None for all clients
90835c4bbdfSmrg  @param[in/out] ctx      The context object that contains the request as well
90935c4bbdfSmrg                          as the response buffer.
91035c4bbdfSmrg*/
91105b261ecSmrgstatic int
91235c4bbdfSmrgConstructResourceBytes(XID aboutClient,
91335c4bbdfSmrg                       ConstructResourceBytesCtx *ctx)
91435c4bbdfSmrg{
91535c4bbdfSmrg    if (aboutClient) {
91635c4bbdfSmrg        int clientIdx = CLIENT_ID(aboutClient);
91735c4bbdfSmrg        ClientPtr client = NullClient;
91835c4bbdfSmrg
91935c4bbdfSmrg        if ((clientIdx >= currentMaxClients) || !clients[clientIdx]) {
92035c4bbdfSmrg            ctx->sendClient->errorValue = aboutClient;
92135c4bbdfSmrg            return BadValue;
92235c4bbdfSmrg        }
92335c4bbdfSmrg
92435c4bbdfSmrg        client = clients[clientIdx];
92535c4bbdfSmrg
92635c4bbdfSmrg        ConstructClientResourceBytes(client, ctx);
92735c4bbdfSmrg        ConstructResourceBytesByResource(aboutClient, ctx);
92835c4bbdfSmrg    } else {
92935c4bbdfSmrg        int clientIdx;
93035c4bbdfSmrg
93135c4bbdfSmrg        ConstructClientResourceBytes(NULL, ctx);
93235c4bbdfSmrg
93335c4bbdfSmrg        for (clientIdx = 0; clientIdx < currentMaxClients; ++clientIdx) {
93435c4bbdfSmrg            ClientPtr client = clients[clientIdx];
93535c4bbdfSmrg
93635c4bbdfSmrg            if (client) {
93735c4bbdfSmrg                ConstructClientResourceBytes(client, ctx);
93835c4bbdfSmrg            }
93935c4bbdfSmrg        }
94035c4bbdfSmrg
94135c4bbdfSmrg        ConstructResourceBytesByResource(None, ctx);
94235c4bbdfSmrg    }
94335c4bbdfSmrg
94435c4bbdfSmrg
94535c4bbdfSmrg    return ctx->status;
94635c4bbdfSmrg}
94735c4bbdfSmrg
94835c4bbdfSmrg/** @brief Implements the XResQueryResourceBytes of XResProto v1.2 */
94935c4bbdfSmrgstatic int
95035c4bbdfSmrgProcXResQueryResourceBytes (ClientPtr client)
95135c4bbdfSmrg{
95235c4bbdfSmrg    REQUEST(xXResQueryResourceBytesReq);
95335c4bbdfSmrg
95435c4bbdfSmrg    int                          rc;
95535c4bbdfSmrg    ConstructResourceBytesCtx    ctx;
95635c4bbdfSmrg
95735c4bbdfSmrg    REQUEST_AT_LEAST_SIZE(xXResQueryResourceBytesReq);
9586e78d31fSmrg    if (stuff->numSpecs > UINT32_MAX / sizeof(ctx.specs[0]))
9596e78d31fSmrg        return BadLength;
96035c4bbdfSmrg    REQUEST_FIXED_SIZE(xXResQueryResourceBytesReq,
96135c4bbdfSmrg                       stuff->numSpecs * sizeof(ctx.specs[0]));
96235c4bbdfSmrg
96335c4bbdfSmrg    if (!InitConstructResourceBytesCtx(&ctx, client,
96435c4bbdfSmrg                                       stuff->numSpecs,
96535c4bbdfSmrg                                       (void*) ((char*) stuff +
96635c4bbdfSmrg                                                sz_xXResQueryResourceBytesReq))) {
96735c4bbdfSmrg        return BadAlloc;
96835c4bbdfSmrg    }
96935c4bbdfSmrg
97035c4bbdfSmrg    rc = ConstructResourceBytes(stuff->client, &ctx);
97135c4bbdfSmrg
97235c4bbdfSmrg    if (rc == Success) {
97335c4bbdfSmrg        xXResQueryResourceBytesReply rep = {
97435c4bbdfSmrg            .type = X_Reply,
97535c4bbdfSmrg            .sequenceNumber = client->sequence,
97635c4bbdfSmrg            .length = bytes_to_int32(ctx.resultBytes),
97735c4bbdfSmrg            .numSizes = ctx.numSizes
97835c4bbdfSmrg        };
97935c4bbdfSmrg
98035c4bbdfSmrg        if (client->swapped) {
98135c4bbdfSmrg            swaps (&rep.sequenceNumber);
98235c4bbdfSmrg            swapl (&rep.length);
98335c4bbdfSmrg            swapl (&rep.numSizes);
98435c4bbdfSmrg
98535c4bbdfSmrg            SwapXResQueryResourceBytes(&ctx.response);
98635c4bbdfSmrg        }
98735c4bbdfSmrg
98835c4bbdfSmrg        WriteToClient(client, sizeof(rep), &rep);
98935c4bbdfSmrg        WriteFragmentsToClient(client, &ctx.response);
99035c4bbdfSmrg    }
99135c4bbdfSmrg
99235c4bbdfSmrg    DestroyConstructResourceBytesCtx(&ctx);
99335c4bbdfSmrg
99435c4bbdfSmrg    return rc;
99535c4bbdfSmrg}
99635c4bbdfSmrg
99735c4bbdfSmrgstatic int
99835c4bbdfSmrgProcResDispatch(ClientPtr client)
99905b261ecSmrg{
100005b261ecSmrg    REQUEST(xReq);
100105b261ecSmrg    switch (stuff->data) {
100205b261ecSmrg    case X_XResQueryVersion:
100305b261ecSmrg        return ProcXResQueryVersion(client);
100405b261ecSmrg    case X_XResQueryClients:
100505b261ecSmrg        return ProcXResQueryClients(client);
100605b261ecSmrg    case X_XResQueryClientResources:
100705b261ecSmrg        return ProcXResQueryClientResources(client);
100805b261ecSmrg    case X_XResQueryClientPixmapBytes:
100905b261ecSmrg        return ProcXResQueryClientPixmapBytes(client);
101035c4bbdfSmrg    case X_XResQueryClientIds:
101135c4bbdfSmrg        return ProcXResQueryClientIds(client);
101235c4bbdfSmrg    case X_XResQueryResourceBytes:
101335c4bbdfSmrg        return ProcXResQueryResourceBytes(client);
101405b261ecSmrg    default: break;
101505b261ecSmrg    }
101605b261ecSmrg
101705b261ecSmrg    return BadRequest;
101805b261ecSmrg}
101905b261ecSmrg
10207e31ba66Smrgstatic int _X_COLD
102135c4bbdfSmrgSProcXResQueryVersion(ClientPtr client)
102205b261ecSmrg{
102335c4bbdfSmrg    REQUEST_SIZE_MATCH(xXResQueryVersionReq);
102405b261ecSmrg    return ProcXResQueryVersion(client);
102505b261ecSmrg}
102605b261ecSmrg
10277e31ba66Smrgstatic int _X_COLD
102835c4bbdfSmrgSProcXResQueryClientResources(ClientPtr client)
102905b261ecSmrg{
103005b261ecSmrg    REQUEST(xXResQueryClientResourcesReq);
103135c4bbdfSmrg    REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq);
103235c4bbdfSmrg    swapl(&stuff->xid);
103305b261ecSmrg    return ProcXResQueryClientResources(client);
103405b261ecSmrg}
103505b261ecSmrg
10367e31ba66Smrgstatic int _X_COLD
103735c4bbdfSmrgSProcXResQueryClientPixmapBytes(ClientPtr client)
103805b261ecSmrg{
103905b261ecSmrg    REQUEST(xXResQueryClientPixmapBytesReq);
104035c4bbdfSmrg    REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq);
104135c4bbdfSmrg    swapl(&stuff->xid);
104205b261ecSmrg    return ProcXResQueryClientPixmapBytes(client);
104305b261ecSmrg}
104405b261ecSmrg
10457e31ba66Smrgstatic int _X_COLD
104635c4bbdfSmrgSProcXResQueryClientIds (ClientPtr client)
104735c4bbdfSmrg{
104835c4bbdfSmrg    REQUEST(xXResQueryClientIdsReq);
104935c4bbdfSmrg
105035c4bbdfSmrg    REQUEST_AT_LEAST_SIZE (xXResQueryClientIdsReq);
105135c4bbdfSmrg    swapl(&stuff->numSpecs);
105235c4bbdfSmrg    return ProcXResQueryClientIds(client);
105335c4bbdfSmrg}
105435c4bbdfSmrg
105535c4bbdfSmrg/** @brief Implements the XResQueryResourceBytes of XResProto v1.2.
105635c4bbdfSmrg    This variant byteswaps request contents before issuing the
105735c4bbdfSmrg    rest of the work to ProcXResQueryResourceBytes */
10587e31ba66Smrgstatic int _X_COLD
105935c4bbdfSmrgSProcXResQueryResourceBytes (ClientPtr client)
106035c4bbdfSmrg{
106135c4bbdfSmrg    REQUEST(xXResQueryResourceBytesReq);
106235c4bbdfSmrg    int c;
106335c4bbdfSmrg    xXResResourceIdSpec *specs = (void*) ((char*) stuff + sizeof(*stuff));
106435c4bbdfSmrg
106535c4bbdfSmrg    REQUEST_AT_LEAST_SIZE(xXResQueryResourceBytesReq);
10666e78d31fSmrg    swapl(&stuff->numSpecs);
106735c4bbdfSmrg    REQUEST_FIXED_SIZE(xXResQueryResourceBytesReq,
106835c4bbdfSmrg                       stuff->numSpecs * sizeof(specs[0]));
106935c4bbdfSmrg
107035c4bbdfSmrg    for (c = 0; c < stuff->numSpecs; ++c) {
107135c4bbdfSmrg        SwapXResResourceIdSpec(specs + c);
107235c4bbdfSmrg    }
107335c4bbdfSmrg
107435c4bbdfSmrg    return ProcXResQueryResourceBytes(client);
107535c4bbdfSmrg}
107635c4bbdfSmrg
10777e31ba66Smrgstatic int _X_COLD
107805b261ecSmrgSProcResDispatch (ClientPtr client)
107905b261ecSmrg{
108005b261ecSmrg    REQUEST(xReq);
108135c4bbdfSmrg    swaps(&stuff->length);
108205b261ecSmrg
108305b261ecSmrg    switch (stuff->data) {
108405b261ecSmrg    case X_XResQueryVersion:
108505b261ecSmrg        return SProcXResQueryVersion(client);
108635c4bbdfSmrg    case X_XResQueryClients:   /* nothing to swap */
108705b261ecSmrg        return ProcXResQueryClients(client);
108805b261ecSmrg    case X_XResQueryClientResources:
108905b261ecSmrg        return SProcXResQueryClientResources(client);
109005b261ecSmrg    case X_XResQueryClientPixmapBytes:
109105b261ecSmrg        return SProcXResQueryClientPixmapBytes(client);
109235c4bbdfSmrg    case X_XResQueryClientIds:
109335c4bbdfSmrg        return SProcXResQueryClientIds(client);
109435c4bbdfSmrg    case X_XResQueryResourceBytes:
109535c4bbdfSmrg        return SProcXResQueryResourceBytes(client);
109605b261ecSmrg    default: break;
109705b261ecSmrg    }
109805b261ecSmrg
109905b261ecSmrg    return BadRequest;
110005b261ecSmrg}
110105b261ecSmrg
110205b261ecSmrgvoid
110335c4bbdfSmrgResExtensionInit(void)
110405b261ecSmrg{
110505b261ecSmrg    (void) AddExtension(XRES_NAME, 0, 0,
110635c4bbdfSmrg                        ProcResDispatch, SProcResDispatch,
110735c4bbdfSmrg                        NULL, StandardMinorOpcode);
110805b261ecSmrg}
1109