OSDN Git Service

Success build TortoiseMerge.
[tortoisegit/TortoiseGitJp.git] / src / TortoiseMerge / libsvn_diff / checksum.c
1 /*\r
2  * checksum.c:   checksum routines\r
3  *\r
4  * ====================================================================\r
5  * Copyright (c) 2008 CollabNet.  All rights reserved.\r
6  *\r
7  * This software is licensed as described in the file COPYING, which\r
8  * you should have received as part of this distribution.  The terms\r
9  * are also available at http://subversion.tigris.org/license-1.html.\r
10  * If newer versions of this license are posted there, you may use a\r
11  * newer version instead, at your option.\r
12  *\r
13  * This software consists of voluntary contributions made by many\r
14  * individuals.  For exact contribution history, see the revision\r
15  * history and logs, available at http://subversion.tigris.org/.\r
16  * ====================================================================\r
17  */\r
18 \r
19 \r
20 #include <ctype.h>\r
21 \r
22 #include <apr_md5.h>\r
23 #include <apr_sha1.h>\r
24 \r
25 #include "svn_checksum.h"\r
26 #include "svn_error.h"\r
27 \r
28 #include "sha1.h"\r
29 #include "md5.h"\r
30 \r
31 \f\r
32 \r
33 /* Returns the digest size of it's argument. */\r
34 #define DIGESTSIZE(k) ((k) == svn_checksum_md5 ? APR_MD5_DIGESTSIZE : \\r
35                        (k) == svn_checksum_sha1 ? APR_SHA1_DIGESTSIZE : 0)\r
36 \r
37 \r
38 /* Check to see if KIND is something we recognize.  If not, return\r
39  * SVN_ERR_BAD_CHECKSUM_KIND */\r
40 static svn_error_t *\r
41 validate_kind(svn_checksum_kind_t kind)\r
42 {\r
43   if (kind == svn_checksum_md5 || kind == svn_checksum_sha1)\r
44     return SVN_NO_ERROR;\r
45   else\r
46     return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);\r
47 }\r
48 \r
49 \r
50 svn_checksum_t *\r
51 svn_checksum_create(svn_checksum_kind_t kind,\r
52                     apr_pool_t *pool)\r
53 {\r
54   svn_checksum_t *checksum;\r
55 \r
56   switch (kind)\r
57     {\r
58       case svn_checksum_md5:\r
59       case svn_checksum_sha1:\r
60         checksum = apr_pcalloc(pool, sizeof(*checksum) + DIGESTSIZE(kind));\r
61         checksum->digest = (unsigned char *)checksum + sizeof(*checksum);\r
62         checksum->kind = kind;\r
63         return checksum;\r
64 \r
65       default:\r
66         return NULL;\r
67     }\r
68 }\r
69 \r
70 svn_checksum_t *\r
71 svn_checksum__from_digest(const unsigned char *digest,\r
72                           svn_checksum_kind_t kind,\r
73                           apr_pool_t *result_pool)\r
74 {\r
75   svn_checksum_t *checksum = svn_checksum_create(kind, result_pool);\r
76 \r
77   memcpy((unsigned char *)checksum->digest, digest, DIGESTSIZE(kind));\r
78   return checksum;\r
79 }\r
80 \r
81 svn_error_t *\r
82 svn_checksum_clear(svn_checksum_t *checksum)\r
83 {\r
84   SVN_ERR(validate_kind(checksum->kind));\r
85 \r
86   memset((unsigned char *) checksum->digest, 0, DIGESTSIZE(checksum->kind));\r
87   return SVN_NO_ERROR;\r
88 }\r
89 \r
90 svn_boolean_t\r
91 svn_checksum_match(const svn_checksum_t *checksum1,\r
92                    const svn_checksum_t *checksum2)\r
93 {\r
94   if (checksum1 == NULL || checksum2 == NULL)\r
95     return TRUE;\r
96 \r
97   if (checksum1->kind != checksum2->kind)\r
98     return FALSE;\r
99 \r
100   switch (checksum1->kind)\r
101     {\r
102       case svn_checksum_md5:\r
103         return svn_md5__digests_match(checksum1->digest, checksum2->digest);\r
104       case svn_checksum_sha1:\r
105         return svn_sha1__digests_match(checksum1->digest, checksum2->digest);\r
106       default:\r
107         /* We really shouldn't get here, but if we do... */\r
108         return FALSE;\r
109     }\r
110 }\r
111 \r
112 const char *\r
113 svn_checksum_to_cstring_display(const svn_checksum_t *checksum,\r
114                                 apr_pool_t *pool)\r
115 {\r
116   switch (checksum->kind)\r
117     {\r
118       case svn_checksum_md5:\r
119         return svn_md5__digest_to_cstring_display(checksum->digest, pool);\r
120       case svn_checksum_sha1:\r
121         return svn_sha1__digest_to_cstring_display(checksum->digest, pool);\r
122       default:\r
123         /* We really shouldn't get here, but if we do... */\r
124         return NULL;\r
125     }\r
126 }\r
127 \r
128 const char *\r
129 svn_checksum_to_cstring(const svn_checksum_t *checksum,\r
130                         apr_pool_t *pool)\r
131 {\r
132   switch (checksum->kind)\r
133     {\r
134       case svn_checksum_md5:\r
135         return svn_md5__digest_to_cstring(checksum->digest, pool);\r
136       case svn_checksum_sha1:\r
137         return svn_sha1__digest_to_cstring(checksum->digest, pool);\r
138       default:\r
139         /* We really shouldn't get here, but if we do... */\r
140         return NULL;\r
141     }\r
142 }\r
143 \r
144 svn_error_t *\r
145 svn_checksum_parse_hex(svn_checksum_t **checksum,\r
146                        svn_checksum_kind_t kind,\r
147                        const char *hex,\r
148                        apr_pool_t *pool)\r
149 {\r
150   int len;\r
151   int i;\r
152   unsigned char is_zeros = '\0';\r
153 \r
154   if (hex == NULL)\r
155     {\r
156       *checksum = NULL;\r
157       return SVN_NO_ERROR;\r
158     }\r
159 \r
160   SVN_ERR(validate_kind(kind));\r
161 \r
162   *checksum = svn_checksum_create(kind, pool);\r
163   len = DIGESTSIZE(kind);\r
164 \r
165   for (i = 0; i < len; i++)\r
166     {\r
167       if ((! isxdigit(hex[i * 2])) || (! isxdigit(hex[i * 2 + 1])))\r
168         return svn_error_create(SVN_ERR_BAD_CHECKSUM_PARSE, NULL, NULL);\r
169 \r
170       ((unsigned char *)(*checksum)->digest)[i] =\r
171         (( isalpha(hex[i*2]) ? hex[i*2] - 'a' + 10 : hex[i*2] - '0') << 4) |\r
172         ( isalpha(hex[i*2+1]) ? hex[i*2+1] - 'a' + 10 : hex[i*2+1] - '0');\r
173       is_zeros |= (*checksum)->digest[i];\r
174     }\r
175 \r
176   if (is_zeros == '\0')\r
177     *checksum = NULL;\r
178 \r
179   return SVN_NO_ERROR;\r
180 }\r
181 \r
182 svn_checksum_t *\r
183 svn_checksum_dup(const svn_checksum_t *checksum,\r
184                  apr_pool_t *pool)\r
185 {\r
186   /* The duplicate of a NULL checksum is a NULL... */\r
187   if (checksum == NULL)\r
188     return NULL;\r
189 \r
190   return svn_checksum__from_digest(checksum->digest, checksum->kind, pool);\r
191 }\r
192 \r
193 svn_error_t *\r
194 svn_checksum(svn_checksum_t **checksum,\r
195              svn_checksum_kind_t kind,\r
196              const void *data,\r
197              apr_size_t len,\r
198              apr_pool_t *pool)\r
199 {\r
200   apr_sha1_ctx_t sha1_ctx;\r
201 \r
202   SVN_ERR(validate_kind(kind));\r
203   *checksum = svn_checksum_create(kind, pool);\r
204 \r
205   switch (kind)\r
206     {\r
207       case svn_checksum_md5:\r
208         apr_md5((unsigned char *)(*checksum)->digest, data, len);\r
209         break;\r
210 \r
211       case svn_checksum_sha1:\r
212         apr_sha1_init(&sha1_ctx);\r
213         apr_sha1_update(&sha1_ctx, data, len);\r
214         apr_sha1_final((unsigned char *)(*checksum)->digest, &sha1_ctx);\r
215         break;\r
216 \r
217       default:\r
218         /* We really shouldn't get here, but if we do... */\r
219         return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);\r
220     }\r
221 \r
222   return SVN_NO_ERROR;\r
223 }\r
224 \r
225 \r
226 svn_checksum_t *\r
227 svn_checksum_empty_checksum(svn_checksum_kind_t kind,\r
228                             apr_pool_t *pool)\r
229 {\r
230   const unsigned char *digest;\r
231 \r
232   switch (kind)\r
233     {\r
234       case svn_checksum_md5:\r
235         digest = svn_md5__empty_string_digest();\r
236         break;\r
237 \r
238       case svn_checksum_sha1:\r
239         digest = svn_sha1__empty_string_digest();\r
240         break;\r
241 \r
242       default:\r
243         /* We really shouldn't get here, but if we do... */\r
244         return NULL;\r
245     }\r
246 \r
247   return svn_checksum__from_digest(digest, kind, pool);\r
248 }\r
249 \r
250 struct svn_checksum_ctx_t\r
251 {\r
252   void *apr_ctx;\r
253   svn_checksum_kind_t kind;\r
254 };\r
255 \r
256 svn_checksum_ctx_t *\r
257 svn_checksum_ctx_create(svn_checksum_kind_t kind,\r
258                         apr_pool_t *pool)\r
259 {\r
260   svn_checksum_ctx_t *ctx = apr_palloc(pool, sizeof(*ctx));\r
261 \r
262   ctx->kind = kind;\r
263   switch (kind)\r
264     {\r
265       case svn_checksum_md5:\r
266         ctx->apr_ctx = apr_palloc(pool, sizeof(apr_md5_ctx_t));\r
267         apr_md5_init(ctx->apr_ctx);\r
268         break;\r
269 \r
270       case svn_checksum_sha1:\r
271         ctx->apr_ctx = apr_palloc(pool, sizeof(apr_sha1_ctx_t));\r
272         apr_sha1_init(ctx->apr_ctx);\r
273         break;\r
274 \r
275       default:\r
276         return NULL;\r
277     }\r
278 \r
279   return ctx;\r
280 }\r
281 \r
282 svn_error_t *\r
283 svn_checksum_update(svn_checksum_ctx_t *ctx,\r
284                     const void *data,\r
285                     apr_size_t len)\r
286 {\r
287   switch (ctx->kind)\r
288     {\r
289       case svn_checksum_md5:\r
290         apr_md5_update(ctx->apr_ctx, data, len);\r
291         break;\r
292 \r
293       case svn_checksum_sha1:\r
294         apr_sha1_update(ctx->apr_ctx, data, len);\r
295         break;\r
296 \r
297       default:\r
298         /* We really shouldn't get here, but if we do... */\r
299         return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);\r
300     }\r
301 \r
302   return SVN_NO_ERROR;\r
303 }\r
304 \r
305 svn_error_t *\r
306 svn_checksum_final(svn_checksum_t **checksum,\r
307                    const svn_checksum_ctx_t *ctx,\r
308                    apr_pool_t *pool)\r
309 {\r
310   *checksum = svn_checksum_create(ctx->kind, pool);\r
311 \r
312   switch (ctx->kind)\r
313     {\r
314       case svn_checksum_md5:\r
315         apr_md5_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx);\r
316         break;\r
317 \r
318       case svn_checksum_sha1:\r
319         apr_sha1_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx);\r
320         break;\r
321 \r
322       default:\r
323         /* We really shouldn't get here, but if we do... */\r
324         return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);\r
325     }\r
326 \r
327   return SVN_NO_ERROR;\r
328 }\r
329 \r
330 apr_size_t\r
331 svn_checksum_size(const svn_checksum_t *checksum)\r
332 {\r
333   return DIGESTSIZE(checksum->kind);\r
334 }\r