ShapeRecord   F
last analyzed

Complexity

Total Complexity 148

Size/Duplication

Total Lines 789
Duplicated Lines 0 %

Test Coverage

Coverage 93%

Importance

Changes 13
Bugs 0 Features 0
Metric Value
eloc 354
dl 0
loc 789
ccs 372
cts 400
cp 0.93
rs 2
c 13
b 0
f 0
wmc 148

53 Methods

Rating   Name   Duplication   Size   Complexity  
A loadHeaders() 0 24 4
A savePolygonRecord() 0 3 1
A savePointRecord() 0 3 1
A loadPolyLineMZRecord() 0 20 6
A loadPolygonRecord() 0 3 1
B adjustBBox() 0 19 7
A setError() 0 3 1
A savePolyLineZRecord() 0 6 1
A savePolygonZRecord() 0 3 1
A savePolyLineRecord() 0 21 4
A loadPoint() 0 5 1
A loadPointZRecord() 0 3 1
D deletePoint() 0 65 21
A savePoint() 0 4 1
A loadData() 0 10 2
A loadNullRecord() 0 3 1
A loadPolygonZRecord() 0 3 1
A saveMultiPointRecord() 0 14 2
A savePolyLineMRecord() 0 5 1
A reportInvalidShapeTypeError() 0 3 1
A saveHeaders() 0 5 1
A loadPolygonMRecord() 0 3 1
A savePointZ() 0 6 1
B loadPolyLineRecord() 0 29 7
A adjustPoint() 0 11 3
A getShapeName() 0 3 1
A savePointZRecord() 0 3 1
A loadPolyLineMRecord() 0 5 1
A saveMultiPointZRecord() 0 6 1
A savePolygonMRecord() 0 3 1
A loadPointM() 0 7 1
A savePolyLineMZRecord() 0 7 3
B loadFromFile() 0 42 6
A saveMultiPointMRecord() 0 5 1
A loadMultiPointRecord() 0 9 2
A loadPointRecord() 0 3 1
A __construct() 0 2 1
A loadMultiPointMZRecord() 0 12 4
A savePointM() 0 5 1
C getContentLength() 0 60 17
A loadPointMRecord() 0 3 1
A loadMultiPointZRecord() 0 6 1
A saveDBFData() 0 13 5
A loadPolyLineZRecord() 0 6 1
A saveToFile() 0 28 3
A updateDBFInfo() 0 6 2
A saveMultiPointMZRecord() 0 6 2
A loadMultiPointMRecord() 0 5 1
C addPoint() 0 39 14
A loadPointZ() 0 8 1
A loadBBox() 0 6 1
A loadDBFData() 0 4 1
A savePointMRecord() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like ShapeRecord often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ShapeRecord, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * phpMyAdmin ShapeFile library
7
 * <https://github.com/phpmyadmin/shapefile/>.
8
 *
9
 * Copyright 2006-2007 Ovidio <ovidio AT users.sourceforge.net>
10
 * Copyright 2016 - 2017 Michal Čihař <[email protected]>
11
 *
12
 * This program is free software; you can redistribute it and/or
13
 * modify it under the terms of the GNU General Public License
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program; if not, you can download one from
23
 * https://www.gnu.org/copyleft/gpl.html.
24
 */
25
26
namespace PhpMyAdmin\ShapeFile;
27
28
use function array_values;
29
use function count;
30
use function dbase_add_record;
0 ignored issues
show
introduced by
The function dbase_add_record was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
31
use function dbase_get_record_with_names;
0 ignored issues
show
introduced by
The function dbase_get_record_with_names was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
32
use function dbase_numrecords;
0 ignored issues
show
introduced by
The function dbase_numrecords was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
33
use function dbase_replace_record;
0 ignored issues
show
introduced by
The function dbase_replace_record was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
34
use function fwrite;
35
use function in_array;
36
use function is_array;
37
use function pack;
38
use function strlen;
39
40
/**
41
 * ShapeFile record class.
42
 */
