clang-tidy: readability-non-const-parameter
[geeqie.git] / src / md5-util.cc
1 /*
2  * Copyright (C) 1993 Branko Lankester
3  * Copyright (C) 1993 Colin Plumb
4  * Copyright (C) 1995 Erik Troan
5  * Copyright (C) 2004 John Ellis
6  * Copyright (C) 2008 - 2016 The Geeqie Team
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * This code implements the MD5 message-digest algorithm.
23  * The algorithm is due to Ron Rivest.  This code was
24  * written by Colin Plumb in 1993, no copyright is claimed.
25  * This code is in the public domain; do with it what you wish.
26  *
27  * Equivalent code is available from RSA Data Security, Inc.
28  * This code has been tested against that, and is equivalent,
29  * except that you don't need to include two pages of legalese
30  * with every copy.
31  */
32
33 #include "md5-util.h"
34
35 #include <cstdio>
36 #include <cstring>
37 #include <memory>
38
39 using GQChecksumPtr = std::unique_ptr<GChecksum, decltype(&g_checksum_free)>;
40
41 constexpr gsize MD5_SIZE = 16;
42
43 /**
44  * md5_update_from_file: get the md5 hash of a file
45  * @md5: MD5 checksumming context
46  * @path: file name
47  * @return: TRUE on success
48  *
49  * Get the md5 hash of a file.
50  **/
51 static gboolean md5_update_from_file(GChecksum *md5, const gchar *path)
52 {
53         guchar tmp_buf[1024];
54         gint nb_bytes_read;
55         FILE *fp;
56         gint success;
57
58         fp = fopen(path, "r");
59         if (!fp) return FALSE;
60
61         while ((nb_bytes_read = fread(tmp_buf, sizeof (guchar), sizeof(tmp_buf), fp)) > 0)
62                 {
63                 g_checksum_update(md5, tmp_buf, nb_bytes_read);
64                 }
65
66         success = (ferror(fp) == 0);
67         fclose(fp);
68
69         return success;
70 }
71
72 /**
73  * md5_get_string: get the md5 hash of a buffer
74  * @buffer: byte buffer
75  * @buffer_size: buffer size (in bytes)
76  * @return: hash as a hexadecimal string
77  *
78  * Get the md5 hash of a buffer. The result is returned
79  * as a hexadecimal string.
80  **/
81 gchar *md5_get_string(const guchar *buffer, gint buffer_size)
82 {
83         GQChecksumPtr md5{g_checksum_new(G_CHECKSUM_MD5), g_checksum_free};
84         if (!md5) return nullptr;
85
86         g_checksum_update(md5.get(), buffer, buffer_size);
87
88         return g_strdup(g_checksum_get_string(md5.get()));
89 }
90
91 /**
92  * md5_get_digest_from_file: get the md5 hash of a file
93  * @filename: file name
94  * @digest: 16 bytes buffer receiving the hash code.
95  * @return: TRUE on success
96  *
97  * Get the md5 hash of a file. The result is put in
98  * the 16 bytes buffer @digest .
99  **/
100 gboolean md5_get_digest_from_file(const gchar *path, guchar digest[16])
101 {
102         GQChecksumPtr md5{g_checksum_new(G_CHECKSUM_MD5), g_checksum_free};
103         if (!md5) return FALSE;
104
105         if (!md5_update_from_file(md5.get(), path)) return FALSE;
106
107         gsize digest_size = MD5_SIZE;
108         g_checksum_get_digest(md5.get(), digest, &digest_size);
109         if (digest_size != MD5_SIZE) return FALSE;
110
111         return TRUE;
112 }
113
114 /**
115  * md5_get_string_from_file: get the md5 hash of a file
116  * @filename: file name
117  * @return: hash as a hexadecimal string
118  *
119  * Get the md5 hash of a file. The result is returned
120  * as a hexadecimal string.
121  **/
122 gchar *md5_get_string_from_file(const gchar *path)
123 {
124         GQChecksumPtr md5{g_checksum_new(G_CHECKSUM_MD5), g_checksum_free};
125         if (!md5) return nullptr;
126
127         if (!md5_update_from_file(md5.get(), path)) return nullptr;
128
129         return g_strdup(g_checksum_get_string(md5.get()));
130 }
131
132 /* these to and from text string converters were borrowed from
133  * the libgnomeui library, where they are name thumb_digest_to/from_ascii
134  *
135  * this version of the from text util does buffer length checking,
136  * and assumes a NULL terminated string.
137  */
138
139 gchar *md5_digest_to_text(const guchar digest[16])
140 {
141         static gchar hex_digits[] = "0123456789abcdef";
142         gchar *result;
143         constexpr gsize result_size = 2 * MD5_SIZE;
144
145         result = static_cast<gchar *>(g_malloc((result_size + 1) * sizeof(gchar)));
146         for (gsize i = 0; i < MD5_SIZE; i++)
147                 {
148                 result[2*i] = hex_digits[digest[i] >> 4];
149                 result[2*i+1] = hex_digits[digest[i] & 0xf];
150                 }
151         result[result_size] = '\0';
152
153         return result;
154 }
155
156 gboolean md5_digest_from_text(const gchar *text, guchar digest[16])
157 {
158         for (gsize i = 0; i < MD5_SIZE; i++)
159                 {
160                 if (text[2*i] == '\0' || text[2*i+1] == '\0') return FALSE;
161                 digest[i] = g_ascii_xdigit_value(text[2*i]) << 4 |
162                             g_ascii_xdigit_value(text[2*i + 1]);
163                 }
164
165         return TRUE;
166 }
167
168 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */