1 /* Part of SWI-Prolog
2
3 Author: Jan Wielemaker
4 E-mail: J.Wielemaker@vu.nl
5 WWW: http://www.swi-prolog.org
6 Copyright (c) 2012-2018, VU University Amsterdam
7 CWI, Amsterdam
8 All rights reserved.
9
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions
12 are met:
13
14 1. Redistributions of source code must retain the above copyright
15 notice, this list of conditions and the following disclaimer.
16
17 2. Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in
19 the documentation and/or other materials provided with the
20 distribution.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <config.h>
37 #ifdef HAVE_OSSP_UUID_H
38 #include <ossp/uuid.h>
39 #else
40 #include <uuid.h>
41 #endif
42
43 #include <SWI-Prolog.h>
44 #include <SWI-Stream.h>
45 #include <assert.h>
46 #if defined(HAVE_OSSP_UUID_H)
47 #include <ossp/uuid.h>
48 #else
49 #include <uuid.h>
50 #endif
51
52 /* Seems to be defined in some MinGW installations. The
53 * ossp-uuid header defines the types using typedef, so
54 * we can safely kill these macros
55 */
56 #undef UUID
57 #undef uuid_t
58
59 static atom_t ATOM_version;
60 static atom_t ATOM_format;
61 static atom_t ATOM_atom;
62 static atom_t ATOM_integer;
63 static atom_t ATOM_url;
64 static atom_t ATOM_dns;
65 static atom_t ATOM_oid;
66 static atom_t ATOM_x500;
67
68 static foreign_t
pl_uuid(term_t UUID,term_t options)69 pl_uuid(term_t UUID, term_t options)
70 { unsigned int mode = UUID_MAKE_V1;
71 atom_t format = ATOM_atom;
72 uuid_t *uuid;
73 char *ns = NULL;
74 char *str = NULL;
75 int rc;
76 uuid_rc_t urc;
77
78 if ( !PL_get_nil(options) )
79 { term_t tail = PL_copy_term_ref(options);
80 term_t head = PL_new_term_ref();
81 term_t arg = PL_new_term_ref();
82
83 while( PL_get_list(tail, head, tail) )
84 { atom_t name;
85 size_t arity;
86
87 if ( !PL_get_name_arity(head, &name, &arity) || arity != 1 )
88 return PL_type_error("option", head);
89 _PL_get_arg(1, head, arg);
90
91 if ( name == ATOM_version )
92 { int v;
93
94 if ( !PL_get_integer_ex(arg, &v) )
95 return FALSE;
96 switch(v)
97 { case 1: mode = UUID_MAKE_V1; break;
98 case 2: mode = UUID_MAKE_MC; break;
99 case 3: mode = UUID_MAKE_V3; break;
100 case 4: mode = UUID_MAKE_V4; break;
101 case 5: mode = UUID_MAKE_V5; break;
102 default: return PL_domain_error("uuid_version", arg);
103 }
104 } else if ( name == ATOM_format )
105 { if ( !PL_get_atom_ex(arg, &format) )
106 return FALSE;
107 if ( format != ATOM_atom && format != ATOM_integer )
108 return PL_domain_error("uuid_format", arg);
109 } else
110 { char *newns = NULL;
111
112 if ( name == ATOM_dns )
113 { newns = "ns:DNS";
114 } else if ( name == ATOM_url )
115 { newns = "ns:URL";
116 } else if ( name == ATOM_oid )
117 { newns = "ns:OID";
118 } else if ( name == ATOM_x500 )
119 { newns = "ns:X500";
120 }
121
122 if ( newns )
123 { ns = newns;
124 if ( !PL_get_chars(arg, &str, CVT_ATOM|CVT_EXCEPTION) )
125 return FALSE;
126 if ( mode == UUID_MAKE_V1 )
127 mode = UUID_MAKE_V3;
128 }
129 }
130 }
131 if ( !PL_get_nil_ex(tail) )
132 return FALSE;
133 }
134
135 switch(mode)
136 { case UUID_MAKE_V1:
137 case UUID_MAKE_MC:
138 case UUID_MAKE_V4:
139 uuid_create(&uuid);
140 if ( (urc=uuid_make(uuid, mode)) != UUID_RC_OK )
141 return PL_warning("UUID: make: %s\n", uuid_error(urc));
142 break;
143 case UUID_MAKE_V3:
144 case UUID_MAKE_V5:
145 { uuid_t *uuid_ns;
146
147 if ( !ns )
148 return PL_existence_error("uuid_context", options);
149
150 uuid_create(&uuid);
151 uuid_create(&uuid_ns);
152 uuid_load(uuid_ns, ns);
153 if ( (urc=uuid_make(uuid, mode, uuid_ns, str)) != UUID_RC_OK )
154 return PL_warning("UUID: make: %s\n", uuid_error(urc));
155 uuid_destroy(uuid_ns);
156 break;
157 }
158 default:
159 assert(0);
160 return FALSE;
161 }
162
163 if ( format == ATOM_atom )
164 { char buf[UUID_LEN_STR+1];
165 void *ptr = buf;
166 size_t datalen = sizeof(buf);
167
168 if ( (urc=uuid_export(uuid, UUID_FMT_STR, &ptr, &datalen)) != UUID_RC_OK )
169 return PL_warning("UUID: export: %s\n", uuid_error(urc));
170 rc = PL_unify_chars(UUID, PL_ATOM|REP_ISO_LATIN_1, (size_t)-1, buf);
171 } else if ( format == ATOM_integer )
172 { char buf[UUID_LEN_SIV+1];
173 void *ptr = buf;
174 size_t datalen = sizeof(buf);
175 term_t tmp = PL_new_term_ref();
176
177 if ( (urc=uuid_export(uuid, UUID_FMT_SIV, &ptr, &datalen)) != UUID_RC_OK )
178 return PL_warning("UUID: export: %s\n", uuid_error(urc));
179 rc = ( PL_chars_to_term(buf, tmp) &&
180 PL_unify(UUID, tmp)
181 );
182 } else
183 { assert(0);
184 return FALSE;
185 }
186
187 uuid_destroy(uuid);
188
189 return rc;
190 }
191
192
193 install_t
install_uuid(void)194 install_uuid(void)
195 { ATOM_version = PL_new_atom("version");
196 ATOM_format = PL_new_atom("format");
197 ATOM_atom = PL_new_atom("atom");
198 ATOM_integer = PL_new_atom("integer");
199 ATOM_dns = PL_new_atom("dns");
200 ATOM_url = PL_new_atom("url");
201 ATOM_oid = PL_new_atom("oid");
202 ATOM_x500 = PL_new_atom("x500");
203
204 PL_register_foreign("uuid", 2, pl_uuid, 0);
205 }
206
207