43
class ShapeRecord
44
{
45
    /** @var resource */
46
    private $shpFile;
47
48
    private ShapeFile|null $shapeFile = null;
49
50
    private int $size = 0;
51
52
    private int $read = 0;
53
54
    public int $recordNumber = 0;
55
56
    public string $lastError = '';
57
58
    /** @var mixed[] */
59
    public array $shpData = [];
60
61
    /** @var mixed[] */
62
    public array $dbfData = [];
63
64 92
    public function __construct(public ShapeType $shapeType)
65
    {
66 92
    }
67
68
    /**
69
     * Loads record from files.
70
     *
71
     * @param ShapeFile      $shapeFile The ShapeFile object
72
     * @param resource|false $dbfFile   Opened DBF file
73
     */
74 88
    public function loadFromFile(ShapeFile $shapeFile, $dbfFile): void
75
    {
76 88
        $this->shapeFile = $shapeFile;
77 88
        $this->loadHeaders();
78
79
        /* No header read */
80 88
        if ($this->read === 0) {
81 88
            return;
82
        }
83
84 88
        match ($this->shapeType) {
85 88
            ShapeType::Null => $this->loadNullRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadNullRecord() targeting PhpMyAdmin\ShapeFile\ShapeRecord::loadNullRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
86 88
            ShapeType::Point => $this->loadPointRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadPointRecord() targeting PhpMyAdmin\ShapeFile\Sha...cord::loadPointRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
87 72
            ShapeType::PointM => $this->loadPointMRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadPointMRecord() targeting PhpMyAdmin\ShapeFile\Sha...ord::loadPointMRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
88 68
            ShapeType::PointZ => $this->loadPointZRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadPointZRecord() targeting PhpMyAdmin\ShapeFile\Sha...ord::loadPointZRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
89 64
            ShapeType::PolyLine => $this->loadPolyLineRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadPolyLineRecord() targeting PhpMyAdmin\ShapeFile\Sha...d::loadPolyLineRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
90 51
            ShapeType::PolyLineM => $this->loadPolyLineMRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadPolyLineMRecord() targeting PhpMyAdmin\ShapeFile\Sha...::loadPolyLineMRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
91 47
            ShapeType::PolyLineZ => $this->loadPolyLineZRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadPolyLineZRecord() targeting PhpMyAdmin\ShapeFile\Sha...::loadPolyLineZRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
92 43
            ShapeType::Polygon => $this->loadPolygonRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadPolygonRecord() targeting PhpMyAdmin\ShapeFile\Sha...rd::loadPolygonRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
93 28
            ShapeType::PolygonM => $this->loadPolygonMRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadPolygonMRecord() targeting PhpMyAdmin\ShapeFile\Sha...d::loadPolygonMRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
94 24
            ShapeType::PolygonZ => $this->loadPolygonZRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadPolygonZRecord() targeting PhpMyAdmin\ShapeFile\Sha...d::loadPolygonZRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
95 16
            ShapeType::MultiPoint => $this->loadMultiPointRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadMultiPointRecord() targeting PhpMyAdmin\ShapeFile\Sha...:loadMultiPointRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
96 12
            ShapeType::MultiPointM => $this->loadMultiPointMRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadMultiPointMRecord() targeting PhpMyAdmin\ShapeFile\Sha...loadMultiPointMRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
97 8
            ShapeType::MultiPointZ => $this->loadMultiPointZRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->loadMultiPointZRecord() targeting PhpMyAdmin\ShapeFile\Sha...loadMultiPointZRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
98
            default => $this->reportInvalidShapeTypeError(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->reportInvalidShapeTypeError() targeting PhpMyAdmin\ShapeFile\Sha...InvalidShapeTypeError() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
99 88
        };
100
101
        /* We need to skip rest of the record */
102 88
        while ($this->read < $this->size) {
103 24
            $this->loadData('V', 4);
104
        }
105
106
        /* Check if we didn't read too much */
107 88
        if ($this->read !== $this->size) {
108
            $this->reportInvalidShapeTypeError();
109
        }
110
111 88
        if (! ShapeFile::supportsDbase() || $dbfFile === false) {
112 22
            return;
113
        }
114
115 66
        $this->loadDBFData($dbfFile);
116
    }
117
118
    /**
119
     * Saves record to files.
120
     *
121
     * @param resource       $shpFile      Opened SHP file
122
     * @param resource|false $dbfFile      Opened DBF file
123
     * @param int            $recordNumber Record number
124
     */
125 57
    public function saveToFile($shpFile, $dbfFile, int $recordNumber): void
126
    {
127 57
        $this->shpFile = $shpFile;
128 57
        $this->recordNumber = $recordNumber;
129 57
        $this->saveHeaders();
130
131 57
        match ($this->shapeType) {
132 57
            ShapeType::Null => null, // Nothing to save
133 57
            ShapeType::Point => $this->savePointRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->savePointRecord() targeting PhpMyAdmin\ShapeFile\Sha...cord::savePointRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
134 53
            ShapeType::PointM => $this->savePointMRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->savePointMRecord() targeting PhpMyAdmin\ShapeFile\Sha...ord::savePointMRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
135 49
            ShapeType::PointZ => $this->savePointZRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->savePointZRecord() targeting PhpMyAdmin\ShapeFile\Sha...ord::savePointZRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
136 45
            ShapeType::PolyLine => $this->savePolyLineRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->savePolyLineRecord() targeting PhpMyAdmin\ShapeFile\Sha...d::savePolyLineRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
137 32
            ShapeType::PolyLineM => $this->savePolyLineMRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->savePolyLineMRecord() targeting PhpMyAdmin\ShapeFile\Sha...::savePolyLineMRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
138 28
            ShapeType::PolyLineZ => $this->savePolyLineZRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->savePolyLineZRecord() targeting PhpMyAdmin\ShapeFile\Sha...::savePolyLineZRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
139 24
            ShapeType::Polygon => $this->savePolygonRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->savePolygonRecord() targeting PhpMyAdmin\ShapeFile\Sha...rd::savePolygonRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
140 20
            ShapeType::PolygonM => $this->savePolygonMRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->savePolygonMRecord() targeting PhpMyAdmin\ShapeFile\Sha...d::savePolygonMRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
141 16
            ShapeType::PolygonZ => $this->savePolygonZRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->savePolygonZRecord() targeting PhpMyAdmin\ShapeFile\Sha...d::savePolygonZRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
142 12
            ShapeType::MultiPoint => $this->saveMultiPointRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->saveMultiPointRecord() targeting PhpMyAdmin\ShapeFile\Sha...:saveMultiPointRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
143 8
            ShapeType::MultiPointM => $this->saveMultiPointMRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->saveMultiPointMRecord() targeting PhpMyAdmin\ShapeFile\Sha...saveMultiPointMRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
144 4
            ShapeType::MultiPointZ => $this->saveMultiPointZRecord(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->saveMultiPointZRecord() targeting PhpMyAdmin\ShapeFile\Sha...saveMultiPointZRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
145
            default => $this->reportInvalidShapeTypeError(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->reportInvalidShapeTypeError() targeting PhpMyAdmin\ShapeFile\Sha...InvalidShapeTypeError() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
146 57
        };
147
148 57
        if (! ShapeFile::supportsDbase() || $dbfFile === false) {
149 12
            return;
150
        }
151
152 45
        $this->saveDBFData($dbfFile);
153
    }
154
155
    /**
156
     * Updates DBF data to match header.
157
     *
158
     * @param mixed[] $header DBF structure header
159
     */
160 57
    public function updateDBFInfo(array $header): void
161
    {
162 57
        $tmp = $this->dbfData;
163 57
        $this->dbfData = [];
164 57
        foreach ($header as [$value]) {
165 57
            $this->dbfData[$value] = $tmp[$value] ?? '';
166
        }
167
    }
168
169
    /**
170
     * Reads data.
171
     *
172
     * @param string      $type  type for unpack()
173
     * @param int<0, max> $count number of bytes
174
     */
175 88
    private function loadData(string $type, int $count): mixed
176
    {
177 88
        $data = $this->shapeFile->readSHP($count);
0 ignored issues
show
Bug introduced by
The method readSHP() does not exist on null. ( Ignorable by Annotation )

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

177
        /** @scrutinizer ignore-call */ 
178
        $data = $this->shapeFile->readSHP($count);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
178 88
        if ($data === false) {
179
            return false;
180
        }
181
182 88
        $this->read += strlen($data);
183
184 88
        return Util::loadData($type, $data);
185
    }
186
187
    /**
188
     * Loads metadata header from a file.
189
     */
190 88
    private function loadHeaders(): void
191
    {
192 88
        $this->shapeType = ShapeType::Unknown;
193 88
        $recordNumber = $this->loadData('N', 4);
194 88
        if ($recordNumber === false) {
195 88
            return;
196
        }
197
198 88
        $this->recordNumber = (int) $recordNumber;
199
200
        // We read the length of the record
201 88
        $size = $this->loadData('N', 4);
202 88
        if ($size === false) {
203
            return;
204
        }
205
206 88
        $this->size = ($size * 2) + 8;
207
208 88
        $shapeType = $this->loadData('V', 4);
209 88
        if ($shapeType === false) {
210
            return;
211
        }
212
213 88
        $this->shapeType = ShapeType::tryFrom((int) $shapeType) ?? ShapeType::Unknown;
214
    }
215
216
    /**
217
     * Saves metadata header to a file.
218
     */
219 57
    private function saveHeaders(): void
220
    {
221 57
        fwrite($this->shpFile, pack('N', $this->recordNumber));
222 57
        fwrite($this->shpFile, pack('N', $this->getContentLength()));
223 57
        fwrite($this->shpFile, pack('V', $this->shapeType->value));
224
    }
225
226
    /** @return mixed[] */
227 88
    private function loadPoint(): array
228
    {
229 88
        return [
230 88
            'x' => $this->loadData('d', 8),
231 88
            'y' => $this->loadData('d', 8),
232 88
        ];
233
    }
234
235
    /** @return mixed[] */
236 13
    private function loadPointM(): array
237
    {
238 13
        $data = $this->loadPoint();
239
240 13
        $data['m'] = $this->loadData('d', 8);
241
242 13
        return $data;
243
    }
244
245
    /** @return mixed[] */
246 13
    private function loadPointZ(): array
247
    {
248 13
        $data = $this->loadPoint();
249
250 13
        $data['z'] = $this->loadData('d', 8);
251 13
        $data['m'] = $this->loadData('d', 8);
252
253 13
        return $data;
254
    }
255
256
    /** @param mixed[] $data */
257 49
    private function savePoint(array $data): void
258
    {
259 49
        fwrite($this->shpFile, Util::packDouble($data['x']));
260 49
        fwrite($this->shpFile, Util::packDouble($data['y']));
261
    }
262
263
    /** @param mixed[] $data */
264 13
    private function savePointM(array $data): void
265
    {
266 13
        fwrite($this->shpFile, Util::packDouble($data['x']));
267 13
        fwrite($this->shpFile, Util::packDouble($data['y']));
268 13
        fwrite($this->shpFile, Util::packDouble($data['m']));
269
    }
270
271
    /** @param mixed[] $data */
272 13
    private function savePointZ(array $data): void
273
    {
274 13
        fwrite($this->shpFile, Util::packDouble($data['x']));
275 13
        fwrite($this->shpFile, Util::packDouble($data['y']));
276 13
        fwrite($this->shpFile, Util::packDouble($data['z']));
277 13
        fwrite($this->shpFile, Util::packDouble($data['m']));
278
    }
279
280
    private function loadNullRecord(): void
281
    {
282
        $this->shpData = [];
283
    }
284
285 25
    private function loadPointRecord(): void
286
    {
287 25
        $this->shpData = $this->loadPoint();
288
    }
289
290 13
    private function loadPointMRecord(): void
291
    {
292 13
        $this->shpData = $this->loadPointM();
293
    }
294
295 13
    private function loadPointZRecord(): void
296
    {
297 13
        $this->shpData = $this->loadPointZ();
298
    }
299
300 13
    private function savePointRecord(): void
301
    {
302 13
        $this->savePoint($this->shpData);
303
    }
304
305 13
    private function savePointMRecord(): void
306
    {
307 13
        $this->savePointM($this->shpData);
308
    }
309
310 13
    private function savePointZRecord(): void
311
    {
312 13
        $this->savePointZ($this->shpData);
313
    }
314
315 64
    private function loadBBox(): void
316
    {
317 64
        $this->shpData['xmin'] = $this->loadData('d', 8);
318 64
        $this->shpData['ymin'] = $this->loadData('d', 8);
319 64
        $this->shpData['xmax'] = $this->loadData('d', 8);
320 64
        $this->shpData['ymax'] = $this->loadData('d', 8);
321
    }
322
323 16
    private function loadMultiPointRecord(): void
324
    {
325 16
        $this->shpData = [];
326 16
        $this->loadBBox();
327
328 16
        $this->shpData['numpoints'] = $this->loadData('V', 4);
329
330 16
        for ($i = 0; $i < $this->shpData['numpoints']; ++$i) {
331 16
            $this->shpData['points'][] = $this->loadPoint();
332
        }
333
    }
334
335 12
    private function loadMultiPointMZRecord(string $type): void
336
    {
337
        /* The m dimension is optional, depends on bounding box data */
338 12
        if ($type === 'm' && ! $this->shapeFile->hasMeasure()) {
339 12
            return;
340
        }
341
342 8
        $this->shpData[$type . 'min'] = $this->loadData('d', 8);
343 8
        $this->shpData[$type . 'max'] = $this->loadData('d', 8);
344
345 8
        for ($i = 0; $i < $this->shpData['numpoints']; ++$i) {
346 8
            $this->shpData['points'][$i][$type] = $this->loadData('d', 8);
347
        }
348
    }
349
350 4
    private function loadMultiPointMRecord(): void
351
    {
352 4
        $this->loadMultiPointRecord();
353
354 4
        $this->loadMultiPointMZRecord('m');
355
    }
356
357 8
    private function loadMultiPointZRecord(): void
358
    {
359 8
        $this->loadMultiPointRecord();
360
361 8
        $this->loadMultiPointMZRecord('z');
362 8
        $this->loadMultiPointMZRecord('m');
363
    }
364
365 12
    private function saveMultiPointRecord(): void
366
    {
367 12
        fwrite($this->shpFile, pack(
368 12
            'dddd',
369 12
            $this->shpData['xmin'],
370 12
            $this->shpData['ymin'],
371 12
            $this->shpData['xmax'],
372 12
            $this->shpData['ymax'],
373 12
        ));
374
375 12
        fwrite($this->shpFile, pack('V', $this->shpData['numpoints']));
376
377 12
        for ($i = 0; $i < $this->shpData['numpoints']; ++$i) {
378 12
            $this->savePoint($this->shpData['points'][$i]);
379
        }
380
    }
381
382 8
    private function saveMultiPointMZRecord(string $type): void
383
    {
384 8
        fwrite($this->shpFile, pack('dd', $this->shpData[$type . 'min'], $this->shpData[$type . 'max']));
385
386 8
        for ($i = 0; $i < $this->shpData['numpoints']; ++$i) {
387 8
            fwrite($this->shpFile, Util::packDouble($this->shpData['points'][$i][$type]));
388
        }
389
    }
390
391 4
    private function saveMultiPointMRecord(): void
392
    {
393 4
        $this->saveMultiPointRecord();
394
395 4
        $this->saveMultiPointMZRecord('m');
396
    }
397
398 4
    private function saveMultiPointZRecord(): void
399
    {
400 4
        $this->saveMultiPointRecord();
401
402 4
        $this->saveMultiPointMZRecord('z');
403 4
        $this->saveMultiPointMZRecord('m');
404
    }
405
406 48
    private function loadPolyLineRecord(): void
407
    {
408 48
        $this->shpData = [];
409 48
        $this->loadBBox();
410
411 48
        $this->shpData['numparts'] = $this->loadData('V', 4);
412 48
        $this->shpData['numpoints'] = $this->loadData('V', 4);
413
414 48
        $numparts = $this->shpData['numparts'];
415 48
        $numpoints = $this->shpData['numpoints'];
416
417 48
        for ($i = 0; $i < $numparts; ++$i) {
418 48
            $this->shpData['parts'][$i] = $this->loadData('V', 4);
419
        }
420
421 48
        $part = 0;
422 48
        for ($i = 0; $i < $numpoints; ++$i) {
423 48
            if ($part + 1 < $numparts && $i === $this->shpData['parts'][$part + 1]) {
424 44
                ++$part;
425
            }
426
427
            if (
428 48
                ! isset($this->shpData['parts'][$part]['points'])
429 48
                || ! is_array($this->shpData['parts'][$part]['points'])
430
            ) {
431 48
                $this->shpData['parts'][$part] = ['points' => []];
432
            }
433
434 48
            $this->shpData['parts'][$part]['points'][] = $this->loadPoint();
435
        }
436
    }
437
438 20
    private function loadPolyLineMZRecord(string $type): void
439
    {
440
        /* The m dimension is optional, depends on bounding box data */
441 20
        if ($type === 'm' && ! $this->shapeFile->hasMeasure()) {
442 20
            return;
443
        }
444
445 12
        $this->shpData[$type . 'min'] = $this->loadData('d', 8);
446 12
        $this->shpData[$type . 'max'] = $this->loadData('d', 8);
447
448 12
        $numparts = $this->shpData['numparts'];
449 12
        $numpoints = $this->shpData['numpoints'];
450
451 12
        $part = 0;
452 12
        for ($i = 0; $i < $numpoints; ++$i) {
453 12
            if ($part + 1 < $numparts && $i === $this->shpData['parts'][$part + 1]) {
454
                ++$part;
455
            }
456
457 12
            $this->shpData['parts'][$part]['points'][$i][$type] = $this->loadData('d', 8);
458
        }
459
    }
460
461 8
    private function loadPolyLineMRecord(): void
462
    {
463 8
        $this->loadPolyLineRecord();
464
465 8
        $this->loadPolyLineMZRecord('m');
466
    }
467
468 12
    private function loadPolyLineZRecord(): void
469
    {
470 12
        $this->loadPolyLineRecord();
471
472 12
        $this->loadPolyLineMZRecord('z');
473 12
        $this->loadPolyLineMZRecord('m');
474
    }
475
476 33
    private function savePolyLineRecord(): void
477
    {
478 33
        fwrite($this->shpFile, pack(
479 33
            'dddd',
480 33
            $this->shpData['xmin'],
481 33
            $this->shpData['ymin'],
482 33
            $this->shpData['xmax'],
483 33
            $this->shpData['ymax'],
484 33
        ));
485
486 33
        fwrite($this->shpFile, pack('VV', $this->shpData['numparts'], $this->shpData['numpoints']));
487
488 33
        $partIndex = 0;
489 33
        for ($i = 0; $i < $this->shpData['numparts']; ++$i) {
490 33
            fwrite($this->shpFile, pack('V', $partIndex));
491 33
            $partIndex += count($this->shpData['parts'][$i]['points']);
492
        }
493
494 33
        foreach ($this->shpData['parts'] as $partData) {
495 33
            foreach ($partData['points'] as $pointData) {
496 33
                $this->savePoint($pointData);
497
            }
498
        }
499
    }
500
501 16
    private function savePolyLineMZRecord(string $type): void
502
    {
503 16
        fwrite($this->shpFile, pack('dd', $this->shpData[$type . 'min'], $this->shpData[$type . 'max']));
504
505 16
        foreach ($this->shpData['parts'] as $partData) {
506 16
            foreach ($partData['points'] as $pointData) {
507 16
                fwrite($this->shpFile, Util::packDouble($pointData[$type]));
508
            }
509
        }
510
    }
511
512 8
    private function savePolyLineMRecord(): void
513
    {
514 8
        $this->savePolyLineRecord();
515
516 8
        $this->savePolyLineMZRecord('m');
517
    }
518
519 8
    private function savePolyLineZRecord(): void
520
    {
521 8
        $this->savePolyLineRecord();
522
523 8
        $this->savePolyLineMZRecord('z');
524 8
        $this->savePolyLineMZRecord('m');
525
    }
526
527 15
    private function loadPolygonRecord(): void
528
    {
529 15
        $this->loadPolyLineRecord();
530
    }
531
532 4
    private function loadPolygonMRecord(): void
533
    {
534 4
        $this->loadPolyLineMRecord();
535
    }
536
537 8
    private function loadPolygonZRecord(): void
538
    {
539 8
        $this->loadPolyLineZRecord();
540
    }
541
542 4
    private function savePolygonRecord(): void
543
    {
544 4
        $this->savePolyLineRecord();
545
    }
546
547 4
    private function savePolygonMRecord(): void
548
    {
549 4
        $this->savePolyLineMRecord();
550
    }
551
552 4
    private function savePolygonZRecord(): void
553
    {
554 4
        $this->savePolyLineZRecord();
555
    }
556
557
    /** @param mixed[] $point */
558 57
    private function adjustBBox(array $point): void
559
    {
560
        // Adjusts bounding box based on point
561 57
        foreach (['x', 'y', 'z', 'm'] as $direction) {
562 57
            if (! isset($point[$direction])) {
563 41
                continue;
564
            }
565
566 57
            $min = $direction . 'min';
567 57
            $max = $direction . 'max';
568 57
            if (! isset($this->shpData[$min]) || ($this->shpData[$min] > $point[$direction])) {
569 57
                $this->shpData[$min] = $point[$direction];
570
            }
571
572 57
            if (isset($this->shpData[$max]) && ($this->shpData[$max] >= $point[$direction])) {
573 45
                continue;
574
            }
575
576 57
            $this->shpData[$max] = $point[$direction];
577
        }
578
    }
579
580
    /**
581
     * Adjust point and bounding box when adding point.
582
     * Sets dimension to 0 if not set.
583
     *
584
     * @param mixed[] $point Point data
585
     *
586
     * @return mixed[] Fixed point data
587
     */
588 57
    private function adjustPoint(array $point): array
589
    {
590 57
        if (in_array($this->shapeType, ShapeType::MEASURED_TYPES, true)) {
0 ignored issues
show
Bug introduced by
The constant PhpMyAdmin\ShapeFile\ShapeType::MEASURED_TYPES was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
591 41
            $point['m'] ??= 0.0;
592
        }
593
594 57
        if (in_array($this->shapeType, ShapeType::TYPES_WITH_Z, true)) {
0 ignored issues
show
Bug introduced by
The constant PhpMyAdmin\ShapeFile\ShapeType::TYPES_WITH_Z was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
595 25
            $point['z'] ??= 0.0;
596
        }
597
598 57
        return $point;
599
    }
600
601
    /**
602
     * Adds point to a record.
603
     *
604
     * @param mixed[] $point     Point data
605
     * @param int     $partIndex Part index
606
     */
607 57
    public function addPoint(array $point, int $partIndex = 0): void
608
    {
609 57
        $point = $this->adjustPoint($point);
610 57
        switch ($this->shapeType) {
611 57
            case ShapeType::Null:
612
                //Don't add anything
613
                return;
614
615 57
            case ShapeType::Point:
616 53
            case ShapeType::PointZ:
617 49
            case ShapeType::PointM:
618
                //Substitutes the value of the current point
619 21
                $this->shpData = $point;
620 21
                break;
621 45
            case ShapeType::PolyLine:
622 32
            case ShapeType::Polygon:
623 28
            case ShapeType::PolyLineZ:
624 24
            case ShapeType::PolygonZ:
625 20
            case ShapeType::PolyLineM:
626 16
            case ShapeType::PolygonM:
627
                //Adds a new point to the selected part
628 33
                $this->shpData['parts'][$partIndex]['points'][] = $point;
629 33
                $this->shpData['numparts'] = count($this->shpData['parts']);
630 33
                $this->shpData['numpoints'] = 1 + ($this->shpData['numpoints'] ?? 0);
631 33
                break;
632 12
            case ShapeType::MultiPoint:
633 8
            case ShapeType::MultiPointZ:
634 4
            case ShapeType::MultiPointM:
635
                //Adds a new point
636 12
                $this->shpData['points'][] = $point;
637 12
                $this->shpData['numpoints'] = 1 + ($this->shpData['numpoints'] ?? 0);
638 12
                break;
639
            default:
640
                $this->reportInvalidShapeTypeError();
641
642
                return;
643
        }
644
645 57
        $this->adjustBBox($point);
646
    }
647
648
    /**
649
     * Deletes point from a record.
650
     *
651
     * @param int $pointIndex Point index
652
     * @param int $partIndex  Part index
653
     */
654 48
    public function deletePoint(int $pointIndex = 0, int $partIndex = 0): void
655
    {
656 48
        switch ($this->shapeType) {
657 48
            case ShapeType::Null:
658
                //Don't delete anything
659
                break;
660 48
            case ShapeType::Point:
661 44
            case ShapeType::PointZ:
662 40
            case ShapeType::PointM:
663
                //Sets the value of the point to zero
664 12
                $this->shpData['x'] = 0.0;
665 12
                $this->shpData['y'] = 0.0;
666 12
                if (in_array($this->shapeType, [ShapeType::PointZ, ShapeType::PointM], true)) {
667 8
                    $this->shpData['m'] = 0.0;
668
                }
669
670 12
                if ($this->shapeType === ShapeType::PointZ) {
671 4
                    $this->shpData['z'] = 0.0;
672
                }
673
674 12
                break;
675 36
            case ShapeType::PolyLine:
676 32
            case ShapeType::Polygon:
677 28
            case ShapeType::PolyLineZ:
678 24
            case ShapeType::PolygonZ:
679 20
            case ShapeType::PolyLineM:
680 16
            case ShapeType::PolygonM:
681
                //Deletes the point from the selected part, if exists
682
                if (
683 24
                    isset($this->shpData['parts'][$partIndex])
684 24
                    && isset($this->shpData['parts'][$partIndex]['points'][$pointIndex])
685
                ) {
686 24
                    $count = count($this->shpData['parts'][$partIndex]['points']) - 1;
687 24
                    for ($i = $pointIndex; $i < $count; ++$i) {
688 24
                        $point = $this->shpData['parts'][$partIndex]['points'][$i + 1];
689 24
                        $this->shpData['parts'][$partIndex]['points'][$i] = $point;
690
                    }
691
692 24
                    $count = count($this->shpData['parts'][$partIndex]['points']) - 1;
693 24
                    unset($this->shpData['parts'][$partIndex]['points'][$count]);
694
695 24
                    $this->shpData['numparts'] = count($this->shpData['parts']);
696 24
                    --$this->shpData['numpoints'];
697
                }
698
699 24
                break;
700 12
            case ShapeType::MultiPoint:
701 8
            case ShapeType::MultiPointZ:
702 4
            case ShapeType::MultiPointM:
703
                //Deletes the point, if exists
704 12
                if (isset($this->shpData['points'][$pointIndex])) {
705 12
                    $count = count($this->shpData['points']) - 1;
706 12
                    for ($i = $pointIndex; $i < $count; ++$i) {
707 12
                        $this->shpData['points'][$i] = $this->shpData['points'][$i + 1];
708
                    }
709
710 12
                    unset($this->shpData['points'][count($this->shpData['points']) - 1]);
711
712 12
                    --$this->shpData['numpoints'];
713
                }
714
715 12
                break;
716
            default:
717
                $this->reportInvalidShapeTypeError();
718
                break;
719
        }
720
    }
721
722
    /**
723
     * Returns length of content.
724
     */
725 57
    public function getContentLength(): int|null
726
    {
727
        // The content length for a record is the length of the record contents section measured in 16-bit words.
728
        // one coordinate makes 4 16-bit words (64 bit double)
729 57
        switch ($this->shapeType) {
730 57
            case ShapeType::Null:
731
                $result = 0;
732
                break;
733 57
            case ShapeType::Point:
734 13
                $result = 10;
735 13
                break;
736 53
            case ShapeType::PointM:
737 13
                $result = 10 + 4;
738 13
                break;
739 49
            case ShapeType::PointZ:
740 13
                $result = 10 + 8;
741 13
                break;
742 45
            case ShapeType::PolyLine:
743 32
            case ShapeType::Polygon:
744 17
                $count = count($this->shpData['parts']);
745 17
                $result = 22 + 2 * $count;
746 17
                for ($i = 0; $i < $count; ++$i) {
747 17
                    $result += 8 * count($this->shpData['parts'][$i]['points']);
748
                }
749
750 17
                break;
751 28
            case ShapeType::PolyLineM:
752 24
            case ShapeType::PolygonM:
753 8
                $count = count($this->shpData['parts']);
754 8
                $result = 22 + (2 * 4) + 2 * $count;
755 8
                for ($i = 0; $i < $count; ++$i) {
756 8
                    $result += (8 + 4) * count($this->shpData['parts'][$i]['points']);
757
                }
758
759 8
                break;
760 20
            case ShapeType::PolyLineZ:
761 16
            case ShapeType::PolygonZ:
762 8
                $count = count($this->shpData['parts']);
763 8
                $result = 22 + (4 * 4) + 2 * $count;
764 8
                for ($i = 0; $i < $count; ++$i) {
765 8
                    $result += (8 + 8) * count($this->shpData['parts'][$i]['points']);
766
                }
767
768 8
                break;
769 12
            case ShapeType::MultiPoint:
770 4
                $result = 20 + 8 * count($this->shpData['points']);
771 4
                break;
772 8
            case ShapeType::MultiPointM:
773 4
                $result = 20 + (2 * 4) + (8 + 4) * count($this->shpData['points']);
774 4
                break;
775 4
            case ShapeType::MultiPointZ:
776 4
                $result = 20 + (4 * 4) + (8 + 8) * count($this->shpData['points']);
777 4
                break;
778
            default:
779
                $result = null;
780
                $this->reportInvalidShapeTypeError();
781
                break;
782
        }
783
784 57
        return $result;
785
    }
786
787
    /** @param resource $dbfFile Opened DBF file */
788 66
    private function loadDBFData($dbfFile): void
789
    {
790 66
        $this->dbfData = @dbase_get_record_with_names($dbfFile, $this->recordNumber);
0 ignored issues
show
Bug introduced by
The function dbase_get_record_with_names 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

790
        $this->dbfData = @/** @scrutinizer ignore-call */ dbase_get_record_with_names($dbfFile, $this->recordNumber);
Loading history...
791 66
        unset($this->dbfData['deleted']);
792
    }
793
794
    /** @param resource $dbfFile */
795 45
    private function saveDBFData($dbfFile): void
796
    {
797 45
        if ($this->dbfData === []) {
798
            return;
799
        }
800
801 45
        unset($this->dbfData['deleted']);
802 45
        if ($this->recordNumber <= dbase_numrecords($dbfFile)) {
0 ignored issues
show
Bug introduced by
The function dbase_numrecords 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

802
        if ($this->recordNumber <= /** @scrutinizer ignore-call */ dbase_numrecords($dbfFile)) {
Loading history...
803
            if (! dbase_replace_record($dbfFile, array_values($this->dbfData), $this->recordNumber)) {
0 ignored issues
show
Bug introduced by
The function dbase_replace_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

803
            if (! /** @scrutinizer ignore-call */ dbase_replace_record($dbfFile, array_values($this->dbfData), $this->recordNumber)) {
Loading history...
804
                $this->setError("I wasn't possible to update the information in the DBF file.");
805
            }
806 45
        } elseif (! dbase_add_record($dbfFile, array_values($this->dbfData))) {
0 ignored issues
show
Bug introduced by
The function dbase_add_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

806
        } elseif (! /** @scrutinizer ignore-call */ dbase_add_record($dbfFile, array_values($this->dbfData))) {
Loading history...
807
            $this->setError("I wasn't possible to add the information to the DBF file.");
808
        }
809
    }
810
811
    /**
812
     * Sets error message.
813
     */
814
    public function setError(string $error): void
815
    {
816
        $this->lastError = $error;
817
    }
818
819
    /**
820
     * Returns shape name.
821
     *
822
     * @psalm-return non-empty-string
823
     */
824 4
    public function getShapeName(): string
825
    {
826 4
        return ShapeType::name($this->shapeType);
827
    }
828
829
    private function reportInvalidShapeTypeError(): void
830
    {
831
        $this->setError('Invalid Shape type.');
832
    }
833
}
834