rpcrt4_main.c 20.9 KB
Newer Older
Huw D M Davies's avatar
Huw D M Davies committed
1 2 3
/*
 *  RPCRT4
 *
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright 2000 Huw D M Davies for Codeweavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
 * 
 * WINE RPC TODO's (and a few TODONT's)
 *
 * - widl is like MIDL for wine.  For wine to be a useful RPC platform, quite
 *   a bit of work needs to be done here.  widl currently doesn't generate stubs
 *   for RPC invocation -- it will need to; this is tricky because the MIDL compiler
 *   does some really wierd stuff.  Then again, we don't neccesarily have to
 *   make widl work like MIDL, so it could be worse.
 *
 * - RPC has a quite featureful error handling mechanism; none of it is implemented
 *   right now.
 *
 * - The server portions of the patch don't seem to be getting accepted by
 *   Alexandre.  My guess is that once I have a working test he'll conceed to
 *   let this in.  To implement this properly is tricky and possibly beyond my
 *   abilities; Ove seems to think the right way to do this is to use LPC
 *   (Local Procedure Call, another undocumented monster).  LPC has no implementation
 *   in wine and is not going to be trivial to create.
 *
 * - There are several different memory allocation schemes for MSRPC.
 *   I don't even understand what they all are yet, much less have them
 *   properly implemented.  Surely we are supposed to be doing something with
 *   the user-provided allocation/deallocation functions, but so far,
 *   I don't think we are doing this...
 *
 * - MSRPC provides impersonation capabilities which currently are not possible
 *   to implement in wine.  At the very least we should implement the authorization
 *   API's & gracefully ignore the irrelevant stuff (to a small extent we already do).
 *
 * - Some transports are not yet implemented.  The existing transport implementations
 *   are incomplete; the various transports probably ought to be supported in a more
 *   object-oriented manner, like in DCE's RPC implementation, instead of cluttering
 *   up the code with conditionals like we do now.
 * 
 * - Data marshalling: So far, only the very beginnings of an implementation
 *   exist in wine.  NDR protocol is mostly documented, but the MS API's to
 *   convert data-types in memory into NDR are not.
 *
 * - ORPC is RPC for OLE; once we have a working RPC framework, we can
 *   use it to implement out-of-process OLE client/server communications.
 *   ATM there is a 100% disconnect between the marshalling in the OLE DLL's
 *   and the marshalling going on here.  This is a good thing, since marshalling
 *   doesn't work yet.  But once it does, obviously there will be the opportunity
 *   to implement out-of-process OLE using wine's rpcrt4 or some derivative.
 * 
 * - In-source API Documentation, at least for those functions which we have
 *   implemented, but preferably for everything we can document, would be nice.
 *   I started out being quite good about this, and ended up getting lazy.
 *   Some stuff is undocumented by Microsoft and we are guessing how to implement
 *   (in these cases we should document the behavior we implemented, or, if there
 *   is no implementation, at least hazard some kind of guess, and put a few
 *   question marks after it ;) ).
 *
 * - Stubs.  Lots of stuff is defined in Microsoft's headers, including undocumented
 *   stuff.  So let's make a stub-farm and populate it with as many rpcrt4 api's as
 *   we can stand, so people don't get unimplemented function exceptions.
 *
 * - Name services: this part hasn't even been started.
 *
 * - Concurrency: right now I don't think (?) we handle more than one request at a time;
 *   we are supposed to be able to do this, and to queue requests which exceed the
 *   concurrency limit.
 *
 * - Protocol Towers: Totally unimplemented.  I don't even know what these are.
 *
 * - Context Handle Rundown: whatever that is.
 *
 * - Nested RPC's: Totally unimplemented.
 *
 * - Statistics: we are supposed to be keeping various counters.  we aren't.
 *
 * - Connectionless RPC: unimplemented.
 * 
 * - ...?  More stuff I haven't thought of.  If you think of more RPC todo's drop me
 *   an e-mail <gmturner007@ameritech.net> or send a patch to wine-patches.
Huw D M Davies's avatar
Huw D M Davies committed
94 95 96 97
 */

#include "config.h"

98 99 100 101
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
102 103 104 105 106 107
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
108

