Completed
Push — develop ( 467115...a39d71 )
by Adrien
17:43
created

BIFFwriter::writeData()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 9
Ratio 100 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 9
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer\Xls;
4
5
/**
6
 * Copyright (c) 2006 - 2015 PhpSpreadsheet.
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
 *
22
 * @category   PhpSpreadsheet
23
 *
24
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
25
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
26
 */
27
28
// Original file header of PEAR::Spreadsheet_Excel_Writer_BIFFwriter (used as the base for this class):
29
// -----------------------------------------------------------------------------------------
30
// *  Module written/ported by Xavier Noguer <[email protected]>
31
// *
32
// *  The majority of this is _NOT_ my code.  I simply ported it from the
33
// *  PERL Spreadsheet::WriteExcel module.
34
// *
35
// *  The author of the Spreadsheet::WriteExcel module is John McNamara
36
// *  <[email protected]>
37
// *
38
// *  I _DO_ maintain this code, and John McNamara has nothing to do with the
39
// *  porting of this code to PHP.  Any questions directly related to this
40
// *  class library should be directed to me.
41
// *
42
// *  License Information:
43
// *
44
// *    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
45
// *    Copyright (c) 2002-2003 Xavier Noguer [email protected]
46
// *
47
// *    This library is free software; you can redistribute it and/or
48
// *    modify it under the terms of the GNU Lesser General Public
49
// *    License as published by the Free Software Foundation; either
50
// *    version 2.1 of the License, or (at your option) any later version.
51
// *
52
// *    This library is distributed in the hope that it will be useful,
53
// *    but WITHOUT ANY WARRANTY; without even the implied warranty of
54
// *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
55
// *    Lesser General Public License for more details.
56
// *
57
// *    You should have received a copy of the GNU Lesser General Public
58
// *    License along with this library; if not, write to the Free Software
59
// *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
60
// */
61
class BIFFwriter
62
{
63
    /**
64
     * The byte order of this architecture. 0 => little endian, 1 => big endian.
65
     *
66
     * @var int
67
     */
68
    private static $byteOrder;
69
70
    /**
71
     * The string containing the data of the BIFF stream.
72
     *
73
     * @var string
74
     */
75
    public $_data;
76
77
    /**
78
     * The size of the data in bytes. Should be the same as strlen($this->_data).
79
     *
80
     * @var int
81
     */
82
    public $_datasize;
83
84
    /**
85
     * The maximum length for a BIFF record (excluding record header and length field). See addContinue().
86
     *
87
     * @var int
88
     *
89
     * @see addContinue()
90
     */
91
    private $limit = 8224;
92
93
    /**
94
     * Constructor.
95
     */
96 38
    public function __construct()
97
    {
98 38
        $this->_data = '';
99 38
        $this->_datasize = 0;
100 38
    }
101
102
    /**
103
     * Determine the byte order and store it as class data to avoid
104
     * recalculating it for each call to new().
105
     *
106
     * @return int
107
     */
108 38
    public static function getByteOrder()
109
    {
110 38
        if (!isset(self::$byteOrder)) {
111
            // Check if "pack" gives the required IEEE 64bit float
112 38
            $teststr = pack('d', 1.2345);
113 38
            $number = pack('C8', 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F);
114 38
            if ($number == $teststr) {
115 38
                $byte_order = 0; // Little Endian
116
            } elseif ($number == strrev($teststr)) {
117
                $byte_order = 1; // Big Endian
118
            } else {
119
                // Give up. I'll fix this in a later version.
120
                throw new \PhpOffice\PhpSpreadsheet\Writer\Exception('Required floating point format not supported on this platform.');
121
            }
122 38
            self::$byteOrder = $byte_order;
123
        }
124
125 38
        return self::$byteOrder;
126
    }
127
128
    /**
129
     * General storage function.
130
     *
131
     * @param string $data binary data to append
132
     */
133 38 View Code Duplication
    protected function append($data)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
134
    {
135 38
        if (strlen($data) - 4 > $this->limit) {
136
            $data = $this->addContinue($data);
137
        }
138 38
        $this->_data .= $data;
139 38
        $this->_datasize += strlen($data);
140 38
    }
141
142
    /**
143
     * General storage function like append, but returns string instead of modifying $this->_data.
144
     *
145
     * @param string $data binary data to write
146
     *
147
     * @return string
148
     */
149 38 View Code Duplication
    public function writeData($data)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
150
    {
151 38
        if (strlen($data) - 4 > $this->limit) {
152 7
            $data = $this->addContinue($data);
153
        }
154 38
        $this->_datasize += strlen($data);
155
156 38
        return $data;
157
    }
158
159
    /**
160
     * Writes Excel BOF record to indicate the beginning of a stream or
161
     * sub-stream in the BIFF file.
162
     *
163
     * @param  int $type type of BIFF file to write: 0x0005 Workbook,
164
     *                       0x0010 Worksheet
165
     */
166 38
    protected function storeBof($type)
167
    {
168 38
        $record = 0x0809; // Record identifier    (BIFF5-BIFF8)
169 38
        $length = 0x0010;
170
171
        // by inspection of real files, MS Office Excel 2007 writes the following
172 38
        $unknown = pack('VV', 0x000100D1, 0x00000406);
173
174 38
        $build = 0x0DBB; //    Excel 97
175 38
        $year = 0x07CC; //    Excel 97
176
177 38
        $version = 0x0600; //    BIFF8
178
179 38
        $header = pack('vv', $record, $length);
180 38
        $data = pack('vvvv', $version, $type, $build, $year);
181 38
        $this->append($header . $data . $unknown);
182 38
    }
183
184
    /**
185
     * Writes Excel EOF record to indicate the end of a BIFF stream.
186
     */
187 38 View Code Duplication
    protected function storeEof()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
188
    {
189 38
        $record = 0x000A; // Record identifier
190 38
        $length = 0x0000; // Number of bytes to follow
191
192 38
        $header = pack('vv', $record, $length);
193 38
        $this->append($header);
194 38
    }
195
196
    /**
197
     * Writes Excel EOF record to indicate the end of a BIFF stream.
198
     */
199 38 View Code Duplication
    public function writeEof()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
200
    {
201 38
        $record = 0x000A; // Record identifier
202 38
        $length = 0x0000; // Number of bytes to follow
203 38
        $header = pack('vv', $record, $length);
204
205 38
        return $this->writeData($header);
206
    }
207
208
    /**
209
     * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
210
     * Excel 97 the limit is 8228 bytes. Records that are longer than these limits
211
     * must be split up into CONTINUE blocks.
212
     *
213
     * This function takes a long BIFF record and inserts CONTINUE records as
214
     * necessary.
215
     *
216
     * @param  string  $data The original binary data to be written
217
     *
218
     * @return string        A very convenient string of continue blocks
219
     */
220 7
    private function addContinue($data)
221
    {
222 7
        $limit = $this->limit;
223 7
        $record = 0x003C; // Record identifier
224
225
        // The first 2080/8224 bytes remain intact. However, we have to change
226
        // the length field of the record.
227 7
        $tmp = substr($data, 0, 2) . pack('v', $limit) . substr($data, 4, $limit);
228
229 7
        $header = pack('vv', $record, $limit); // Headers for continue records
230
231
        // Retrieve chunks of 2080/8224 bytes +4 for the header.
232 7
        $data_length = strlen($data);
233 7
        for ($i = $limit + 4; $i < ($data_length - $limit); $i += $limit) {
234 1
            $tmp .= $header;
235 1
            $tmp .= substr($data, $i, $limit);
236
        }
237
238
        // Retrieve the last chunk of data
239 7
        $header = pack('vv', $record, strlen($data) - $i);
240 7
        $tmp .= $header;
241 7
        $tmp .= substr($data, $i, strlen($data) - $i);
242
243 7
        return $tmp;
244
    }
245
}
246