@@ -1283,6 +1283,148 @@ void test_split_at_multiple_boundaries(void) {
12831283 free_test_cd_result (cd );
12841284}
12851285
1286+ // =============================================================================
1287+ // Central Directory Detection Tests
1288+ // =============================================================================
1289+
1290+ // Helper to create a Central Directory header signature
1291+ static size_t create_central_dir_header (uint8_t * buffer ) {
1292+ uint32_t sig = 0x02014b50 ; // ZIP_CENTRAL_DIR_HEADER_SIG
1293+ memcpy (buffer , & sig , 4 );
1294+ return 4 ;
1295+ }
1296+
1297+ void test_central_directory_at_expected_offset (void ) {
1298+ uint8_t buffer [1024 ];
1299+ size_t offset = 0 ;
1300+
1301+ // Create: local header + zstd frame + data descriptor + CD header
1302+ offset += create_local_header (buffer + offset , "test.txt" );
1303+ size_t zstd_size = create_test_zstd_frame (buffer + offset , sizeof (buffer ) - offset , 100 );
1304+ offset += zstd_size ;
1305+ offset += create_data_descriptor (buffer + offset , 0 , (uint32_t )zstd_size , 100 );
1306+
1307+ // Record where CD starts
1308+ size_t cd_offset = offset ;
1309+
1310+ // Add CD header signature
1311+ offset += create_central_dir_header (buffer + offset );
1312+
1313+ // Create cd_result with matching central_dir_offset
1314+ struct central_dir_parse_result * cd = create_test_cd_result ("test.txt" , 0 , zstd_size , 100 );
1315+ cd -> central_dir_offset = cd_offset ; // Set expected CD location
1316+
1317+ struct part_processor_state * state = part_processor_create (0 , cd , test_output_dir , 8 * 1024 * 1024 );
1318+
1319+ int rc = part_processor_process_data (state , buffer , offset );
1320+ TEST_ASSERT_EQUAL (STREAM_PROC_SUCCESS , rc );
1321+
1322+ rc = part_processor_finalize (state );
1323+ TEST_ASSERT_EQUAL (STREAM_PROC_SUCCESS , rc );
1324+
1325+ part_processor_destroy (state );
1326+ free_test_cd_result (cd );
1327+ }
1328+
1329+ void test_central_directory_before_expected_offset (void ) {
1330+ uint8_t buffer [1024 ];
1331+ size_t offset = 0 ;
1332+
1333+ // Create: local header + zstd frame + data descriptor + CD header
1334+ offset += create_local_header (buffer + offset , "test.txt" );
1335+ size_t zstd_size = create_test_zstd_frame (buffer + offset , sizeof (buffer ) - offset , 100 );
1336+ offset += zstd_size ;
1337+ offset += create_data_descriptor (buffer + offset , 0 , (uint32_t )zstd_size , 100 );
1338+
1339+ // Record where CD starts
1340+ size_t cd_offset = offset ;
1341+
1342+ // Add CD header signature
1343+ offset += create_central_dir_header (buffer + offset );
1344+
1345+ // Create cd_result with central_dir_offset set LARGER than actual
1346+ // (CD found earlier than expected - e.g., truncated archive)
1347+ struct central_dir_parse_result * cd = create_test_cd_result ("test.txt" , 0 , zstd_size , 100 );
1348+ cd -> central_dir_offset = cd_offset + 1000 ; // Expected later than actual
1349+
1350+ struct part_processor_state * state = part_processor_create (0 , cd , test_output_dir , 8 * 1024 * 1024 );
1351+
1352+ // Should still succeed (warning printed to stderr but no error)
1353+ int rc = part_processor_process_data (state , buffer , offset );
1354+ TEST_ASSERT_EQUAL (STREAM_PROC_SUCCESS , rc );
1355+
1356+ rc = part_processor_finalize (state );
1357+ TEST_ASSERT_EQUAL (STREAM_PROC_SUCCESS , rc );
1358+
1359+ part_processor_destroy (state );
1360+ free_test_cd_result (cd );
1361+ }
1362+
1363+ void test_central_directory_after_expected_offset (void ) {
1364+ uint8_t buffer [1024 ];
1365+ size_t offset = 0 ;
1366+
1367+ // Create: local header + zstd frame + data descriptor + CD header
1368+ offset += create_local_header (buffer + offset , "test.txt" );
1369+ size_t zstd_size = create_test_zstd_frame (buffer + offset , sizeof (buffer ) - offset , 100 );
1370+ offset += zstd_size ;
1371+ offset += create_data_descriptor (buffer + offset , 0 , (uint32_t )zstd_size , 100 );
1372+
1373+ // Record where CD starts
1374+ size_t cd_offset = offset ;
1375+
1376+ // Add CD header signature
1377+ offset += create_central_dir_header (buffer + offset );
1378+
1379+ // Create cd_result with central_dir_offset set SMALLER than actual
1380+ // (CD found later than expected - e.g., extra padding before CD)
1381+ struct central_dir_parse_result * cd = create_test_cd_result ("test.txt" , 0 , zstd_size , 100 );
1382+ cd -> central_dir_offset = cd_offset > 100 ? cd_offset - 100 : 0 ; // Expected earlier than actual
1383+
1384+ struct part_processor_state * state = part_processor_create (0 , cd , test_output_dir , 8 * 1024 * 1024 );
1385+
1386+ // Should still succeed (warning printed to stderr but no error)
1387+ int rc = part_processor_process_data (state , buffer , offset );
1388+ TEST_ASSERT_EQUAL (STREAM_PROC_SUCCESS , rc );
1389+
1390+ rc = part_processor_finalize (state );
1391+ TEST_ASSERT_EQUAL (STREAM_PROC_SUCCESS , rc );
1392+
1393+ part_processor_destroy (state );
1394+ free_test_cd_result (cd );
1395+ }
1396+
1397+ void test_central_directory_in_processing_frames_state (void ) {
1398+ // Test CD detection when in STATE_PROCESSING_FRAMES (with open file)
1399+ uint8_t buffer [1024 ];
1400+ size_t offset = 0 ;
1401+
1402+ // Create: local header + zstd frame (no data descriptor) + CD header
1403+ // This tests the FRAME_ZIP_CENTRAL_DIRECTORY case in STATE_PROCESSING_FRAMES
1404+ offset += create_local_header (buffer + offset , "test.txt" );
1405+ size_t zstd_size = create_test_zstd_frame (buffer + offset , sizeof (buffer ) - offset , 100 );
1406+ offset += zstd_size ;
1407+
1408+ // No data descriptor - go directly to CD
1409+ size_t cd_offset = offset ;
1410+ offset += create_central_dir_header (buffer + offset );
1411+
1412+ // Create cd_result - file uses no data descriptor (for this test)
1413+ struct central_dir_parse_result * cd = create_test_cd_result ("test.txt" , 0 , zstd_size , 100 );
1414+ cd -> central_dir_offset = cd_offset ;
1415+
1416+ struct part_processor_state * state = part_processor_create (0 , cd , test_output_dir , 8 * 1024 * 1024 );
1417+
1418+ int rc = part_processor_process_data (state , buffer , offset );
1419+ TEST_ASSERT_EQUAL (STREAM_PROC_SUCCESS , rc );
1420+
1421+ rc = part_processor_finalize (state );
1422+ TEST_ASSERT_EQUAL (STREAM_PROC_SUCCESS , rc );
1423+
1424+ part_processor_destroy (state );
1425+ free_test_cd_result (cd );
1426+ }
1427+
12861428int main (void ) {
12871429 UNITY_BEGIN ();
12881430
@@ -1330,5 +1472,11 @@ int main(void) {
13301472 RUN_TEST (test_split_mid_local_header_variable_fields );
13311473 RUN_TEST (test_split_at_multiple_boundaries );
13321474
1475+ // Central Directory detection tests
1476+ RUN_TEST (test_central_directory_at_expected_offset );
1477+ RUN_TEST (test_central_directory_before_expected_offset );
1478+ RUN_TEST (test_central_directory_after_expected_offset );
1479+ RUN_TEST (test_central_directory_in_processing_frames_state );
1480+
13331481 return UNITY_END ();
13341482}
0 commit comments