Huw D M Davies's avatar
Huw D M Davies committed
109 110 111
#include "windef.h"
#include "winerror.h"
#include "winbase.h"
112
#include "wine/unicode.h"
Huw D M Davies's avatar
Huw D M Davies committed
113 114
#include "rpc.h"

115 116 117 118
#include "ole2.h"
#include "rpcndr.h"
#include "rpcproxy.h"

Huw D M Davies's avatar
Huw D M Davies committed
119 120 121
#ifdef HAVE_SYS_FILE_H
# include <sys/file.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
122 123 124
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
Huw D M Davies's avatar
Huw D M Davies committed
125 126 127 128 129 130 131 132 133 134 135 136 137
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_SYS_SOCKIO_H
# include <sys/sockio.h>
#endif
#ifdef HAVE_NET_IF_H
# include <net/if.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif

138 139
#include "rpc_binding.h"

140
#include "wine/debug.h"
Huw D M Davies's avatar
Huw D M Davies committed
141

142
WINE_DEFAULT_DEBUG_CHANNEL(ole);
Huw D M Davies's avatar
Huw D M Davies committed
143

144 145
static UUID uuid_nil;

Huw D M Davies's avatar
Huw D M Davies committed
146 147 148 149
/***********************************************************************
 * RPCRT4_LibMain
 *
 * PARAMS
Andreas Mohr's avatar
Andreas Mohr committed
150
 *     hinstDLL    [I] handle to the DLL's instance
Huw D M Davies's avatar
Huw D M Davies committed
151
 *     fdwReason   [I]
Andreas Mohr's avatar
Andreas Mohr committed
152
 *     lpvReserved [I] reserved, must be NULL
Huw D M Davies's avatar
Huw D M Davies committed
153 154 155 156 157 158 159 160 161 162 163 164 165 166
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL WINAPI
RPCRT4_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason) {
    case DLL_PROCESS_ATTACH:
	break;

    case DLL_PROCESS_DETACH:
167
	break;
Huw D M Davies's avatar
Huw D M Davies committed
168 169 170 171 172
    }

    return TRUE;
}

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
/*************************************************************************
 *           RpcStringFreeA   [RPCRT4.@]
 *
 * Frees a character string allocated by the RPC run-time library.
 *
 * RETURNS
 *
 *  S_OK if successful.
 */
RPC_STATUS WINAPI RpcStringFreeA(LPSTR* String)
{
  HeapFree( GetProcessHeap(), 0, *String);

  return RPC_S_OK;
}

/*************************************************************************
 *           RpcStringFreeW   [RPCRT4.@]
 *
 * Frees a character string allocated by the RPC run-time library.
 *
 * RETURNS
 *
 *  S_OK if successful.
 */
RPC_STATUS WINAPI RpcStringFreeW(LPWSTR* String)
{
  HeapFree( GetProcessHeap(), 0, *String);

  return RPC_S_OK;
}

205
/*************************************************************************
206 207 208
 * UuidCompare [RPCRT4.@]
 *
 * (an educated-guess implementation)
209 210 211 212 213
 *
 * PARAMS
 *     UUID *Uuid1        [I] Uuid to compare
 *     UUID *Uuid2        [I] Uuid to compare
 *     RPC_STATUS *Status [O] returns RPC_S_OK
214
 * 
215
 * RETURNS
216 217 218
 *     -1 if Uuid1 is less than Uuid2
 *     0  if Uuid1 and Uuid2 are equal
 *     1  if Uuid1 is greater than Uuid2
219
 */
220
int WINAPI UuidCompare(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status)
221
{
Greg Turner's avatar
Greg Turner committed
222
  TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2));
223
  *Status = RPC_S_OK;
Greg Turner's avatar
Greg Turner committed
224 225
  if (!Uuid1) Uuid1 = &uuid_nil;
  if (!Uuid2) Uuid2 = &uuid_nil;
226 227
  if (Uuid1 == Uuid2) return 0;
  return memcmp(Uuid1, Uuid2, sizeof(UUID));
Greg Turner's avatar
Greg Turner committed
228 229 230
}

/*************************************************************************
231
 * UuidEqual [RPCRT4.@]
Greg Turner's avatar
Greg Turner committed
232 233 234 235 236
 *
 * PARAMS
 *     UUID *Uuid1        [I] Uuid to compare
 *     UUID *Uuid2        [I] Uuid to compare
 *     RPC_STATUS *Status [O] returns RPC_S_OK
237
 *
Greg Turner's avatar
Greg Turner committed
238
 * RETURNS
239
 *     TRUE/FALSE
Greg Turner's avatar
Greg Turner committed
240
 */
241
int WINAPI UuidEqual(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status)
Greg Turner's avatar
Greg Turner committed
242 243
{
  TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2));
244
  return !UuidCompare(Uuid1, Uuid2, Status);
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
}

/*************************************************************************
 * UuidIsNil [RPCRT4.@]
 *
 * PARAMS
 *     UUID *Uuid         [I] Uuid to compare
 *     RPC_STATUS *Status [O] retuns RPC_S_OK
 *
 * RETURNS
 *     TRUE/FALSE
 */
int WINAPI UuidIsNil(UUID *uuid, RPC_STATUS *Status)
{
  TRACE("(%s)\n", debugstr_guid(uuid));
  *Status = RPC_S_OK;
  if (!uuid) return TRUE;
  return !memcmp(uuid, &uuid_nil, sizeof(UUID));
}

 /*************************************************************************
 * UuidCreateNil [RPCRT4.@]
 *
 * PARAMS
 *     UUID *Uuid [O] returns a nil UUID
 *
 * RETURNS
 *     RPC_S_OK
 */
RPC_STATUS WINAPI UuidCreateNil(UUID *Uuid)
{
  *Uuid = uuid_nil;
  return RPC_S_OK;
}

Huw D M Davies's avatar
Huw D M Davies committed
280
/*************************************************************************
281
 *           UuidCreate   [RPCRT4.@]
Huw D M Davies's avatar
Huw D M Davies committed
282 283 284 285 286 287 288 289 290 291
 *
 * Creates a 128bit UUID.
 * Implemented according the DCE specification for UUID generation.
 * Code is based upon uuid library in e2fsprogs by Theodore Ts'o.
 * Copyright (C) 1996, 1997 Theodore Ts'o.
 *
 * RETURNS
 *
 *  S_OK if successful.
 */
