Coverage Report

Created: 2025-07-11 06:45

/src/minizip-ng/mz_os.c
Line
Count
Source (jump to first uncovered line)
1
/* mz_os.c -- System functions
2
   part of the minizip-ng project
3
4
   Copyright (C) Nathan Moinvaziri
5
     https://github.com/zlib-ng/minizip-ng
6
   Copyright (C) 1998-2010 Gilles Vollant
7
     https://www.winimage.com/zLibDll/minizip.html
8
9
   This program is distributed under the terms of the same license as zlib.
10
   See the accompanying LICENSE file for the full text of the license.
11
*/
12
13
#include "mz.h"
14
#include "mz_crypt.h"
15
#include "mz_os.h"
16
#include "mz_strm.h"
17
#include "mz_strm_os.h"
18
19
#include <ctype.h> /* tolower */
20
#include <string.h>
21
22
/***************************************************************************/
23
24
0
int32_t mz_path_combine(char *path, const char *join, int32_t max_path) {
25
0
    int32_t path_len = 0;
26
27
0
    if (!path || !join || !max_path)
28
0
        return MZ_PARAM_ERROR;
29
30
0
    path_len = (int32_t)strlen(path);
31
32
0
    if (path_len == 0) {
33
0
        strncpy(path, join, max_path - 1);
34
0
        path[max_path - 1] = 0;
35
0
    } else {
36
0
        mz_path_append_slash(path, max_path, MZ_PATH_SLASH_PLATFORM);
37
0
        path_len = (int32_t)strlen(path);
38
0
        if (max_path > path_len)
39
0
            strncat(path, join, max_path - path_len - 1);
40
0
    }
41
42
0
    return MZ_OK;
43
0
}
44
45
0
int32_t mz_path_append_slash(char *path, int32_t max_path, char slash) {
46
0
    int32_t path_len = (int32_t)strlen(path);
47
0
    if ((path_len + 2) >= max_path)
48
0
        return MZ_BUF_ERROR;
49
0
    if (!mz_os_is_dir_separator(path[path_len - 1])) {
50
0
        path[path_len] = slash;
51
0
        path[path_len + 1] = 0;
52
0
    }
53
0
    return MZ_OK;
54
0
}
55
56
0
int32_t mz_path_remove_slash(char *path) {
57
0
    int32_t path_len = (int32_t)strlen(path);
58
0
    while (path_len > 0) {
59
0
        if (mz_os_is_dir_separator(path[path_len - 1]))
60
0
            path[path_len - 1] = 0;
61
0
        else
62
0
            break;
63
64
0
        path_len -= 1;
65
0
    }
66
0
    return MZ_OK;
67
0
}
68
69
0
int32_t mz_path_has_slash(const char *path) {
70
0
    int32_t path_len = (int32_t)strlen(path);
71
0
    if (path_len > 0 && !mz_os_is_dir_separator(path[path_len - 1]))
72
0
        return MZ_EXIST_ERROR;
73
0
    return MZ_OK;
74
0
}
75
76
0
int32_t mz_path_convert_slashes(char *path, char slash) {
77
0
    int32_t i = 0;
78
79
0
    for (i = 0; i < (int32_t)strlen(path); i += 1) {
80
0
        if (mz_os_is_dir_separator(path[i]))
81
0
            path[i] = slash;
82
0
    }
83
0
    return MZ_OK;
84
0
}
85
86
0
int32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case) {
87
0
    while (*path != 0) {
88
0
        switch (*wildcard) {
89
0
        case '*':
90
91
0
            if (*(wildcard + 1) == 0)
92
0
                return MZ_OK;
93
94
0
            while (*path != 0) {
95
0
                if (mz_path_compare_wc(path, (wildcard + 1), ignore_case) == MZ_OK)
96
0
                    return MZ_OK;
97
98
0
                path += 1;
99
0
            }
100
101
0
            return MZ_EXIST_ERROR;
102
103
0
        default:
104
            /* Ignore differences in path slashes on platforms */
105
0
            if ((*path == '\\' && *wildcard == '/') || (*path == '/' && *wildcard == '\\'))
106
0
                break;
107
108
0
            if (ignore_case) {
109
0
                if (tolower(*path) != tolower(*wildcard))
110
0
                    return MZ_EXIST_ERROR;
111
0
            } else {
112
0
                if (*path != *wildcard)
113
0
                    return MZ_EXIST_ERROR;
114
0
            }
115
116
0
            break;
117
0
        }
118
119
0
        path += 1;
120
0
        wildcard += 1;
121
0
    }
122
123
0
    if ((*wildcard != 0) && (*wildcard != '*'))
124
0
        return MZ_EXIST_ERROR;
125
126
0
    return MZ_OK;
127
0
}
128
129
0
int32_t mz_path_resolve(const char *path, char *output, int32_t max_output) {
130
0
    const char *source = path;
131
0
    const char *check = output;
132
0
    char *target = output;
133
134
0
    if (max_output <= 0)
135
0
        return MZ_PARAM_ERROR;
136
137
0
    while (*source != 0 && max_output > 1) {
138
0
        check = source;
139
0
        if (mz_os_is_dir_separator(*check))
140
0
            check += 1;
141
142
0
        if (source == path || target == output || check != source) {
143
            /* Skip double paths */
144
0
            if (mz_os_is_dir_separator(*check)) {
145
0
                source += 1;
146
0
                continue;
147
0
            }
148
0
            if (*check == '.') {
149
0
                check += 1;
150
151
                /* Remove . if at end of string and not at the beginning */
152
0
                if (*check == 0 && source != path && target != output) {
153
                    /* Copy last slash */
154
0
                    *target = *source;
155
0
                    target += 1;
156
0
                    max_output -= 1;
157
0
                    source += (check - source);
158
0
                    continue;
159
0
                }
160
                /* Remove . if not at end of string */
161
0
                else if (mz_os_is_dir_separator(*check)) {
162
0
                    source += (check - source);
163
                    /* Skip slash if at beginning of string */
164
0
                    if (target == output && *source != 0)
165
0
                        source += 1;
166
0
                    continue;
167
0
                }
168
                /* Go to parent directory .. */
169
0
                else if (*check == '.') {
170
0
                    check += 1;
171
0
                    if (*check == 0 || mz_os_is_dir_separator(*check)) {
172
0
                        source += (check - source);
173
174
                        /* Search backwards for previous slash or the start of the output string */
175
0
                        if (target != output) {
176
0
                            target -= 1;
177
0
                            do {
178
0
                                if (target == output || mz_os_is_dir_separator(*target))
179
0
                                    break;
180
181
0
                                target -= 1;
182
0
                                max_output += 1;
183
0
                            } while (target > output);
184
0
                        }
185
186
0
                        if ((target == output) && *source != 0)
187
0
                            source += 1;
188
0
                        if (mz_os_is_dir_separator(*target) && *source == 0)
189
0
                            target += 1;
190
191
0
                        *target = 0;
192
0
                        continue;
193
0
                    }
194
0
                }
195
0
            }
196
0
        }
197
198
0
        *target = *source;
199
200
0
        source += 1;
201
0
        target += 1;
202
0
        max_output -= 1;
203
0
    }
204
205
0
    *target = 0;
206
207
0
    if (*path == 0)
208
0
        return MZ_INTERNAL_ERROR;
209
210
0
    return MZ_OK;
211
0
}
212
213
0
int32_t mz_path_remove_filename(char *path) {
214
0
    char *path_ptr = NULL;
215
216
0
    if (!path)
217
0
        return MZ_PARAM_ERROR;
218
219
0
    path_ptr = path + strlen(path) - 1;
220
221
0
    while (path_ptr > path) {
222
0
        if (mz_os_is_dir_separator(*path_ptr)) {
223
0
            *path_ptr = 0;
224
0
            break;
225
0
        }
226
227
0
        path_ptr -= 1;
228
0
    }
229
230
0
    if (path_ptr == path)
231
0
        *path_ptr = 0;
232
233
0
    return MZ_OK;
234
0
}
235
236
0
int32_t mz_path_remove_extension(char *path) {
237
0
    char *path_ptr = NULL;
238
239
0
    if (!path)
240
0
        return MZ_PARAM_ERROR;
241
242
0
    path_ptr = path + strlen(path) - 1;
243
244
0
    while (path_ptr > path) {
245
0
        if (mz_os_is_dir_separator(*path_ptr))
246
0
            break;
247
0
        if (*path_ptr == '.') {
248
0
            *path_ptr = 0;
249
0
            break;
250
0
        }
251
252
0
        path_ptr -= 1;
253
0
    }
254
255
0
    if (path_ptr == path)
256
0
        *path_ptr = 0;
257
258
0
    return MZ_OK;
259
0
}
260
261
0
int32_t mz_path_get_filename(const char *path, const char **filename) {
262
0
    const char *match = NULL;
263
264
0
    if (!path || !filename)
265
0
        return MZ_PARAM_ERROR;
266
267
0
    *filename = NULL;
268
269
0
    for (match = path; *match != 0; match += 1) {
270
0
        if (mz_os_is_dir_separator(*match))
271
0
            *filename = match + 1;
272
0
    }
273
274
0
    if (!*filename)
275
0
        return MZ_EXIST_ERROR;
276
277
0
    return MZ_OK;
278
0
}
279
280
0
int32_t mz_dir_make(const char *path) {
281
0
    int32_t err = MZ_OK;
282
0
    char *current_dir = NULL;
283
0
    char *match = NULL;
284
0
    char hold = 0;
285
286
0
    if (!*path)
287
0
        return MZ_OK;
288
289
0
    current_dir = strdup(path);
290
0
    if (!current_dir)
291
0
        return MZ_MEM_ERROR;
292
293
0
    mz_path_remove_slash(current_dir);
294
295
0
    err = mz_os_make_dir(current_dir);
296
0
    if (err != MZ_OK) {
297
0
        match = current_dir + 1;
298
0
        while (1) {
299
0
            while (*match != 0 && !mz_os_is_dir_separator(*match))
300
0
                match += 1;
301
0
            hold = *match;
302
0
            *match = 0;
303
304
0
            err = mz_os_make_dir(current_dir);
305
0
            if (err != MZ_OK)
306
0
                break;
307
0
            if (hold == 0)
308
0
                break;
309
310
0
            *match = hold;
311
0
            match += 1;
312
0
        }
313
0
    }
314
315
0
    free(current_dir);
316
0
    return err;
317
0
}
318
319
0
int32_t mz_file_get_crc(const char *path, uint32_t *result_crc) {
320
0
    void *stream = NULL;
321
0
    uint32_t crc32 = 0;
322
0
    int32_t read = 0;
323
0
    int32_t err = MZ_OK;
324
0
    uint8_t buf[16384];
325
326
0
    stream = mz_stream_os_create();
327
0
    if (!stream)
328
0
        return MZ_MEM_ERROR;
329
330
0
    err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);
331
0
    if (err == MZ_OK) {
332
0
        do {
333
0
            read = mz_stream_os_read(stream, buf, sizeof(buf));
334
335
0
            if (read < 0) {
336
0
                err = read;
337
0
                break;
338
0
            }
339
340
0
            crc32 = mz_crypt_crc32_update(crc32, buf, read);
341
0
        } while ((err == MZ_OK) && (read > 0));
342
343
0
        mz_stream_os_close(stream);
344
0
    }
345
346
0
    *result_crc = crc32;
347
348
0
    mz_stream_os_delete(&stream);
349
350
0
    return err;
351
0
}
352
353
/***************************************************************************/