Passed
Push — master ( 990947...a164fb )
by Maurício
02:00
created

ShapeFile::openDBFFile()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 9.488

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 4
nop 0
dl 0
loc 22
ccs 3
cts 10
cp 0.3
crap 9.488
rs 9.8333
c 0
b 0
f 0
1
<?php
2
/**
3
 * phpMyAdmin ShapeFile library
4
 * <https://github.com/phpmyadmin/shapefile/>.
5
 *
6
 * Copyright 2006-2007 Ovidio <ovidio AT users.sourceforge.net>
7
 * Copyright 2016 - 2017 Michal Čihař <[email protected]>
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation.
12
 *
13
 * This program 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
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, you can download one from
20
 * https://www.gnu.org/copyleft/gpl.html.
21
 */
22
declare(strict_types=1);
23
24
namespace PhpMyAdmin\ShapeFile;
25
26
/**
27
 * ShapeFile class.
28
 */
29
class ShapeFile
30
{
31
    const MAGIC = 0x270a;
32
33
    public $FileName;
34
35
    private $SHPFile = null;
36
    private $SHXFile = null;
37
    private $DBFFile = null;
38
39
    private $DBFHeader;
40
41
    public $lastError = '';
42
43
    public $boundingBox = [
44
        'xmin' => 0.0,
45
        'ymin' => 0.0,
46
        'xmax' => 0.0,
47
        'ymax' => 0.0,
48
    ];
49
    private $fileLength = 0;
50
    public $shapeType = 0;
51
52
    public $records = [];
53 21
54
    /**
55 21
     * Checks whether dbase manipuations are supported.
56
     *
57
     * @return bool
58
     */
59
    public static function supportsDbase()
60
    {
61
        return extension_loaded('dbase');
62
    }
63 24
64
    /**
65 24
     * @param int        $shapeType   File shape type, should be same as all records
66 24
     * @param array      $boundingBox File bounding box
67 24
     * @param null|mixed $FileName    File name
68 24
     */
69 24
    public function __construct(
70
        $shapeType,
71
        $boundingBox = [
72
            'xmin' => 0.0,
73
            'ymin' => 0.0,
74
            'xmax' => 0.0,
75
            'ymax' => 0.0,
76 22
        ],
77
        $FileName = null
78 22
    ) {
79 22
        $this->shapeType = $shapeType;
80 22
        $this->boundingBox = $boundingBox;
81 22
        $this->FileName = $FileName;
82
        $this->fileLength = 50; // The value for file length is the total length of the file in 16-bit words (including the fifty 16-bit words that make up the header).
83
    }
84
85
    /**
86 22
     * Loads shapefile and dbase (if supported).
87 20
     *
88 1
     * @param string $FileName File mask to load (eg. example.*)
89 1
     */
90
    public function loadFromFile($FileName)
91 1
    {
92
        if (! empty($FileName)) {
93 19
            $this->FileName = $FileName;
94
            $result = $this->openSHPFile();
95
        } else {
96
            /* We operate on buffer emulated by readSHP / eofSHP */
97
            $result = true;
98
        }
99 19
100 19
        if ($result && ($this->openDBFFile())) {
101
            if (! $this->loadHeaders()) {
102 19
                $this->closeSHPFile();
103
                $this->closeDBFFile();
104
105 2
                return false;
106
            }
107
            if (! $this->loadRecords()) {
108
                $this->closeSHPFile();
109
                $this->closeDBFFile();
110
111
                return false;
112
            }
113 13
            $this->closeSHPFile();
114
            $this->closeDBFFile();
115 13
116 13
            return true;
117 13
        }
118
119 13
        return false;
120 13
    }
121 13
122 13
    /**
123 13
     * Saves shapefile.
124 13
     *
125 13
     * @param string|null $FileName Name of file, otherwise existing is used
126
     */
127
    public function saveToFile($FileName = null)
128 13
    {
129
        if (! is_null($FileName)) {
130
            $this->FileName = $FileName;
131
        }
132
133
        if (($this->openSHPFile(true)) && ($this->openSHXFile(true)) && ($this->createDBFFile())) {
134
            $this->saveHeaders();
135
            $this->saveRecords();
136
            $this->closeSHPFile();
137 23
            $this->closeSHXFile();
138
            $this->closeDBFFile();
139 23
        } else {
140
            return false;
141
        }
142
    }
143
144
    /**
145
     * Generates filename with given extension.
146
     *
147
     * @param string $extension Extension to use (including dot)
148 12
     *
149
     * @return string
150 12
     */
151 12
    private function getFilename($extension)
152
    {
153 12
        return str_replace('.*', $extension, $this->FileName);
154 12
    }
155 12
156 12
    /**
157 12
     * Updates bounding box based on SHPData.
158 12
     *
159 12
     * @param string $type Type of box
160
     * @param array  $data ShapeRecord SHPData
161
     */
162
    private function updateBBox($type, $data)
163
    {
164
        $min = $type . 'min';
165
        $max = $type . 'max';
166
167
        if (! isset($this->boundingBox[$min]) || $this->boundingBox[$min] == 0.0 || ($this->boundingBox[$min] > $data[$min])) {
168 12
            $this->boundingBox[$min] = $data[$min];
169
        }
170 12
        if (! isset($this->boundingBox[$max]) || $this->boundingBox[$max] == 0.0 || ($this->boundingBox[$max] < $data[$max])) {
171 12
            $this->boundingBox[$max] = $data[$max];
172 12
        }
173
    }
174 12
175 12
    /**
176 12
     * Adds record to shape file.
177
     *
178 12
     * @param ShapeRecord $record
179 12
     *
180
     * @return int Number of added record
181 12
     */
182 8
    public function addRecord($record)
183 8
    {
184
        if ((isset($this->DBFHeader)) && (is_array($this->DBFHeader))) {
185 12
            $record->updateDBFInfo($this->DBFHeader);
186 4
        }
187 4
188
        $this->fileLength += ($record->getContentLength() + 4);
189 12
        $this->records[] = $record;
190
        $this->records[count($this->records) - 1]->recordNumber = count($this->records);
191
192
        $this->updateBBox('x', $record->SHPData);
193
        $this->updateBBox('y', $record->SHPData);
194
195
        if (in_array($this->shapeType, [11, 13, 15, 18, 21, 23, 25, 28])) {
196
            $this->updateBBox('m', $record->SHPData);
197
        }
198
199
        if (in_array($this->shapeType, [11, 13, 15, 18])) {
200
            $this->updateBBox('z', $record->SHPData);
201
        }
202
203
        return count($this->records) - 1;
204
    }
205
206
    /**
207
     * Deletes record from shapefile.
208
     *
209
     * @param int $index
210
     */
211
    public function deleteRecord($index)
212
    {
213
        if (isset($this->records[$index])) {
214
            $this->fileLength -= ($this->records[$index]->getContentLength() + 4);
215
            $count = count($this->records) - 1;
216
            for ($i = $index; $i < $count; ++$i) {
217
                $this->records[$i] = $this->records[$i + 1];
218
            }
219
            unset($this->records[count($this->records) - 1]);
220
            $this->deleteRecordFromDBF($index);
221
        }
222
    }
223
224
    /**
225
     * Returns array defining fields in DBF file.
226
     *
227
     * @return array see setDBFHeader for more information
228
     */
229 12
    public function getDBFHeader()
230
    {
231 12
        return $this->DBFHeader;
232
    }
233 12
234 12
    /**
235
     * Changes array defining fields in DBF file, used in dbase_create call.
236
     *
237 12
     * @param array $header An array of arrays, each array describing the
238
     *                      format of one field of the database. Each
239
     *                      field consists of a name, a character indicating
240
     *                      the field type, and optionally, a length,
241
     *                      a precision and a nullable flag.
242
     */
243
    public function setDBFHeader($header)
244
    {
245
        $this->DBFHeader = $header;
246
247 1
        $count = count($this->records);
248
        for ($i = 0; $i < $count; ++$i) {
249 1
            $this->records[$i]->updateDBFInfo($header);
250 1
        }
251
    }
252 1
253
    /**
254
     * Lookups value in the DBF file and returs index.
255 1
     *
256
     * @param string $field Field to match
257 1
     * @param mixed  $value Value to match
258
     *
259
     * @return int
260
     */
261
    public function getIndexFromDBFData($field, $value)
262
    {
263
        foreach ($this->records as $index => $record) {
264
            if (isset($record->DBFData[$field]) &&
265
                (trim(strtoupper($record->DBFData[$field])) == strtoupper($value))
266
            ) {
267
                return $index;
268
            }
269
        }
270
271
        return -1;
272
    }
273
274
    /**
275
     * Loads DBF metadata.
276
     */
277
    private function loadDBFHeader()
278
    {
279
        $DBFFile = fopen($this->getFilename('.dbf'), 'r');
280
281
        $result = [];
282
        $i = 1;
283
        $inHeader = true;
284
285
        while ($inHeader) {
286
            if (! feof($DBFFile)) {
0 ignored issues
show
Bug introduced by
It seems like $DBFFile can also be of type false; however, parameter $handle of feof() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

286
            if (! feof(/** @scrutinizer ignore-type */ $DBFFile)) {
Loading history...
287
                $buff32 = fread($DBFFile, 32);
0 ignored issues
show
Bug introduced by
It seems like $DBFFile can also be of type false; however, parameter $handle of fread() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

287
                $buff32 = fread(/** @scrutinizer ignore-type */ $DBFFile, 32);
Loading history...
288
                if ($i > 1) {
289
                    if (substr($buff32, 0, 1) == chr(13)) {
290
                        $inHeader = false;
291
                    } else {
292
                        $pos = strpos(substr($buff32, 0, 10), chr(0));
293
                        $pos = ($pos == 0 ? 10 : $pos);
294
295
                        $fieldName = substr($buff32, 0, $pos);
296
                        $fieldType = substr($buff32, 11, 1);
297
                        $fieldLen = ord(substr($buff32, 16, 1));
298
                        $fieldDec = ord(substr($buff32, 17, 1));
299
300
                        array_push($result, [$fieldName, $fieldType, $fieldLen, $fieldDec]);
301
                    }
302
                }
303
                ++$i;
304
            } else {
305
                $inHeader = false;
306
            }
307
        }
308
309
        fclose($DBFFile);
0 ignored issues
show
Bug introduced by
It seems like $DBFFile can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

309
        fclose(/** @scrutinizer ignore-type */ $DBFFile);
Loading history...
310
311
        return $result;
312
    }
313
314
    /**
315
     * Deletes record from the DBF file.
316
     *
317 20
     * @param int $index
318
     */
319 20
    private function deleteRecordFromDBF($index)
320 1
    {
321
        if ($this->DBFFile !== null && @dbase_delete_record($this->DBFFile, $index)) {
0 ignored issues
show
Bug introduced by
The function dbase_delete_record was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

321
        if ($this->DBFFile !== null && @/** @scrutinizer ignore-call */ dbase_delete_record($this->DBFFile, $index)) {
Loading history...
322 1
            dbase_pack($this->DBFFile);
0 ignored issues
show
Bug introduced by
The function dbase_pack was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

322
            /** @scrutinizer ignore-call */ 
323
            dbase_pack($this->DBFFile);
Loading history...
323
        }
324
    }
325
326 19
    /**
327
     * Loads SHP file metadata.
328 19
     *
329
     * @return bool
330
     */
331 19
    private function loadHeaders()
332
    {
333 19
        if (Util::loadData('N', $this->readSHP(4)) != self::MAGIC) {
334
            $this->setError('Not a SHP file (file code mismatch)');
335 19
336 19
            return false;
337 19
        }
338 19
339 19
        /* Skip 20 unused bytes */
340 19
        $this->readSHP(20);
341 19
342 19
        $this->fileLength = Util::loadData('N', $this->readSHP(4));
343 19
344
        /* We currently ignore version */
345 19
        $this->readSHP(4);
346
347
        $this->shapeType = Util::loadData('V', $this->readSHP(4));
348
349 19
        $this->boundingBox = [];
350
        $this->boundingBox['xmin'] = Util::loadData('d', $this->readSHP(8));
351
        $this->boundingBox['ymin'] = Util::loadData('d', $this->readSHP(8));
352
        $this->boundingBox['xmax'] = Util::loadData('d', $this->readSHP(8));
353
        $this->boundingBox['ymax'] = Util::loadData('d', $this->readSHP(8));
354
        $this->boundingBox['zmin'] = Util::loadData('d', $this->readSHP(8));
355
        $this->boundingBox['zmax'] = Util::loadData('d', $this->readSHP(8));
356
        $this->boundingBox['mmin'] = Util::loadData('d', $this->readSHP(8));
357
        $this->boundingBox['mmax'] = Util::loadData('d', $this->readSHP(8));
358 13
359
        if (self::supportsDbase()) {
360 13
            $this->DBFHeader = $this->loadDBFHeader();
361 13
        }
362 13
363 13
        return true;
364
    }
365
366
    /**
367
     * Saves bounding box record, possibly using 0 instead of not set values.
368
     *
369
     * @param file   $file File object
0 ignored issues
show
Bug introduced by
The type PhpMyAdmin\ShapeFile\file was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
370 13
     * @param string $type Bounding box dimension (eg. xmax, mmin...)
371
     */
372 13
    private function saveBBoxRecord($file, $type)
373 13
    {
374 13
        fwrite($file, Util::packDouble(
0 ignored issues
show
Bug introduced by
$file of type PhpMyAdmin\ShapeFile\file is incompatible with the type resource expected by parameter $handle of fwrite(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

374
        fwrite(/** @scrutinizer ignore-type */ $file, Util::packDouble(
Loading history...
375 13
            isset($this->boundingBox[$type]) ? $this->boundingBox[$type] : 0
376 13
        ));
377 13
    }
378 13
379 13
    /**
380 13
     * Saves bounding box to a file.
381
     *
382
     * @param file $file File object
383
     */
384
    private function saveBBox($file)
385 13
    {
386
        $this->saveBBoxRecord($file, 'xmin');
387 13
        $this->saveBBoxRecord($file, 'ymin');
388 13
        $this->saveBBoxRecord($file, 'xmax');
389 13
        $this->saveBBoxRecord($file, 'ymax');
390 13
        $this->saveBBoxRecord($file, 'zmin');
391 13
        $this->saveBBoxRecord($file, 'zmax');
392
        $this->saveBBoxRecord($file, 'mmin');
393 13
        $this->saveBBoxRecord($file, 'mmax');
394 13
    }
395 13
396 13
    /**
397 13
     * Saves SHP and SHX file metadata.
398 13
     */
399
    private function saveHeaders()
400
    {
401
        fwrite($this->SHPFile, pack('NNNNNN', self::MAGIC, 0, 0, 0, 0, 0));
402
        fwrite($this->SHPFile, pack('N', $this->fileLength));
403
        fwrite($this->SHPFile, pack('V', 1000));
404
        fwrite($this->SHPFile, pack('V', $this->shapeType));
405 19
        $this->saveBBox($this->SHPFile);
406
407
        fwrite($this->SHXFile, pack('NNNNNN', self::MAGIC, 0, 0, 0, 0, 0));
408 19
        fwrite($this->SHXFile, pack('N', 50 + 4 * count($this->records)));
409 19
        fwrite($this->SHXFile, pack('V', 1000));
410 19
        fwrite($this->SHXFile, pack('V', $this->shapeType));
411 19
        $this->saveBBox($this->SHXFile);
412
    }
413
414
    /**
415
     * Loads records from SHP file (and DBF).
416 19
     *
417 19
     * @return bool
418
     */
419
    private function loadRecords()
420 19
    {
421 19
        /* Need to start at offset 100 */
422
        while (! $this->eofSHP()) {
423 19
            $record = new ShapeRecord(-1);
424
            $record->loadFromFile($this, $this->SHPFile, $this->DBFFile);
425
            if ($record->lastError != '') {
426
                $this->setError($record->lastError);
427
428
                return false;
429 13
            }
430
            if (($record->shapeType === false || $record->shapeType === '') && $this->eofSHP()) {
431 13
                break;
432 13
            }
433 12
434
            $this->records[] = $record;
435 12
        }
436
437
        return true;
438 12
    }
439 12
440 12
    /**
441 12
     * Saves records to SHP and SHX files.
442 12
     */
443 13
    private function saveRecords()
444
    {
445
        $offset = 50;
446
        if (is_array($this->records) && (count($this->records) > 0)) {
447
            foreach ($this->records as $index => $record) {
448
                //Save the record to the .shp file
449
                $record->saveToFile($this->SHPFile, $this->DBFFile, $index + 1);
450
451
                //Save the record to the .shx file
452
                fwrite($this->SHXFile, pack('N', $offset));
453
                fwrite($this->SHXFile, pack('N', $record->getContentLength()));
454 23
                $offset += (4 + $record->getContentLength());
455
            }
456 23
        }
457 23
    }
458 23
459 2
    /**
460
     * Generic interface to open files.
461 2
     *
462
     * @param bool   $toWrite   Whether file should be opened for writing
463
     * @param string $extension File extension
464 21
     * @param string $name      Verbose file name to report errors
465
     *
466
     * @return file|false File handle
467
     */
468
    private function openFile($toWrite, $extension, $name)
469
    {
470
        $shp_name = $this->getFilename($extension);
471
        $result = @fopen($shp_name, ($toWrite ? 'wb+' : 'rb'));
472
        if (! $result) {
0 ignored issues
show
introduced by
$result is of type false|resource, thus it always evaluated to false.
Loading history...
473
            $this->setError(sprintf('It wasn\'t possible to open the %s file "%s"', $name, $shp_name));
474 23
475
            return false;
476 23
        }
477 23
478 2
        return $result;
479
    }
480
481 21
    /**
482
     * Opens SHP file.
483
     *
484
     * @param bool $toWrite Whether file should be opened for writing
485
     *
486
     * @return bool
487 21
     */
488
    private function openSHPFile($toWrite = false)
489 21
    {
490 21
        $this->SHPFile = $this->openFile($toWrite, '.shp', 'Shape');
491 21
        if (! $this->SHPFile) {
492 21
            return false;
493 21
        }
494
495
        return true;
496
    }
497
498
    /**
499
     * Closes SHP file.
500
     */
501
    private function closeSHPFile()
502 13
    {
503
        if ($this->SHPFile) {
504 13
            fclose($this->SHPFile);
505 13
            $this->SHPFile = null;
506
        }
507
    }
508
509 13
    /**
510
     * Opens SHX file.
511
     *
512
     * @param bool $toWrite Whether file should be opened for writing
513
     *
514
     * @return bool
515 13
     */
516
    private function openSHXFile($toWrite = false)
517 13
    {
518 13
        $this->SHXFile = $this->openFile($toWrite, '.shx', 'Index');
519 13
        if (! $this->SHXFile) {
520 13
            return false;
521 13
        }
522
523
        return true;
524
    }
525
526
    /**
527
     * Closes SHX file.
528 13
     */
529
    private function closeSHXFile()
530 13
    {
531 13
        if ($this->SHXFile) {
532
            fclose($this->SHXFile);
533 13
            $this->SHXFile = null;
534
        }
535
    }
536
537
    /**
538
     * Creates DBF file.
539
     *
540
     * @return bool
541
     */
542
    private function createDBFFile()
543
    {
544
        if (! self::supportsDbase() || ! is_array($this->DBFHeader) || count($this->DBFHeader) == 0) {
545
            $this->DBFFile = null;
546
547
            return true;
548
        }
549
        $dbf_name = $this->getFilename('.dbf');
550
551
        /* Unlink existing file */
552
        if (file_exists($dbf_name)) {
553
            unlink($dbf_name);
554
        }
555
556
        /* Create new file */
557
        $this->DBFFile = @dbase_create($dbf_name, $this->DBFHeader);
0 ignored issues
show
Bug introduced by
The function dbase_create was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

557
        $this->DBFFile = @/** @scrutinizer ignore-call */ dbase_create($dbf_name, $this->DBFHeader);
Loading history...
558 20
        if ($this->DBFFile === false) {
559
            $this->setError(sprintf('It wasn\'t possible to create the DBase file "%s"', $dbf_name));
560 20
561 20
            return false;
562
        }
563 20
564
        return true;
565
    }
566
567
    /**
568
     * Loads DBF file if supported.
569
     *
570
     * @return bool
571
     */
572
    private function openDBFFile()
573
    {
574
        if (! self::supportsDbase()) {
575
            $this->DBFFile = null;
576
577
            return true;
578
        }
579
        $dbf_name = $this->getFilename('.dbf');
580
        if (is_readable($dbf_name)) {
581
            $this->DBFFile = @dbase_open($dbf_name, 0);
0 ignored issues
show
Bug introduced by
The function dbase_open was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

581
            $this->DBFFile = @/** @scrutinizer ignore-call */ dbase_open($dbf_name, 0);
Loading history...
582
            if (! $this->DBFFile) {
583
                $this->setError(sprintf('It wasn\'t possible to open the DBase file "%s"', $dbf_name));
584
585 21
                return false;
586
            }
587 21
        } else {
588
            $this->setError(sprintf('It wasn\'t possible to find the DBase file "%s"', $dbf_name));
589
590
            return false;
591 21
        }
592
593
        return true;
594
    }
595
596
    /**
597
     * Closes DBF file.
598 3
     */
599
    private function closeDBFFile()
600 3
    {
601 3
        if ($this->DBFFile) {
602
            dbase_close($this->DBFFile);
0 ignored issues
show
Bug introduced by
The function dbase_close was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

602
            /** @scrutinizer ignore-call */ 
603
            dbase_close($this->DBFFile);
Loading history...
603
            $this->DBFFile = null;
604
        }
605
    }
606
607
    /**
608
     * Sets error message.
609
     *
610 20
     * @param string $error
611
     */
612 20
    public function setError($error)
613
    {
614
        $this->lastError = $error;
615
    }
616
617
    /**
618
     * Reads given number of bytes from SHP file.
619
     *
620 19
     * @param int $bytes
621
     *
622 19
     * @return string
623
     */
624
    public function readSHP($bytes)
625
    {
626
        return fread($this->SHPFile, $bytes);
627
    }
628
629
    /**
630 1
     * Checks whether file is at EOF.
631
     *
632 1
     * @return bool
633
     */
634
    public function eofSHP()
635
    {
636
        return feof($this->SHPFile);
637
    }
638
639
    /**
640
     * Returns shape name.
641
     *
642
     * @return string
643 8
     */
644
    public function getShapeName()
645 8
    {
646
        return Util::nameShape($this->shapeType);
647
    }
648
649
    /**
650
     * Check whether file contains measure data.
651
     *
652
     * For some reason this is distinguished by zero bounding box in the
653
     * specification.
654
     *
655
     * @return bool
656
     */
657
    public function hasMeasure()
658
    {
659
        return $this->boundingBox['mmin'] != 0 || $this->boundingBox['mmax'] != 0;
660
    }
661
}
662