1 /*
2 * ggit-oid.c
3 * This file is part of libgit2-glib
4 *
5 * Copyright (C) 2011 - Ignacio Casal Quinteiro
6 *
7 * libgit2-glib is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * libgit2-glib is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with libgit2-glib. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <git2.h>
22
23 #include "ggit-oid.h"
24
25 struct _GgitOId
26 {
27 git_oid oid;
28 };
29
G_DEFINE_BOXED_TYPE(GgitOId,ggit_oid,ggit_oid_copy,ggit_oid_free)30 G_DEFINE_BOXED_TYPE (GgitOId, ggit_oid, ggit_oid_copy, ggit_oid_free)
31
32 GgitOId *
33 _ggit_oid_wrap (const git_oid *oid)
34 {
35 GgitOId *glib_oid;
36
37 glib_oid = g_slice_new (GgitOId);
38 git_oid_cpy (&glib_oid->oid, oid);
39
40 return glib_oid;
41 }
42
43 const git_oid *
_ggit_oid_get_oid(GgitOId * oid)44 _ggit_oid_get_oid (GgitOId *oid)
45 {
46 return (const git_oid *)&oid->oid;
47 }
48
49 /**
50 * ggit_oid_copy:
51 * @oid: a #GgitOId.
52 *
53 * Copies @oid into a newly allocated #GgitOId.
54 *
55 * Returns: (transfer full) (nullable): a newly allocated #GgitOId.
56 */
57 GgitOId *
ggit_oid_copy(GgitOId * oid)58 ggit_oid_copy (GgitOId *oid)
59 {
60 g_return_val_if_fail (oid != NULL, NULL);
61
62 return _ggit_oid_wrap (&oid->oid);
63 }
64
65 /**
66 * ggit_oid_free:
67 * @oid: a #GgitOId.
68 *
69 * Frees @oid.
70 */
71 void
ggit_oid_free(GgitOId * oid)72 ggit_oid_free (GgitOId *oid)
73 {
74 g_return_if_fail (oid != NULL);
75
76 g_slice_free (GgitOId, oid);
77 }
78
79 /**
80 * ggit_oid_new_from_string:
81 * @str: input hex string; must be pointing at the start of
82 * the hex sequence and have at least the number of bytes
83 * needed for an oid encoded in hex (40 bytes).
84 *
85 * Parses a hex formatted object id into a #GgitOId.
86 *
87 * Returns: (transfer full) (nullable): a newly allocated #GgitOId or %NULL on error.
88 */
89 GgitOId *
ggit_oid_new_from_string(const gchar * str)90 ggit_oid_new_from_string (const gchar *str)
91 {
92 GgitOId *glib_oid = NULL;
93 git_oid oid;
94
95 g_return_val_if_fail (str != NULL, NULL);
96
97 if (git_oid_fromstr (&oid, str) == GIT_OK)
98 {
99 glib_oid = _ggit_oid_wrap (&oid);
100 }
101
102 return glib_oid;
103 }
104
105 /**
106 * ggit_oid_new_from_raw:
107 * @raw: (array zero-terminated=1) (element-type guchar): the raw input bytes to be copied.
108 *
109 * Creates a new #GgitOId from a raw oid.
110 *
111 * Returns: (transfer full) (nullable): a newly allocated #GgitOId or %NULL on error.
112 */
113 GgitOId *
ggit_oid_new_from_raw(const guchar * raw)114 ggit_oid_new_from_raw (const guchar *raw)
115 {
116 git_oid oid;
117
118 g_return_val_if_fail (raw != NULL, NULL);
119
120 git_oid_fromraw (&oid, raw);
121
122 return _ggit_oid_wrap (&oid);
123 }
124
125 /**
126 * ggit_oid_compare:
127 * @a: first #GgitOId.
128 * @b: second #GgitOId.
129 *
130 * Compare two #GgitOId structures.
131 *
132 * Returns: <0, 0, >0 if a < b, a == b, a > b.
133 */
134 gint
ggit_oid_compare(GgitOId * a,GgitOId * b)135 ggit_oid_compare (GgitOId *a,
136 GgitOId *b)
137 {
138 g_return_val_if_fail (a != NULL, 0);
139 g_return_val_if_fail (b != NULL, 0);
140
141 return git_oid_cmp (&a->oid, &b->oid);
142 }
143
144 /**
145 * ggit_oid_to_string:
146 * @oid: a #GgitOId.
147 *
148 * Converts @oid into a readable string.
149 *
150 * Returns: (transfer full) (nullable): a newly allocated string representing @oid or %NULL.
151 */
152 gchar *
ggit_oid_to_string(GgitOId * oid)153 ggit_oid_to_string (GgitOId *oid)
154 {
155 gchar *hex;
156
157 g_return_val_if_fail (oid != NULL, NULL);
158
159 hex = g_new (char, GIT_OID_HEXSZ + 1);
160
161 return git_oid_tostr (hex, GIT_OID_HEXSZ + 1, &oid->oid);
162 }
163
164 /**
165 * ggit_oid_hash:
166 * @oid: a #GgitOId.
167 *
168 * Computes a hash value for a git object identifier.
169 *
170 * Returns: the hash value
171 *
172 **/
173 guint
ggit_oid_hash(GgitOId const * oid)174 ggit_oid_hash (GgitOId const *oid)
175 {
176 /* This is copied from glib
177 * This function implements the widely used "djb" hash apparently posted
178 * by Daniel Bernstein to comp.lang.c some time ago. The 32 bit
179 * unsigned hash value starts at 5381 and for each byte 'c' in the
180 * string, is updated: <literal>hash = hash * 33 + c</literal>. This
181 * function uses the signed value of each byte.
182 */
183
184 guint32 h = 5381;
185 guint i;
186
187 for (i = 0; i < GIT_OID_RAWSZ; ++i)
188 {
189 h = (h << 5) + h + oid->oid.id[i];
190 }
191
192 return h;
193 }
194
195 /**
196 * ggit_oid_equal:
197 * @a: a #GgitOId.
198 * @b: a #GgitOId.
199 *
200 * Compares two #GgitOId for equality.
201 *
202 * Returns: %TRUE if @a and @b are equal, %FALSE otherwise
203 *
204 **/
205 gboolean
ggit_oid_equal(GgitOId const * a,GgitOId const * b)206 ggit_oid_equal (GgitOId const *a,
207 GgitOId const *b)
208 {
209 if ((a != NULL) != (b != NULL))
210 {
211 return FALSE;
212 }
213 else if (a == b)
214 {
215 return TRUE;
216 }
217
218 return git_oid_cmp (&a->oid, &b->oid) == 0;
219 }
220
221 /**
222 * ggit_oid_is_zero:
223 * @oid: a #GgitOId.
224 *
225 * Get whether the oid contains only zeros.
226 *
227 * Returns: %TRUE if the oid contains only zeros, %FALSE otherwise.
228 */
229 gboolean
ggit_oid_is_zero(GgitOId const * oid)230 ggit_oid_is_zero (GgitOId const *oid)
231 {
232 g_return_val_if_fail (oid != NULL, FALSE);
233
234 return git_oid_iszero (&oid->oid) == 1;
235 }
236
237 static gint
c_to_h(gchar c)238 c_to_h (gchar c)
239 {
240 if (c >= '0' && c <= '9')
241 {
242 return c - '0';
243 }
244 else if (c >= 'A' && c <= 'F')
245 {
246 return 10 + (c - 'A');
247 }
248 else if (c >= 'a' && c <= 'f')
249 {
250 return 10 + (c - 'a');
251 }
252 else
253 {
254 return -1;
255 }
256 }
257
258 /**
259 * ggit_oid_has_prefix:
260 * @oid: a #GgitOId.
261 * @prefix: a prefix.
262 *
263 * Check whether the object id has a given prefix. Note that the prefix is
264 * specified in hexadecimal ASCII.
265 *
266 * Returns: %TRUE if the id has the given prefix, %FALSE otherwise.
267 */
268 gboolean
ggit_oid_has_prefix(GgitOId * oid,const gchar * prefix)269 ggit_oid_has_prefix (GgitOId *oid,
270 const gchar *prefix)
271 {
272 gint i;
273
274 for (i = 0; i < GIT_OID_RAWSZ; ++i)
275 {
276 gint v1;
277
278 if (*prefix == '\0')
279 {
280 return TRUE;
281 }
282
283 v1 = c_to_h (*prefix++);
284
285 if (v1 == -1)
286 {
287 return FALSE;
288 }
289
290 if (*prefix != '\0')
291 {
292 gint v2;
293
294 v2 = c_to_h (*prefix++);
295
296 if (v2 == -1)
297 {
298 return FALSE;
299 }
300
301 if (oid->oid.id[i] != (v1 << 4) + v2)
302 {
303 return FALSE;
304 }
305 }
306 else if (oid->oid.id[i] >> 4 != v1)
307 {
308 return FALSE;
309 }
310 }
311
312 return *prefix == '\0';
313 }
314
315 /* ex:set ts=8 noet: */
316