GCC Code Coverage Report


Directory: Utils/
File: CRCChecker.cpp
Date: 2026-09-23 21:15:08
Exec Total Coverage
Lines: 106 119 89.1%
Functions: 3 3 100.0%
Branches: 77 96 80.2%

Line Branch Exec Source
1 // ======================================================================
2 // \title CRCChecker.cpp
3 // \author ortega
4 // \brief cpp file for a crc32 checker
5 //
6 // \copyright
7 // Copyright 2009-2020, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 // ======================================================================
11
12 #include <Fw/FPrimeBasicTypes.hpp>
13 #include <Fw/Types/Assert.hpp>
14 #include <Fw/Types/FileNameString.hpp>
15 #include <Fw/Types/SerialBuffer.hpp>
16 #include <Os/File.hpp>
17 #include <Os/FileSystem.hpp>
18 #include <Utils/CRCChecker.hpp>
19 #include <Utils/Hash/Hash.hpp>
20
21 namespace Utils {
22 38 crc_stat_t create_checksum_file(const char* const fname) {
23 38 FW_ASSERT(fname != nullptr);
24
25 FwSizeType i;
26 FwSizeType blocks;
27 FwSizeType remaining_bytes;
28 38 FwSizeType filesize;
29
1/1
✓ Branch 2 taken 38 times.
38 Os::File f;
30 Os::FileSystem::Status fs_stat;
31 Os::File::Status stat;
32
1/1
✓ Branch 2 taken 38 times.
38 Utils::Hash hash;
33 38 U32 checksum;
34 38 FwSizeType bytes_to_read;
35 38 FwSizeType bytes_to_write;
36
1/1
✓ Branch 2 taken 38 times.
38 Fw::FileNameString hashFilename;
37 38 U8 block_data[CRC_FILE_READ_BLOCK];
38
39
1/1
✓ Branch 1 taken 38 times.
38 fs_stat = Os::FileSystem::getFileSize(fname, filesize);
40
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 37 times.
38 if (fs_stat != Os::FileSystem::OP_OK) {
41 1 return FAILED_FILE_SIZE;
42 }
43
44 // Open file
45
1/1
✓ Branch 2 taken 37 times.
37 stat = f.open(fname, Os::File::OPEN_READ);
46
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (stat != Os::File::OP_OK) {
47 ✗ return FAILED_FILE_OPEN;
48 }
49
50 // Read file
51 37 bytes_to_read = CRC_FILE_READ_BLOCK;
52 37 blocks = filesize / CRC_FILE_READ_BLOCK;
53
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 37 times.
76 for (i = 0; i < blocks; i++) {
54
1/1
✓ Branch 2 taken 39 times.
39 stat = f.read(block_data, bytes_to_read);
55
2/4
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
39 if (stat != Os::File::OP_OK || bytes_to_read != CRC_FILE_READ_BLOCK) {
56 ✗ f.close();
57 ✗ return FAILED_FILE_READ;
58 }
59
60
1/1
✓ Branch 1 taken 39 times.
39 hash.update(block_data, bytes_to_read);
61 }
62
63 37 remaining_bytes = filesize % CRC_FILE_READ_BLOCK;
64 37 bytes_to_read = remaining_bytes;
65
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 2 times.
37 if (remaining_bytes > 0) {
66
1/1
✓ Branch 2 taken 35 times.
35 stat = f.read(block_data, bytes_to_read);
67
2/4
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 35 times.
35 if (stat != Os::File::OP_OK || bytes_to_read != remaining_bytes) {
68 ✗ f.close();
69 ✗ return FAILED_FILE_READ;
70 }
71
72
1/1
✓ Branch 1 taken 35 times.
35 hash.update(block_data, remaining_bytes);
73 }
74
75 // close file
76
1/1
✓ Branch 2 taken 37 times.
37 f.close();
77
78 // generate checksum
79
1/1
✓ Branch 1 taken 37 times.
37 hash.finalize(checksum);
80
81 // open checksum file. The filename is caller-supplied input: an overlong name is a reportable
82 // failure, not a coding error, so it must not assert.
83
1/1
✓ Branch 2 taken 37 times.
37 Fw::FormatStatus formatStatus = hashFilename.format("%s%s", fname, HASH_EXTENSION_STRING);
84
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 35 times.
37 if (formatStatus != Fw::FormatStatus::SUCCESS) {
85 2 return FAILED_FILE_NAME_TOO_LONG;
86 }
87
88
1/1
✓ Branch 4 taken 35 times.
35 stat = f.open(hashFilename.toChar(), Os::File::OPEN_WRITE);
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (stat != Os::File::OP_OK) {
90 ✗ return FAILED_FILE_CRC_OPEN;
91 }
92
93 // Write checksum file. Serialize the value rather than writing the raw U32 bytes so that the
94 // file contents do not depend on the endianness of the processor.
95 35 U8 checksum_data[sizeof(checksum)] = {};
96
1/1
✓ Branch 2 taken 35 times.
35 Fw::SerialBuffer checksum_buffer(checksum_data, sizeof(checksum_data));
97
1/1
✓ Branch 2 taken 35 times.
35 Fw::SerializeStatus ser_stat = checksum_buffer.serializeFrom(checksum);
98 35 FW_ASSERT(Fw::FW_SERIALIZE_OK == ser_stat, static_cast<FwAssertArgType>(ser_stat));
99
100
1/1
✓ Branch 2 taken 35 times.
35 bytes_to_write = checksum_buffer.getSize();
101
1/1
✓ Branch 4 taken 35 times.
35 stat = f.write(checksum_buffer.getBuffAddr(), bytes_to_write);
102
2/4
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 35 times.
35 if (stat != Os::File::OP_OK || sizeof(checksum) != bytes_to_write) {
103 ✗ f.close();
104 ✗ return FAILED_FILE_CRC_WRITE;
105 }
106
107 // close checksum file
108
1/1
✓ Branch 2 taken 35 times.
35 f.close();
109
110 35 return PASSED_FILE_CRC_WRITE;
111 38 }
112
113 69 crc_stat_t read_crc32_from_file(const char* const fname, U32& checksum_from_file) {
114
1/1
✓ Branch 2 taken 69 times.
69 Os::File f;
115 Os::File::Status stat;
116
1/1
✓ Branch 2 taken 69 times.
69 Fw::FileNameString hashFilename;
117 69 FW_ASSERT(fname != nullptr);
118 // open checksum file. See create_checksum_file(): overlong names are reported, not asserted.
119
1/1
✓ Branch 2 taken 69 times.
69 Fw::FormatStatus formatStatus = hashFilename.format("%s%s", fname, HASH_EXTENSION_STRING);
120
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 65 times.
69 if (formatStatus != Fw::FormatStatus::SUCCESS) {
121 4 return FAILED_FILE_NAME_TOO_LONG;
122 }
123
124
1/1
✓ Branch 4 taken 65 times.
65 stat = f.open(hashFilename.toChar(), Os::File::OPEN_READ);
125
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 63 times.
65 if (stat != Os::File::OP_OK) {
126 2 return FAILED_FILE_CRC_OPEN;
127 }
128
129 // Read checksum file
130 63 U8 checksum_data[sizeof(checksum_from_file)] = {};
131 63 FwSizeType checksum_from_file_size = static_cast<FwSizeType>(sizeof(checksum_from_file));
132
1/1
✓ Branch 2 taken 63 times.
63 stat = f.read(checksum_data, checksum_from_file_size);
133
3/4
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 61 times.
63 if (stat != Os::File::OP_OK || checksum_from_file_size != sizeof(checksum_from_file)) {
134
1/1
✓ Branch 2 taken 2 times.
2 f.close();
135 2 return FAILED_FILE_CRC_READ;
136 }
137
138 // Deserialize the value to match the serialized form written by create_checksum_file
139
1/1
✓ Branch 2 taken 61 times.
61 Fw::SerialBuffer checksum_buffer(checksum_data, sizeof(checksum_data));
140
1/1
✓ Branch 2 taken 61 times.
61 checksum_buffer.fill();
141
1/1
✓ Branch 2 taken 61 times.
61 Fw::SerializeStatus ser_stat = checksum_buffer.deserializeTo(checksum_from_file);
142 61 FW_ASSERT(Fw::FW_SERIALIZE_OK == ser_stat, static_cast<FwAssertArgType>(ser_stat));
143
144 // close checksum file
145
1/1
✓ Branch 2 taken 61 times.
61 f.close();
146 61 return PASSED_FILE_CRC_CHECK;
147 69 }
148
149 64 crc_stat_t verify_checksum(const char* const fname, U32& expected, U32& actual) {
150 64 FW_ASSERT(fname != nullptr);
151
152 FwSizeType i;
153 FwSizeType blocks;
154 FwSizeType remaining_bytes;
155 64 FwSizeType filesize;
156
1/1
✓ Branch 2 taken 64 times.
64 Os::File f;
157 Os::FileSystem::Status fs_stat;
158 Os::File::Status stat;
159
1/1
✓ Branch 2 taken 64 times.
64 Utils::Hash hash;
160 64 U32 checksum;
161 64 U32 checksum_from_file;
162 64 FwSizeType bytes_to_read;
163 64 U8 block_data[CRC_FILE_READ_BLOCK];
164
165
1/1
✓ Branch 1 taken 64 times.
64 fs_stat = Os::FileSystem::getFileSize(fname, filesize);
166
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 63 times.
64 if (fs_stat != Os::FileSystem::OP_OK) {
167 1 return FAILED_FILE_SIZE;
168 }
169
170 // Open file
171
1/1
✓ Branch 2 taken 63 times.
63 stat = f.open(fname, Os::File::OPEN_READ);
172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 if (stat != Os::File::OP_OK) {
173 ✗ return FAILED_FILE_OPEN;
174 }
175
176 // Read file
177 63 bytes_to_read = CRC_FILE_READ_BLOCK;
178 63 blocks = filesize / CRC_FILE_READ_BLOCK;
179
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 63 times.
136 for (i = 0; i < blocks; i++) {
180
1/1
✓ Branch 2 taken 73 times.
73 stat = f.read(block_data, bytes_to_read);
181
2/4
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 73 times.
73 if (stat != Os::File::OP_OK || bytes_to_read != CRC_FILE_READ_BLOCK) {
182 ✗ f.close();
183 ✗ return FAILED_FILE_READ;
184 }
185
186
1/1
✓ Branch 1 taken 73 times.
73 hash.update(block_data, static_cast<FwSizeType>(bytes_to_read));
187 }
188
189 63 remaining_bytes = filesize % CRC_FILE_READ_BLOCK;
190 63 bytes_to_read = remaining_bytes;
191
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 2 times.
63 if (remaining_bytes > 0) {
192
1/1
✓ Branch 2 taken 61 times.
61 stat = f.read(block_data, bytes_to_read);
193
2/4
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 61 times.
61 if (stat != Os::File::OP_OK || bytes_to_read != remaining_bytes) {
194 ✗ f.close();
195 ✗ return FAILED_FILE_READ;
196 }
197
198
1/1
✓ Branch 1 taken 61 times.
61 hash.update(block_data, remaining_bytes);
199 }
200
201 // close file
202
1/1
✓ Branch 2 taken 63 times.
63 f.close();
203 // generate checksum
204
1/1
✓ Branch 1 taken 63 times.
63 hash.finalize(checksum);
205
206
1/1
✓ Branch 1 taken 63 times.
63 crc_stat_t crcstat = read_crc32_from_file(fname, checksum_from_file);
207
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 59 times.
63 if (crcstat != PASSED_FILE_CRC_CHECK) {
208 4 return crcstat;
209 }
210
211 // compare checksums
212
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 33 times.
59 if (checksum != checksum_from_file) {
213 26 expected = checksum_from_file;
214 26 actual = checksum;
215 26 return FAILED_FILE_CRC_CHECK;
216 }
217
218 33 expected = checksum_from_file;
219 33 actual = checksum;
220 33 return PASSED_FILE_CRC_CHECK;
221 64 }
222
223 } // namespace Utils
224