MacSubblockTest.java

package com.github.junrar.bugfixes;

import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * Regression test for archives containing MAC_HEAD (0x77 subtype 0x0102) subblocks
 * interleaved between file entries, as produced by Mac OS RAR archivers.
 * <p>
 * The bug: junrar read only the fixed-size MacInfoHeader (8 bytes) from the subblock's
 * packed data but never seeked past the remaining bytes, leaving the channel positioned
 * mid-block. Every subsequent file header was then parsed from the wrong offset, causing
 * a CorruptHeaderException and making the archive appear unreadable.
 */
public class MacSubblockTest {

    @Test
    public void archiveWithMacSubblocksBetweenFilesCanBeListedAndExtracted() throws Exception {
        File f = new File(getClass().getResource("mac-subblock.rar").toURI());
        try (Archive archive = new Archive(f)) {
            assertThat(archive.isPasswordProtected()).isFalse();
            assertThat(archive.isEncrypted()).isFalse();

            List<FileHeader> fileHeaders = archive.getFileHeaders();
            assertThat(fileHeaders).hasSize(2);

            FileHeader first = fileHeaders.get(0);
            assertThat(first.getFileName()).isEqualTo("file1.txt");
            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                IOUtils.copy(archive.getInputStream(first), baos);
                assertThat(baos.toString()).isEqualTo("hello\n");
            }

            FileHeader second = fileHeaders.get(1);
            assertThat(second.getFileName()).isEqualTo("file2.txt");
            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                IOUtils.copy(archive.getInputStream(second), baos);
                assertThat(baos.toString()).isEqualTo("world\n");
            }
        }
    }
}