| 1 | /* Copyright (C) 2021 The RetroArch team |
| 2 | * |
| 3 | * --------------------------------------------------------------------------------------- |
| 4 | * The following license statement only applies to this file (test_stdstring.c). |
| 5 | * --------------------------------------------------------------------------------------- |
| 6 | * |
| 7 | * Permission is hereby granted, free of charge, |
| 8 | * to any person obtaining a copy of this software and associated documentation files (the "Software"), |
| 9 | * to deal in the Software without restriction, including without limitation the rights to |
| 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, |
| 11 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
| 14 | * |
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
| 16 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 19 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 21 | */ |
| 22 | |
| 23 | #include <check.h> |
| 24 | #include <stdarg.h> |
| 25 | #include <stdlib.h> |
| 26 | #include <stdio.h> |
| 27 | |
| 28 | #include <utils/md5.h> |
| 29 | #include <encodings/crc32.h> |
| 30 | #include <streams/file_stream.h> |
| 31 | |
| 32 | #define SUITE_NAME "hash" |
| 33 | |
| 34 | START_TEST (test_md5) |
| 35 | { |
| 36 | uint8_t output[16]; |
| 37 | MD5_CTX ctx; |
| 38 | MD5_Init(&ctx); |
| 39 | MD5_Final(output, &ctx); |
| 40 | ck_assert(!memcmp( |
| 41 | "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e", |
| 42 | output, 16)); |
| 43 | MD5_Init(&ctx); |
| 44 | MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43); |
| 45 | MD5_Final(output, &ctx); |
| 46 | ck_assert(!memcmp( |
| 47 | "\x9e\x10\x7d\x9d\x37\x2b\xb6\x82\x6b\xd8\x1d\x35\x42\xa4\x19\xd6", |
| 48 | output, 16)); |
| 49 | MD5_Init(&ctx); |
| 50 | MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43); |
| 51 | MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43); |
| 52 | MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43); |
| 53 | MD5_Final(output, &ctx); |
| 54 | ck_assert(!memcmp( |
| 55 | "\x4e\x67\xdb\x4a\x7a\x40\x6b\x0c\xfd\xad\xd8\x87\xcd\xe7\x88\x8e", |
| 56 | output, 16)); |
| 57 | } |
| 58 | END_TEST |
| 59 | |
| 60 | START_TEST (test_crc32) |
| 61 | { |
| 62 | char buf1[] = "retroarch"; |
| 63 | char buf2[] = "12345678"; |
| 64 | char buf3[] = "The quick brown fox jumps over the lazy dog"; |
| 65 | uint32_t test1 = encoding_crc32(0, (uint8_t*)buf1, strlen(buf1)); |
| 66 | uint32_t test2 = encoding_crc32(0, (uint8_t*)buf2, strlen(buf2)); |
| 67 | uint32_t test3 = encoding_crc32(0, (uint8_t*)buf3, strlen(buf3)); |
| 68 | ck_assert_uint_eq(0x3cae141a, test1); |
| 69 | ck_assert_uint_eq(0x9ae0daaf, test2); |
| 70 | ck_assert_uint_eq(0x414fa339, test3); |
| 71 | } |
| 72 | END_TEST |
| 73 | |
| 74 | #define CRC32_BUFFER_SIZE 1048576 |
| 75 | #define CRC32_MAX_MB 64 |
| 76 | |
| 77 | /** |
| 78 | * Calculate a CRC32 from the first part of the given file. |
| 79 | * "first part" being the first (CRC32_BUFFER_SIZE * CRC32_MAX_MB) |
| 80 | * bytes. |
| 81 | * |
| 82 | * Returns: the crc32, or 0 if there was an error. |
| 83 | */ |
| 84 | static uint32_t file_crc32(uint32_t crc, const char *path) |
| 85 | { |
| 86 | unsigned i; |
| 87 | RFILE *file = NULL; |
| 88 | unsigned char *buf = NULL; |
| 89 | if (!path) |
| 90 | return 0; |
| 91 | |
| 92 | if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0))) |
| 93 | return 0; |
| 94 | |
| 95 | if (!(buf = (unsigned char*)malloc(CRC32_BUFFER_SIZE))) |
| 96 | { |
| 97 | filestream_close(file); |
| 98 | return 0; |
| 99 | } |
| 100 | |
| 101 | for (i = 0; i < CRC32_MAX_MB; i++) |
| 102 | { |
| 103 | int64_t nread = filestream_read(file, buf, CRC32_BUFFER_SIZE); |
| 104 | if (nread < 0) |
| 105 | { |
| 106 | free(buf); |
| 107 | filestream_close(file); |
| 108 | return 0; |
| 109 | } |
| 110 | |
| 111 | crc = encoding_crc32(crc, buf, (size_t)nread); |
| 112 | if (filestream_eof(file)) |
| 113 | break; |
| 114 | } |
| 115 | free(buf); |
| 116 | filestream_close(file); |
| 117 | return crc; |
| 118 | } |
| 119 | |
| 120 | START_TEST (test_crc32_file) |
| 121 | { |
| 122 | char tmpfile[512]; |
| 123 | FILE *fd; |
| 124 | tmpnam(tmpfile); |
| 125 | fd = fopen(tmpfile, "wb"); |
| 126 | ck_assert(fd != NULL); |
| 127 | fwrite("12345678", 1, 8, fd); |
| 128 | fclose(fd); |
| 129 | |
| 130 | ck_assert_uint_eq(file_crc32(0, tmpfile), 0x9ae0daaf); |
| 131 | /* Error checking */ |
| 132 | ck_assert_uint_eq(file_crc32(0, "/this/path/should/not/exist"), 0); |
| 133 | ck_assert_uint_eq(file_crc32(0, NULL), 0); |
| 134 | } |
| 135 | END_TEST |
| 136 | |
| 137 | Suite *create_suite(void) |
| 138 | { |
| 139 | Suite *s = suite_create(SUITE_NAME); |
| 140 | |
| 141 | TCase *tc_core = tcase_create("Core"); |
| 142 | tcase_add_test(tc_core, test_md5); |
| 143 | tcase_add_test(tc_core, test_crc32); |
| 144 | tcase_add_test(tc_core, test_crc32_file); |
| 145 | suite_add_tcase(s, tc_core); |
| 146 | |
| 147 | return s; |
| 148 | } |
| 149 | |
| 150 | int main(void) |
| 151 | { |
| 152 | int num_fail; |
| 153 | Suite *s = create_suite(); |
| 154 | SRunner *sr = srunner_create(s); |
| 155 | srunner_run_all(sr, CK_NORMAL); |
| 156 | num_fail = srunner_ntests_failed(sr); |
| 157 | srunner_free(sr); |
| 158 | return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE; |
| 159 | } |