1292473Simp/*-
2292473Simp * Copyright (c) 2015 M. Warner Losh
3292473Simp * All rights reserved.
4292473Simp *
5292473Simp * Redistribution and use in source and binary forms, with or without
6292473Simp * modification, are permitted provided that the following conditions
7292473Simp * are met:
8292473Simp * 1. Redistributions of source code must retain the above copyright
9292473Simp *    notice, this list of conditions and the following disclaimer.
10292473Simp * 2. Redistributions in binary form must reproduce the above copyright
11292473Simp *    notice, this list of conditions and the following disclaimer in the
12292473Simp *    documentation and/or other materials provided with the distribution.
13292473Simp *
14292473Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15292473Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16292473Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17292473Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18292473Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19292473Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20292473Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21292473Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22292473Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23292473Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24292473Simp * SUCH DAMAGE.
25292473Simp *
26292473Simp * $FreeBSD: stable/11/stand/libsa/uuid_from_string.c 329132 2018-02-11 19:51:29Z kevans $
27292473Simp */
28292473Simp
29292473Simp/*
30292473Simp * Note: some comments taken from lib/libc/uuid/uuid_from_string.c
31292473Simp * Copyright (c) 2002 Marcel Moolenaar
32292473Simp * Copyright (c) 2002 Hiten Mahesh Pandya
33292473Simp */
34292473Simp
35292473Simp
36292473Simp#include <stand.h>
37292473Simp#include <uuid.h>
38292473Simp
39292473Simpstatic int
40292473Simphex2int(int ch)
41292473Simp{
42292473Simp	if (ch >= '0' && ch <= '9')
43292473Simp		return ch - '0';
44292473Simp	if (ch >= 'a' && ch <= 'f')
45292473Simp		return 10 + ch - 'a';
46292473Simp	if (ch >= 'A' && ch <= 'F')
47292473Simp		return 10 + ch - 'A';
48292473Simp	return 16;
49292473Simp}
50292473Simp
51292473Simpstatic uint32_t
52292473Simpfromhex(const char *s, int len, int *ok)
53292473Simp{
54292473Simp	uint32_t v;
55292473Simp	int i, h;
56292473Simp
57292473Simp	if (!*ok)
58292473Simp		return 0;
59292473Simp	v = 0;
60300264Simp	for (i = 0; i < len; i++) {
61292473Simp		h = hex2int(s[i]);
62292473Simp		if (h == 16) {
63292473Simp			*ok = 0;
64292473Simp			return v;
65292473Simp		}
66292473Simp		v = (v << 4) | h;
67292473Simp	}
68292473Simp	return v;
69292473Simp}
70292473Simp
71292473Simp/*
72292473Simp * uuid_from_string() - convert a string representation of an UUID into
73292473Simp *			a binary representation.
74292473Simp * See also:
75292473Simp *	http://www.opengroup.org/onlinepubs/009629399/uuid_from_string.htm
76292473Simp *
77292473Simp * NOTE: The sequence field is in big-endian, while the time fields are in
78292473Simp *	 native byte order.
79292473Simp *
80292473Simp * 01234567-89ab-cdef-0123-456789abcdef
81292473Simp * 000000000011111111112222222222333333
82292473Simp * 012345678901234567890123456789012345
83292473Simp *         -    -    -    -
84292473Simp * hhhhhhhh-hhhh-hhhh-bbbb-bbbbbbbbbbbb
85292473Simp *
86292473Simp */
87292473Simpvoid
88292473Simpuuid_from_string(const char *s, uuid_t *u, uint32_t *status)
89292473Simp{
90292473Simp	int ok = 1;
91292473Simp	int n;
92292473Simp
93292473Simp	if (s == NULL || *s == '\0') {
94292473Simp		uuid_create_nil(u, status);
95292473Simp		return;
96292473Simp	}
97292473Simp
98292473Simp	if (status != NULL)
99292473Simp		*status = uuid_s_invalid_string_uuid;
100292473Simp	if (strlen(s) != 36)
101292473Simp		return;
102292473Simp	/* Only support new format, check for all the right dashes */
103292473Simp	if (s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
104292473Simp		return;
105292473Simp	/* native byte order */
106292473Simp	u->time_low                  = fromhex(s     , 8, &ok);
107292473Simp	u->time_mid                  = fromhex(s +  9, 4, &ok);
108292473Simp	u->time_hi_and_version       = fromhex(s + 14, 4, &ok);
109292473Simp	/* Big endian, but presented as a whole number so decode as such */
110292473Simp	u->clock_seq_hi_and_reserved = fromhex(s + 19, 2, &ok);
111292473Simp	u->clock_seq_low             = fromhex(s + 21, 2, &ok);
112292473Simp	u->node[0]                   = fromhex(s + 24, 2, &ok);
113292473Simp	u->node[1]                   = fromhex(s + 26, 2, &ok);
114292473Simp	u->node[2]                   = fromhex(s + 28, 2, &ok);
115292473Simp	u->node[3]                   = fromhex(s + 30, 2, &ok);
116292473Simp	u->node[4]                   = fromhex(s + 32, 2, &ok);
117292473Simp	u->node[5]                   = fromhex(s + 34, 2, &ok);
118292473Simp	if (!ok)
119292473Simp		return;
120292473Simp
121292473Simp	/* We have a successful scan. Check semantics... */
122292473Simp	n = u->clock_seq_hi_and_reserved;
123292473Simp	if ((n & 0x80) != 0x00 &&			/* variant 0? */
124292473Simp	    (n & 0xc0) != 0x80 &&			/* variant 1? */
125292473Simp	    (n & 0xe0) != 0xc0) {			/* variant 2? */
126292473Simp		if (status != NULL)
127292473Simp			*status = uuid_s_bad_version;
128292473Simp	} else {
129292473Simp		if (status != NULL)
130292473Simp			*status = uuid_s_ok;
131292473Simp	}
132292473Simp}
133