292
RPC_STATUS WINAPI UuidCreate(UUID *Uuid)
Huw D M Davies's avatar
Huw D M Davies committed
293 294
{
   static char has_init = 0;
295
   static unsigned char a[6];
Huw D M Davies's avatar
Huw D M Davies committed
296 297
   static int                      adjustment = 0;
   static struct timeval           last = {0, 0};
298
   static WORD                     clock_seq;
Huw D M Davies's avatar
Huw D M Davies committed
299 300
   struct timeval                  tv;
   unsigned long long              clock_reg;
301 302
   DWORD clock_high, clock_low;
   WORD temp_clock_seq, temp_clock_mid, temp_clock_hi_and_version;
Huw D M Davies's avatar
Huw D M Davies committed
303 304 305 306 307 308 309
#ifdef HAVE_NET_IF_H
   int             sd;
   struct ifreq    ifr, *ifrp;
   struct ifconf   ifc;
   char buf[1024];
   int             n, i;
#endif
310

Huw D M Davies's avatar
Huw D M Davies committed
311 312 313 314 315 316 317 318
   /* Have we already tried to get the MAC address? */
   if (!has_init) {
#ifdef HAVE_NET_IF_H
      /* BSD 4.4 defines the size of an ifreq to be
       * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
       * However, under earlier systems, sa_len isn't present, so
       *  the size is just sizeof(struct ifreq)
       */
319
#ifdef HAVE_SOCKADDR_SA_LEN
Huw D M Davies's avatar
Huw D M Davies committed
320 321 322 323 324 325 326
#  ifndef max
#   define max(a,b) ((a) > (b) ? (a) : (b))
#  endif
#  define ifreq_size(i) max(sizeof(struct ifreq),\
sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
# else
#  define ifreq_size(i) sizeof(struct ifreq)
327 328
# endif /* defined(HAVE_SOCKADDR_SA_LEN) */

Huw D M Davies's avatar
Huw D M Davies committed
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
      sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
      if (sd < 0) {
	 /* if we can't open a socket, just use random numbers */
	 /* set the multicast bit to prevent conflicts with real cards */
	 a[0] = (rand() & 0xff) | 0x80;
	 a[1] = rand() & 0xff;
	 a[2] = rand() & 0xff;
	 a[3] = rand() & 0xff;
	 a[4] = rand() & 0xff;
	 a[5] = rand() & 0xff;
      } else {
	 memset(buf, 0, sizeof(buf));
	 ifc.ifc_len = sizeof(buf);
	 ifc.ifc_buf = buf;
	 /* get the ifconf interface */
	 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
	    close(sd);
	    /* no ifconf, so just use random numbers */
	    /* set the multicast bit to prevent conflicts with real cards */
	    a[0] = (rand() & 0xff) | 0x80;
	    a[1] = rand() & 0xff;
	    a[2] = rand() & 0xff;
	    a[3] = rand() & 0xff;
	    a[4] = rand() & 0xff;
	    a[5] = rand() & 0xff;
	 } else {
	    /* loop through the interfaces, looking for a valid one */
	    n = ifc.ifc_len;
357
	    for (i = 0; i < n; i+= ifreq_size(ifr) ) {
Huw D M Davies's avatar
Huw D M Davies committed
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
	       ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
	       strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
	       /* try to get the address for this interface */
# ifdef SIOCGIFHWADDR
	       if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
		   continue;
	       memcpy(a, (unsigned char *)&ifr.ifr_hwaddr.sa_data, 6);
# else
#  ifdef SIOCGENADDR
	       if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
		   continue;
	       memcpy(a, (unsigned char *) ifr.ifr_enaddr, 6);
#  else
	       /* XXX we don't have a way of getting the hardware address */
	       close(sd);
	       a[0] = 0;
	       break;
#  endif /* SIOCGENADDR */
# endif /* SIOCGIFHWADDR */
	       /* make sure it's not blank */
	       if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
		   continue;
380

Huw D M Davies's avatar
Huw D M Davies committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
	       goto valid_address;
	    }
	    /* if we didn't find a valid address, make a random one */
	    /* once again, set multicast bit to avoid conflicts */
	    a[0] = (rand() & 0xff) | 0x80;
	    a[1] = rand() & 0xff;
	    a[2] = rand() & 0xff;
	    a[3] = rand() & 0xff;
	    a[4] = rand() & 0xff;
	    a[5] = rand() & 0xff;

	    valid_address:
	    close(sd);
	 }
      }
#else
      /* no networking info, so generate a random address */
      a[0] = (rand() & 0xff) | 0x80;
      a[1] = rand() & 0xff;
      a[2] = rand() & 0xff;
      a[3] = rand() & 0xff;
      a[4] = rand() & 0xff;
      a[5] = rand() & 0xff;
#endif /* HAVE_NET_IF_H */
      has_init = 1;
   }
407

Huw D M Davies's avatar
Huw D M Davies committed
408
   /* generate time element of GUID */
409

Huw D M Davies's avatar
Huw D M Davies committed
410 411
   /* Assume that the gettimeofday() has microsecond granularity */
#define MAX_ADJUSTMENT 10
412

Huw D M Davies's avatar
Huw D M Davies committed
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
   try_again:
   gettimeofday(&tv, 0);
   if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
      clock_seq = ((rand() & 0xff) << 8) + (rand() & 0xff);
      clock_seq &= 0x1FFF;
      last = tv;
      last.tv_sec--;
   }
   if ((tv.tv_sec < last.tv_sec) ||
       ((tv.tv_sec == last.tv_sec) &&
	(tv.tv_usec < last.tv_usec))) {
      clock_seq = (clock_seq+1) & 0x1FFF;
      adjustment = 0;
   } else if ((tv.tv_sec == last.tv_sec) &&
	      (tv.tv_usec == last.tv_usec)) {
      if (adjustment >= MAX_ADJUSTMENT)
	  goto try_again;
      adjustment++;
   } else
       adjustment = 0;
433

Huw D M Davies's avatar
Huw D M Davies committed
434 435 436
   clock_reg = tv.tv_usec*10 + adjustment;
   clock_reg += ((unsigned long long) tv.tv_sec)*10000000;
   clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
437

Huw D M Davies's avatar
Huw D M Davies committed
438 439 440
   clock_high = clock_reg >> 32;
   clock_low = clock_reg;
   temp_clock_seq = clock_seq | 0x8000;
