ByteCodeWriter   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 73
Duplicated Lines 0 %

Test Coverage

Coverage 86.49%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 41
c 1
b 0
f 0
dl 0
loc 73
ccs 32
cts 37
cp 0.8649
rs 10
wmc 13

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A flush() 0 12 5
A writeBlock() 0 10 3
A append() 0 21 4
1
<?php
2
declare(strict_types=1);
3
4
namespace SPSS;
5
6
/**
7
 * Class ByteCodeWriter
8
 * Abstracts bytecode (de)compression
9
 * @package SPSS
10
 */
11
class ByteCodeWriter
12
{
13
    private const BYTE_SYS_MISSING = 255;
14
    private const BYTE_SPACES = 254;
15
    private const BYTE_LITERAL = 253;
16
    private const BYTE_NUL = 0;
17
18
    /** @var Buffer  */
19
    private $buffer;
20
21
    private $commandBuffer = [];
22
    private $dataBuffer = '';
23
    private $data = '';
24
25 3
    public function __construct(Buffer $buffer)
26
    {
27 3
        $this->buffer = $buffer;
28 3
    }
29
30
    /**
31
     * Appends data, data might not actually be written until flush is called
32
     */
33 3
    public function append(string $data): void
34
    {
35 3
        $data = $this->dataBuffer . $data;
36 3
        $this->dataBuffer = '';
37 3
        while(strlen($data) >= 8) {
38 3
            $block = substr($data, 0, 8);
39 3
            $data = substr($data, 8);
40
            switch ($block) {
41 3
                case pack('d', -PHP_FLOAT_MAX):
42
                    $this->commandBuffer[] = self::BYTE_SYS_MISSING;
43
                    break;
44 3
                case '        ':
45
                    $this->commandBuffer[] = self::BYTE_SPACES;
46
                    break;
47
                default:
48 3
                    $this->commandBuffer[] = self::BYTE_LITERAL;
49 3
                    $this->data .= $block;
50
            }
51 3
            $this->writeBlock();
52
        }
53 3
        $this->dataBuffer .= $data;
54 3
    }
55
56 3
    private function writeBlock(): void
57
    {
58 3
        if (count($this->commandBuffer) === 8) {
59 3
            $commandBlock = '';
60 3
            foreach ($this->commandBuffer as $cmd) {
61 3
                $commandBlock .= chr($cmd);
62
            }
63 3
            $this->buffer->write($commandBlock . $this->data);
64 3
            $this->data = '';
65 3
            $this->commandBuffer = [];
66
        }
67 3
    }
68
69
    /**
70
     * Fills the command buffer with nuls and writes the remaining data.
71
     */
72 3
    public function flush(): void
73
    {
74
        // Write remaining data by padding with spaces.
75 3
        if (!empty($this->dataBuffer)) {
76 2
            $this->append(str_repeat(' ', 8 - strlen($this->dataBuffer)));
77
        }
78 3
        if (!empty($this->commandBuffer)) {
79 3
            $this->commandBuffer = array_pad($this->commandBuffer, 8, self::BYTE_NUL);
80 3
            $this->writeBlock();
81
        }
82 3
        if (!empty($this->dataBuffer) || !empty($this->commandBuffer)) {
83
            throw new \Exception('Failed to flush one of the buffers');
84
        }
85 3
    }
86
87
}