ArchiveWriter   A
last analyzed

Complexity

Total Complexity 3

Size/Duplication

Total Lines 61
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 5

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 61
ccs 0
cts 36
cp 0
rs 10
c 0
b 0
f 0
wmc 3
lcom 0
cbo 5

1 Method

Rating   Name   Duplication   Size   Complexity  
A write() 0 53 3
1
<?php
2
3
/*
4
 * (c) 2018 Dennis Birkholz <[email protected]>
5
 *
6
 * $Id$
7
 * Author:    $Format:%an <%ae>, %ai$
8
 * Committer: $Format:%cn <%ce>, %ci$
9
 */
10
11
namespace morgue\zip;
12
13
use morgue\archive\Archive;
14
use morgue\archive\ArchiveWriterInterface;
15
16
/**
17
 * @author Dennis Birkholz <[email protected]>
18
 */
19
final class ArchiveWriter implements ArchiveWriterInterface
20
{
21
    /**
22
     * @param Archive $archive
23
     * @param resource $targetStream
24
     * @return Archive The archive updated with information only available after writing it
25
     */
26
    public function write(Archive $archive, $targetStream) : Archive
27
    {
28
        $centralDirectory = [];
29
30
        foreach ($archive->getEntries() as $archiveEntry) {
31
            // Write local file header
32
            $entryStartPosition = \ftell($targetStream);
33
            $localFileHeader = LocalFileHeader::createFromArchiveEntry($archiveEntry);
34
            \fwrite($targetStream, $localFileHeader->marshal());
35
36
            // Write file content
37
            $fileStartPosition = \ftell($targetStream);
38
            \stream_copy_to_stream($archiveEntry->getSourceStream(), $targetStream);
39
40
            // Position where next entry will be written
41
            $nextEntryPosition = \ftell($targetStream);
42
43
            // Re-write local file header with additional information known after compression only
44
            $localFileHeader = $localFileHeader->setCompressedSize($nextEntryPosition - $fileStartPosition);
45
            \fseek($targetStream, $entryStartPosition);
46
            \fwrite($targetStream, $localFileHeader->marshal());
47
48
            // Update archive entry with additional information known after compression only
49
            $archive = $archive->replaceEntry($archiveEntry, $archiveEntry->withTargetSize($localFileHeader->getCompressedSize()));
50
51
            // Move into position for next entry
52
            \fseek($targetStream, $nextEntryPosition);
53
54
            // Create central directory entry
55
            $centralDirectory[] = CentralDirectoryHeader::createFromArchiveEntry($archiveEntry)
56
                ->setRelativeOffsetOfLocalHeader($entryStartPosition)
57
            ;
58
        }
59
60
        $centralDirectorySize = 0;
61
        $centralDirectoryStart = \ftell($targetStream);
62
        foreach ($centralDirectory as $centralDirectoryHeader) {
63
            $centralDirectorySize += \fwrite($targetStream, $centralDirectoryHeader->encode());
64
        }
65
66
        $endOfCentralDirectory = new EndOfCentralDirectory(
67
            0,
68
            0,
69
            \count($centralDirectory),
70
            \count($centralDirectory),
71
            $centralDirectorySize,
72
            $centralDirectoryStart,
73
            $archive->getComment()
74
        );
75
        \fwrite($targetStream, $endOfCentralDirectory->marshal());
76
77
        return $archive;
78
    }
79
}
80