441
   temp_clock_mid = (WORD)clock_high;
Huw D M Davies's avatar
Huw D M Davies committed
442
   temp_clock_hi_and_version = (clock_high >> 16) | 0x1000;
443

Huw D M Davies's avatar
Huw D M Davies committed
444
   /* pack the information into the GUID structure */
445

Huw D M Davies's avatar
Huw D M Davies committed
446 447 448 449 450 451 452
   ((unsigned char*)&Uuid->Data1)[3] = (unsigned char)clock_low;
   clock_low >>= 8;
   ((unsigned char*)&Uuid->Data1)[2] = (unsigned char)clock_low;
   clock_low >>= 8;
   ((unsigned char*)&Uuid->Data1)[1] = (unsigned char)clock_low;
   clock_low >>= 8;
   ((unsigned char*)&Uuid->Data1)[0] = (unsigned char)clock_low;
453

Huw D M Davies's avatar
Huw D M Davies committed
454 455 456
   ((unsigned char*)&Uuid->Data2)[1] = (unsigned char)temp_clock_mid;
   temp_clock_mid >>= 8;
   ((unsigned char*)&Uuid->Data2)[0] = (unsigned char)temp_clock_mid;
457

Huw D M Davies's avatar
Huw D M Davies committed
458 459 460
   ((unsigned char*)&Uuid->Data3)[1] = (unsigned char)temp_clock_hi_and_version;
   temp_clock_hi_and_version >>= 8;
   ((unsigned char*)&Uuid->Data3)[0] = (unsigned char)temp_clock_hi_and_version;
461

Huw D M Davies's avatar
Huw D M Davies committed
462 463 464
   ((unsigned char*)Uuid->Data4)[1] = (unsigned char)temp_clock_seq;
   temp_clock_seq >>= 8;
   ((unsigned char*)Uuid->Data4)[0] = (unsigned char)temp_clock_seq;
465

Huw D M Davies's avatar
Huw D M Davies committed
466 467 468 469 470 471
   ((unsigned char*)Uuid->Data4)[2] = a[0];
   ((unsigned char*)Uuid->Data4)[3] = a[1];
   ((unsigned char*)Uuid->Data4)[4] = a[2];
   ((unsigned char*)Uuid->Data4)[5] = a[3];
   ((unsigned char*)Uuid->Data4)[6] = a[4];
   ((unsigned char*)Uuid->Data4)[7] = a[5];
472

473
   TRACE("%s\n", debugstr_guid(Uuid));
474

475
   return RPC_S_OK;
Huw D M Davies's avatar
Huw D M Davies committed
476
}
477

478 479 480 481 482 483 484 485 486 487 488 489 490

/*************************************************************************
 *           UuidCreateSequential   [RPCRT4.@]
 *
 * Creates a 128bit UUID by calling UuidCreate.
 * New API in Win 2000
 */
RPC_STATUS WINAPI UuidCreateSequential(UUID *Uuid)
{
   return UuidCreate (Uuid);
}


491
/*************************************************************************
492
 *           UuidHash   [RPCRT4.@]
493
 *
494
 * Generates a hash value for a given UUID
495
 *
496
 * Code based on FreeDCE implementation
497 498
 *
 */
499
unsigned short WINAPI UuidHash(UUID *uuid, RPC_STATUS *Status)
500
{
501 502 503
  BYTE *data = (BYTE*)uuid;
  short c0 = 0, c1 = 0, x, y;
  int i;
504

505
  TRACE("(%s)\n", debugstr_guid(uuid));
506

507 508 509 510 511 512 513 514 515 516
  for (i=0; i<sizeof(UUID); i++) {
    c0 += data[i];
    c1 += c0;
  }

  x = -c1 % 255;
  if (x < 0) x += 255;

  y = (c1 - c0) % 255;
  if (y < 0) y += 255;
517 518

  *Status = RPC_S_OK;
519
  return y*256 + x;
520 521
}

522
/*************************************************************************
523
 *           UuidToStringA   [RPCRT4.@]
524 525 526 527 528 529 530 531 532 533 534
 *
 * Converts a UUID to a string.
 *
 * UUID format is 8 hex digits, followed by a hyphen then three groups of
 * 4 hex digits each followed by a hyphen and then 12 hex digits
 *
 * RETURNS
 *
 *  S_OK if successful.
 *  S_OUT_OF_MEMORY if unsucessful.
 */
