Completed
Push — master ( 76b46b...7ee4bf )
by Ben
02:22
created

ObjectWriter::ensureBlankLine()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
rs 9.6667
cc 2
eloc 5
nc 2
nop 0
1
<?php
2
/**
3
 * BaconPdf
4
 *
5
 * @link      http://github.com/Bacon/BaconPdf For the canonical source repository
6
 * @copyright 2015 Ben Scholzen (DASPRiD)
7
 * @license   http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
 */
9
10
namespace Bacon\Pdf\Writer;
11
12
use Bacon\Pdf\Exception\InvalidArgumentException;
13
use SplFileObject;
14
15
class ObjectWriter
16
{
17
    /**
18
     * @var SplFileObject|null
19
     */
20
    private $fileObject;
21
22
    /**
23
     * @var int
24
     */
25
    private $currentLineLength = 0;
26
27
    /**
28
     * @var bool
29
     */
30
    private $requiresWhitespace = false;
31
32
    /**
33
     * @param SplFileObject $fileObject
34
     */
35
    public function __construct(SplFileObject $fileObject)
36
    {
37
        $this->fileObject = $fileObject;
38
    }
39
40
    /**
41
     * Writes raw data line to the stream.
42
     *
43
     * This method does not obey the normal line length limit, so you have to take care of that yourself. Note that the
44
     * writer may still be on an active line, so take that into account as well.
45
     *
46
     * @param string $data
47
     */
48
    public function writeRawLine($data)
49
    {
50
        if (null === $this->fileObject) {
51
            throw new WriterClosedException('The writer object was closed');
52
        }
53
54
        $this->fileObject->fwrite($data. "\n");
55
        $this->currentLineLength = 0;
56
    }
57
58
    /**
59
     * Ensures that the writer is on a blank line.
60
     */
61
    public function ensureBlankLine()
62
    {
63
        if ($this->currentLineLength === 0) {
64
            return;
65
        }
66
67
        $this->fileObject->fwrite("\n");
68
        $this->currentLineLength = 0;
69
    }
70
71
    /**
72
     * Returns the current position in the file.
73
     *
74
     * @return int
75
     */
76
    public function currentOffset()
77
    {
78
        return $this->fileObject->ftell();
79
    }
80
81
    /**
82
     * Starts a dictionary.
83
     */
84
    public function startDictionary()
85
    {
86
        $this->writeData('<<', false);
87
        $this->requiresWhitespace = false;
88
    }
89
90
    /**
91
     * Ends a dictionary.
92
     */
93
    public function endDictionary()
94
    {
95
        $this->writeData('>>', false);
96
        $this->requiresWhitespace = false;
97
    }
98
99
    /**
100
     * Starts an array.
101
     */
102
    public function startArray()
103
    {
104
        $this->writeData('[', false);
105
        $this->requiresWhitespace = false;
106
    }
107
108
    /**
109
     * Ends an array.
110
     */
111
    public function endArray()
112
    {
113
        $this->writeData(']', false);
114
        $this->requiresWhitespace = false;
115
    }
116
117
    /**
118
     * Writes a null value.
119
     */
120
    public function writeNull()
121
    {
122
        $this->writeData('null', true);
123
        $this->requiresWhitespace = true;
124
    }
125
126
    /**
127
     * Writes a boolean.
128
     *
129
     * @param bool $boolean
130
     */
131
    public function writeBoolean($boolean)
132
    {
133
        $this->writeData($boolean ? 'true' : 'false', true);
134
        $this->requiresWhitespace = true;
135
    }
136
137
    /**
138
     * Writes a number.
139
     *
140
     * @param  int|float $number
141
     * @throws InvalidArgumentException
142
     */
143
    public function writeNumber($number)
144
    {
145
        if (is_int($number)) {
146
            $value = (string) $number;
147
        } elseif (is_float($number)) {
148
            $value = sprintf('%F', $number);
149
        } else {
150
            throw new InvalidArgumentException(sprintf(
151
                'Expected int or float, got %s',
152
                gettype($number)
153
            ));
154
        }
155
156
        $this->writeData($value, true);
157
        $this->requiresWhitespace = true;
158
    }
159
160
    /**
161
     * Writes a name.
162
     *
163
     * @param string $name
164
     */
165
    public function writeName($name)
166
    {
167
        $this->writeData('/' . $name, false);
168
        $this->requiresWhitespace = true;
169
    }
170
171
    /**
172
     * Writes a literal string.
173
     *
174
     * The string itself is splitted into multiple lines after 248 characters. We chose that specific limit to avoid
175
     * splitting mutli-byte characters in half.
176
     *
177
     * @param string $string
178
     */
179
    public function writeLiteralString($string)
180
    {
181
        $this->writeData('(' . chunk_split(strtr($string, [
182
            '(' => '\\(',
183
            ')' => '\\)',
184
            '\\' => '\\\\',
185
        ]), 248, "\\\n") . ')', false, "\\\n");
0 ignored issues
show
Unused Code introduced by
The call to ObjectWriter::writeData() has too many arguments starting with '\\ '.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
186
        $this->requiresWhitespace = false;
187
    }
188
189
    /**
190
     * Writes a hexadecimal string.
191
     *
192
     * @param string $string
193
     */
194
    public function writeHexadecimalString($string)
195
    {
196
        $this->writeData('<' . chunk_split(bin2hex($string), 248, "\n") . '>', false, "\n");
0 ignored issues
show
Unused Code introduced by
The call to ObjectWriter::writeData() has too many arguments starting with ' '.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
197
        $this->requiresWhitespace = false;
198
    }
199
200
    /**
201
     * Unsets the file object so it can release the file pointer.
202
     */
203
    public function close()
204
    {
205
        $this->fileObject = null;
206
    }
207
208
    /**
209
     * Writes data to the stream while obeying the maximum line length of 255 characters.
210
     *
211
     * If $this->requiresWhitespace is true, it means that the last token requires a whitespace character in case the
212
     * next token begins with an alphanumeric character. If that is the case, the callee should set $prependWhitespace
213
     * to true, so that a whitespace is appended in that case, which may either be a space or a newline.
214
     *
215
     * @param string $data
216
     * @param bool   $prependWhitespace
217
     */
218
    private function writeData($data, $prependWhitespace)
219
    {
220
        if (null === $this->fileObject) {
221
            throw new WriterClosedException('The writer object was closed');
222
        }
223
224
        $dataSize = strlen($data);
225
226
        if ($this->requiresWhitespace && $prependWhitespace) {
227
            $dataSize += 1;
228
        }
229
230
        if ($this->currentLineLength + $dataSize >= 255) {
231
            $this->fileObject->fwrite("\n");
232
            $this->currentLineLength = 0;
233
            $this->requiresWhitespace = false;
234
            $dataSize -= 1;
235
        } elseif ($this->requiresWhitespace && $prependWhitespace) {
236
            $this->fileObject->fwrite(' ');
237
        }
238
239
        $this->fileObject->fwrite($data);
240
        $this->currentLineLength += $dataSize;
241
    }
242
}
243