TortoiseGitMerge: Updated libsvn stuff
[TortoiseGit.git] / src / TortoiseMerge / libsvn_diff / checksum.c
blob06e3b778e4ba01583d599c9f0ad7ae54ae7b7f90
1 /*
2 * checksum.c: checksum routines
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 * ====================================================================
25 #include <ctype.h>
27 #include <apr_md5.h>
28 #include <apr_sha1.h>
30 #include "svn_checksum.h"
31 #include "svn_error.h"
32 #include "svn_ctype.h"
34 #include "sha1.h"
35 #include "md5.h"
37 #include "private/svn_subr_private.h"
39 #include "svn_private_config.h"
43 /* Returns the digest size of it's argument. */
44 #define DIGESTSIZE(k) ((k) == svn_checksum_md5 ? APR_MD5_DIGESTSIZE : \
45 (k) == svn_checksum_sha1 ? APR_SHA1_DIGESTSIZE : 0)
48 /* Check to see if KIND is something we recognize. If not, return
49 * SVN_ERR_BAD_CHECKSUM_KIND */
50 static svn_error_t *
51 validate_kind(svn_checksum_kind_t kind)
53 if (kind == svn_checksum_md5 || kind == svn_checksum_sha1)
54 return SVN_NO_ERROR;
55 else
56 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
59 /* Create a svn_checksum_t with everything but the contents of the
60 digest populated. */
61 static svn_checksum_t *
62 checksum_create_without_digest(svn_checksum_kind_t kind,
63 apr_size_t digest_size,
64 apr_pool_t *pool)
66 /* Use apr_palloc() instead of apr_pcalloc() so that the digest
67 * contents are only set once by the caller. */
68 svn_checksum_t *checksum = apr_palloc(pool, sizeof(*checksum) + digest_size);
69 checksum->digest = (unsigned char *)checksum + sizeof(*checksum);
70 checksum->kind = kind;
71 return checksum;
74 static svn_checksum_t *
75 checksum_create(svn_checksum_kind_t kind,
76 apr_size_t digest_size,
77 const unsigned char *digest,
78 apr_pool_t *pool)
80 svn_checksum_t *checksum = checksum_create_without_digest(kind, digest_size,
81 pool);
82 memcpy((unsigned char *)checksum->digest, digest, digest_size);
83 return checksum;
86 svn_checksum_t *
87 svn_checksum_create(svn_checksum_kind_t kind,
88 apr_pool_t *pool)
90 svn_checksum_t *checksum;
91 apr_size_t digest_size;
93 switch (kind)
95 case svn_checksum_md5:
96 digest_size = APR_MD5_DIGESTSIZE;
97 break;
98 case svn_checksum_sha1:
99 digest_size = APR_SHA1_DIGESTSIZE;
100 break;
101 default:
102 return NULL;
105 checksum = checksum_create_without_digest(kind, digest_size, pool);
106 memset((unsigned char *) checksum->digest, 0, digest_size);
107 return checksum;
110 svn_checksum_t *
111 svn_checksum__from_digest_md5(const unsigned char *digest,
112 apr_pool_t *result_pool)
114 return checksum_create(svn_checksum_md5, APR_MD5_DIGESTSIZE, digest,
115 result_pool);
118 svn_checksum_t *
119 svn_checksum__from_digest_sha1(const unsigned char *digest,
120 apr_pool_t *result_pool)
122 return checksum_create(svn_checksum_sha1, APR_SHA1_DIGESTSIZE, digest,
123 result_pool);
126 svn_error_t *
127 svn_checksum_clear(svn_checksum_t *checksum)
129 SVN_ERR(validate_kind(checksum->kind));
131 memset((unsigned char *) checksum->digest, 0, DIGESTSIZE(checksum->kind));
132 return SVN_NO_ERROR;
135 svn_boolean_t
136 svn_checksum_match(const svn_checksum_t *checksum1,
137 const svn_checksum_t *checksum2)
139 if (checksum1 == NULL || checksum2 == NULL)
140 return TRUE;
142 if (checksum1->kind != checksum2->kind)
143 return FALSE;
145 switch (checksum1->kind)
147 case svn_checksum_md5:
148 return svn_md5__digests_match(checksum1->digest, checksum2->digest);
149 case svn_checksum_sha1:
150 return svn_sha1__digests_match(checksum1->digest, checksum2->digest);
151 default:
152 /* We really shouldn't get here, but if we do... */
153 return FALSE;
157 const char *
158 svn_checksum_to_cstring_display(const svn_checksum_t *checksum,
159 apr_pool_t *pool)
161 switch (checksum->kind)
163 case svn_checksum_md5:
164 return svn_md5__digest_to_cstring_display(checksum->digest, pool);
165 case svn_checksum_sha1:
166 return svn_sha1__digest_to_cstring_display(checksum->digest, pool);
167 default:
168 /* We really shouldn't get here, but if we do... */
169 return NULL;
173 const char *
174 svn_checksum_to_cstring(const svn_checksum_t *checksum,
175 apr_pool_t *pool)
177 if (checksum == NULL)
178 return NULL;
180 switch (checksum->kind)
182 case svn_checksum_md5:
183 return svn_md5__digest_to_cstring(checksum->digest, pool);
184 case svn_checksum_sha1:
185 return svn_sha1__digest_to_cstring(checksum->digest, pool);
186 default:
187 /* We really shouldn't get here, but if we do... */
188 return NULL;
193 const char *
194 svn_checksum_serialize(const svn_checksum_t *checksum,
195 apr_pool_t *result_pool,
196 apr_pool_t *scratch_pool)
198 const char *ckind_str;
200 SVN_ERR_ASSERT_NO_RETURN(checksum->kind == svn_checksum_md5
201 || checksum->kind == svn_checksum_sha1);
202 ckind_str = (checksum->kind == svn_checksum_md5 ? "$md5 $" : "$sha1$");
203 return apr_pstrcat(result_pool,
204 ckind_str,
205 svn_checksum_to_cstring(checksum, scratch_pool),
206 (char *)NULL);
210 svn_error_t *
211 svn_checksum_deserialize(const svn_checksum_t **checksum,
212 const char *data,
213 apr_pool_t *result_pool,
214 apr_pool_t *scratch_pool)
216 svn_checksum_kind_t ckind;
217 svn_checksum_t *parsed_checksum;
219 /* "$md5 $..." or "$sha1$..." */
220 SVN_ERR_ASSERT(strlen(data) > 6);
222 ckind = (data[1] == 'm' ? svn_checksum_md5 : svn_checksum_sha1);
223 SVN_ERR(svn_checksum_parse_hex(&parsed_checksum, ckind,
224 data + 6, result_pool));
225 *checksum = parsed_checksum;
227 return SVN_NO_ERROR;
231 svn_error_t *
232 svn_checksum_parse_hex(svn_checksum_t **checksum,
233 svn_checksum_kind_t kind,
234 const char *hex,
235 apr_pool_t *pool)
237 int i, len;
238 char is_nonzero = '\0';
239 char *digest;
240 static const char xdigitval[256] =
242 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
243 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
244 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
245 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, /* 0-9 */
246 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A-F */
247 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
248 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* a-f */
249 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
250 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
251 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
252 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
253 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
254 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
255 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
256 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
257 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
260 if (hex == NULL)
262 *checksum = NULL;
263 return SVN_NO_ERROR;
266 SVN_ERR(validate_kind(kind));
268 *checksum = svn_checksum_create(kind, pool);
269 digest = (char *)(*checksum)->digest;
270 len = DIGESTSIZE(kind);
272 for (i = 0; i < len; i++)
274 char x1 = xdigitval[(unsigned char)hex[i * 2]];
275 char x2 = xdigitval[(unsigned char)hex[i * 2 + 1]];
276 if (x1 == (char)-1 || x2 == (char)-1)
277 return svn_error_create(SVN_ERR_BAD_CHECKSUM_PARSE, NULL, NULL);
279 digest[i] = (char)((x1 << 4) | x2);
280 is_nonzero |= (char)((x1 << 4) | x2);
283 if (!is_nonzero)
284 *checksum = NULL;
286 return SVN_NO_ERROR;
289 svn_checksum_t *
290 svn_checksum_dup(const svn_checksum_t *checksum,
291 apr_pool_t *pool)
293 /* The duplicate of a NULL checksum is a NULL... */
294 if (checksum == NULL)
295 return NULL;
297 /* Without this check on valid checksum kind a NULL svn_checksum_t
298 * pointer is returned which could cause a core dump at an
299 * indeterminate time in the future because callers are not
300 * expecting a NULL pointer. This commit forces an early abort() so
301 * it's easier to track down where the issue arose. */
302 switch (checksum->kind)
304 case svn_checksum_md5:
305 return svn_checksum__from_digest_md5(checksum->digest, pool);
306 break;
307 case svn_checksum_sha1:
308 return svn_checksum__from_digest_sha1(checksum->digest, pool);
309 break;
310 default:
311 SVN_ERR_MALFUNCTION_NO_RETURN();
312 break;
316 svn_error_t *
317 svn_checksum(svn_checksum_t **checksum,
318 svn_checksum_kind_t kind,
319 const void *data,
320 apr_size_t len,
321 apr_pool_t *pool)
323 apr_sha1_ctx_t sha1_ctx;
325 SVN_ERR(validate_kind(kind));
326 *checksum = svn_checksum_create(kind, pool);
328 switch (kind)
330 case svn_checksum_md5:
331 apr_md5((unsigned char *)(*checksum)->digest, data, len);
332 break;
334 case svn_checksum_sha1:
335 apr_sha1_init(&sha1_ctx);
336 apr_sha1_update(&sha1_ctx, data, (unsigned int)len);
337 apr_sha1_final((unsigned char *)(*checksum)->digest, &sha1_ctx);
338 break;
340 default:
341 /* We really shouldn't get here, but if we do... */
342 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
345 return SVN_NO_ERROR;
349 svn_checksum_t *
350 svn_checksum_empty_checksum(svn_checksum_kind_t kind,
351 apr_pool_t *pool)
353 switch (kind)
355 case svn_checksum_md5:
356 return svn_checksum__from_digest_md5(svn_md5__empty_string_digest(),
357 pool);
359 case svn_checksum_sha1:
360 return svn_checksum__from_digest_sha1(svn_sha1__empty_string_digest(),
361 pool);
363 default:
364 /* We really shouldn't get here, but if we do... */
365 SVN_ERR_MALFUNCTION_NO_RETURN();
369 struct svn_checksum_ctx_t
371 void *apr_ctx;
372 svn_checksum_kind_t kind;
375 svn_checksum_ctx_t *
376 svn_checksum_ctx_create(svn_checksum_kind_t kind,
377 apr_pool_t *pool)
379 svn_checksum_ctx_t *ctx = apr_palloc(pool, sizeof(*ctx));
381 ctx->kind = kind;
382 switch (kind)
384 case svn_checksum_md5:
385 ctx->apr_ctx = apr_palloc(pool, sizeof(apr_md5_ctx_t));
386 apr_md5_init(ctx->apr_ctx);
387 break;
389 case svn_checksum_sha1:
390 ctx->apr_ctx = apr_palloc(pool, sizeof(apr_sha1_ctx_t));
391 apr_sha1_init(ctx->apr_ctx);
392 break;
394 default:
395 SVN_ERR_MALFUNCTION_NO_RETURN();
398 return ctx;
401 svn_error_t *
402 svn_checksum_update(svn_checksum_ctx_t *ctx,
403 const void *data,
404 apr_size_t len)
406 switch (ctx->kind)
408 case svn_checksum_md5:
409 apr_md5_update(ctx->apr_ctx, data, len);
410 break;
412 case svn_checksum_sha1:
413 apr_sha1_update(ctx->apr_ctx, data, (unsigned int)len);
414 break;
416 default:
417 /* We really shouldn't get here, but if we do... */
418 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
421 return SVN_NO_ERROR;
424 svn_error_t *
425 svn_checksum_final(svn_checksum_t **checksum,
426 const svn_checksum_ctx_t *ctx,
427 apr_pool_t *pool)
429 *checksum = svn_checksum_create(ctx->kind, pool);
431 switch (ctx->kind)
433 case svn_checksum_md5:
434 apr_md5_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx);
435 break;
437 case svn_checksum_sha1:
438 apr_sha1_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx);
439 break;
441 default:
442 /* We really shouldn't get here, but if we do... */
443 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
446 return SVN_NO_ERROR;
449 apr_size_t
450 svn_checksum_size(const svn_checksum_t *checksum)
452 return DIGESTSIZE(checksum->kind);
455 svn_error_t *
456 svn_checksum_mismatch_err(const svn_checksum_t *expected,
457 const svn_checksum_t *actual,
458 apr_pool_t *scratch_pool,
459 const char *fmt,
460 ...)
462 va_list ap;
463 const char *desc;
465 va_start(ap, fmt);
466 desc = apr_pvsprintf(scratch_pool, fmt, ap);
467 va_end(ap);
469 return svn_error_createf(SVN_ERR_CHECKSUM_MISMATCH, NULL,
470 _("%s:\n"
471 " expected: %s\n"
472 " actual: %s\n"),
473 desc,
474 svn_checksum_to_cstring_display(expected, scratch_pool),
475 svn_checksum_to_cstring_display(actual, scratch_pool));
478 svn_boolean_t
479 svn_checksum_is_empty_checksum(svn_checksum_t *checksum)
481 /* By definition, the NULL checksum matches all others, including the
482 empty one. */
483 if (!checksum)
484 return TRUE;
486 switch (checksum->kind)
488 case svn_checksum_md5:
489 return svn_md5__digests_match(checksum->digest,
490 svn_md5__empty_string_digest());
492 case svn_checksum_sha1:
493 return svn_sha1__digests_match(checksum->digest,
494 svn_sha1__empty_string_digest());
496 default:
497 /* We really shouldn't get here, but if we do... */
498 SVN_ERR_MALFUNCTION_NO_RETURN();