Ove Kaaven's avatar
Ove Kaaven committed
535
RPC_STATUS WINAPI UuidToStringA(UUID *Uuid, LPSTR* StringUuid)
536 537 538 539
{
  *StringUuid = HeapAlloc( GetProcessHeap(), 0, sizeof(char) * 37);

  if(!(*StringUuid))
540
    return RPC_S_OUT_OF_MEMORY;
541

542
  sprintf(*StringUuid, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
543 544 545 546 547
                 Uuid->Data1, Uuid->Data2, Uuid->Data3,
                 Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2],
                 Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5],
                 Uuid->Data4[6], Uuid->Data4[7] );

548
  return RPC_S_OK;
549
}
550

551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
/*************************************************************************
 *           UuidToStringW   [RPCRT4.@]
 *
 * Converts a UUID to a string.
 *
 *  S_OK if successful.
 *  S_OUT_OF_MEMORY if unsucessful.
 */
RPC_STATUS WINAPI UuidToStringW(UUID *Uuid, LPWSTR* StringUuid)
{
  char buf[37];

  sprintf(buf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
               Uuid->Data1, Uuid->Data2, Uuid->Data3,
               Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2],
               Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5],
               Uuid->Data4[6], Uuid->Data4[7] );

  *StringUuid = RPCRT4_strdupAtoW(buf);

  if(!(*StringUuid))
    return RPC_S_OUT_OF_MEMORY;

  return RPC_S_OK;
}
576 577 578 579 580 581 582 583 584 585 586 587

static const BYTE hex2bin[] =
{
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x00 */
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x10 */
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x20 */
    0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,        /* 0x30 */
    0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,  /* 0x40 */
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x50 */
    0,10,11,12,13,14,15                     /* 0x60 */
};

588 589 590
/***********************************************************************
 *		UuidFromStringA (RPCRT4.@)
 */
Ove Kaaven's avatar
Ove Kaaven committed
591
RPC_STATUS WINAPI UuidFromStringA(LPSTR str, UUID *uuid)
592
{
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
    BYTE *s = (BYTE *)str;
    int i;

    if (!s) return UuidCreateNil( uuid );

    if (strlen(s) != 36) return RPC_S_INVALID_STRING_UUID;

    if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-'))
        return RPC_S_INVALID_STRING_UUID;

    for (i=0; i<36; i++)
    {
        if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue;
        if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID;
    }

    /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */

    uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 |
                   hex2bin[s[4]] << 12 | hex2bin[s[5]]  << 8 | hex2bin[s[6]]  << 4 | hex2bin[s[7]]);
    uuid->Data2 =  hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]];
    uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]];

    /* these are just sequential bytes */
    uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]];
    uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]];
    uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]];
    uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]];
    uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]];
    uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]];
    uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]];
    uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]];
    return RPC_S_OK;
626 627
}

628

629 630 631
/***********************************************************************
 *		UuidFromStringW (RPCRT4.@)
 */
632
RPC_STATUS WINAPI UuidFromStringW(LPWSTR s, UUID *uuid)
633
{
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
    int i;

    if (!s) return UuidCreateNil( uuid );

    if (strlenW(s) != 36) return RPC_S_INVALID_STRING_UUID;

    if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-'))
        return RPC_S_INVALID_STRING_UUID;

    for (i=0; i<36; i++)
    {
        if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue;
        if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID;
    }

    /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */

    uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 |
                   hex2bin[s[4]] << 12 | hex2bin[s[5]]  << 8 | hex2bin[s[6]]  << 4 | hex2bin[s[7]]);
    uuid->Data2 =  hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]];
    uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]];

    /* these are just sequential bytes */
    uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]];
    uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]];
    uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]];
    uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]];
    uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]];
    uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]];
    uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]];
    uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]];
    return RPC_S_OK;
666 667
}

668 669 670 671 672 673 674 675 676
/***********************************************************************
 *              DllRegisterServer (RPCRT4.@)
 */

HRESULT WINAPI RPCRT4_DllRegisterServer( void )
{
        FIXME( "(): stub\n" );
        return S_OK;
}