@@ -94,7 +94,7 @@ public function __construct($filepath, $availableColumns = null, $convertFrom =
94
94
}
95
95
}
96
96
97
- protected function open ()
97
+ protected function open (): void
98
98
{
99
99
if (!file_exists ($ this ->filepath )) {
100
100
throw new \Exception (sprintf ('File %s cannot be found ' , $ this ->filepath ));
@@ -108,12 +108,12 @@ protected function open()
108
108
$ this ->readHeader ();
109
109
}
110
110
111
- public function close ()
111
+ public function close (): void
112
112
{
113
113
$ this ->fp ->close ();
114
114
}
115
115
116
- protected function readHeader ()
116
+ protected function readHeader (): void
117
117
{
118
118
$ this ->version = $ this ->fp ->readUChar ();
119
119
$ this ->foxpro = TableType::isFoxpro ($ this ->version );
@@ -134,11 +134,9 @@ protected function readHeader()
134
134
$ this ->fp ->read (4 );
135
135
}
136
136
137
- $ this ->readColumns ();
138
-
139
- if (chr (0x0D ) !== $ this ->fp ->read ()) {
140
- throw new TableException ('Expected header terminator not present at position ' .$ this ->fp ->tell ());
141
- }
137
+ [$ columnsCount , $ terminatorLength ] = $ this ->pickColumnsCount ();
138
+ $ this ->readColumns ($ columnsCount );
139
+ $ this ->checkHeaderTerminator ($ terminatorLength );
142
140
143
141
if (TableType::isVisualFoxpro ($ this ->version )) {
144
142
$ this ->backlist = $ this ->fp ->read (self ::VFP_BACKLIST_LENGTH );
@@ -150,13 +148,24 @@ protected function readHeader()
150
148
$ this ->deleteCount = 0 ;
151
149
}
152
150
153
- protected function readColumns ()
151
+ /**
152
+ * @return array [$fieldCount, $terminatorLength]
153
+ */
154
+ protected function pickColumnsCount (): array
154
155
{
155
- $ fieldCount = $ this ->getLogicalFieldCount ();
156
- if (is_float ($ fieldCount )) {
157
- trigger_error ('Wrong fieldCount calculation ' , E_USER_WARNING );
156
+ // some files has headers with 2byte-terminator 0xOD00
157
+ foreach ([1 , 2 ] as $ terminatorLength ) {
158
+ $ fieldCount = $ this ->getLogicalFieldCount ($ terminatorLength );
159
+ if (is_int ($ fieldCount )) {
160
+ return [$ fieldCount , $ terminatorLength ];
161
+ }
158
162
}
159
163
164
+ throw new \LogicException ('Wrong fieldCount calculation ' );
165
+ }
166
+
167
+ protected function readColumns (int $ columnsCount ): void
168
+ {
160
169
/* some checking */
161
170
clearstatcache ();
162
171
if ($ this ->headerLength > filesize ($ this ->filepath )) {
@@ -173,17 +182,20 @@ protected function readColumns()
173
182
174
183
$ class = ColumnFactory::getClass ($ this ->getVersion ());
175
184
$ index = 0 ;
176
- for ($ i = 0 ; $ i < $ fieldCount ; $ i ++) {
185
+ for ($ i = 0 ; $ i < $ columnsCount ; $ i ++) {
177
186
/** @var ColumnInterface $column */
178
187
$ column = $ class ::create ($ this ->fp ->read (call_user_func ([$ class , 'getHeaderLength ' ])), $ index ++, $ bytePos );
179
188
$ bytePos += $ column ->getLength ();
180
189
$ this ->addColumn ($ column );
181
190
}
182
191
}
183
192
184
- protected function getLogicalFieldCount ()
193
+ /**
194
+ * @return float|int
195
+ */
196
+ protected function getLogicalFieldCount (int $ terminatorLength = 1 )
185
197
{
186
- $ headerLength = self ::HEADER_LENGTH + 1 ; // [Terminator](1)
198
+ $ headerLength = self ::HEADER_LENGTH + $ terminatorLength ; // [Terminator](1)
187
199
$ fieldLength = self ::FIELD_LENGTH ;
188
200
if (in_array ($ this ->getVersion (), [TableType::DBASE_7_MEMO , TableType::DBASE_7_NOMEMO ])) {
189
201
$ headerLength += 36 ; // [Language driver name](32) + [Reserved](4) +
@@ -432,4 +444,26 @@ public function isFoxpro(): bool
432
444
{
433
445
return TableType::isFoxpro ($ this ->version );
434
446
}
447
+
448
+ /**
449
+ * @throws TableException
450
+ */
451
+ private function checkHeaderTerminator (int $ terminatorLength ): void
452
+ {
453
+ $ terminator = $ this ->fp ->read ($ terminatorLength );
454
+ switch ($ terminatorLength ) {
455
+ case 1 :
456
+ if (chr (0x0D ) !== $ terminator ) {
457
+ throw new TableException ('Expected header terminator not present at position ' .$ this ->fp ->tell ());
458
+ }
459
+ break ;
460
+
461
+ case 2 :
462
+ $ unpack = unpack ('n ' , $ terminator );
463
+ if (0x0D00 !== $ unpack [1 ]) {
464
+ throw new TableException ('Expected header terminator not present at position ' .$ this ->fp ->tell ());
465
+ }
466
+ break ;
467
+ }
468
+ }
435
469
}
0 commit comments