Issues (31)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/PhpPresentation/Reader/PowerPoint97.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * This file is part of PHPPresentation - A pure PHP library for reading and writing
4
 * presentations documents.
5
 *
6
 * PHPPresentation is free software distributed under the terms of the GNU Lesser
7
 * General Public License version 3 as published by the Free Software Foundation.
8
 *
9
 * For the full copyright and license information, please read the LICENSE
10
 * file that was distributed with this source code. For the full list of
11
 * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors.
12
 *
13
 * @link        https://github.com/PHPOffice/PHPPresentation
14
 * @copyright   2009-2015 PHPPresentation contributors
15
 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16
 */
17
18
namespace PhpOffice\PhpPresentation\Reader;
19
20
use PhpOffice\Common\Microsoft\OLERead;
21
use PhpOffice\Common\Text;
22
use PhpOffice\PhpPresentation\PhpPresentation;
23
use PhpOffice\PhpPresentation\AbstractShape;
24
use PhpOffice\PhpPresentation\Shape;
25
use PhpOffice\PhpPresentation\Shape\Drawing;
26
use PhpOffice\PhpPresentation\Shape\Group;
27
use PhpOffice\PhpPresentation\Shape\Hyperlink;
28
use PhpOffice\PhpPresentation\Shape\Line;
29
use PhpOffice\PhpPresentation\Shape\RichText;
30
use PhpOffice\PhpPresentation\Style\Alignment;
31
use PhpOffice\PhpPresentation\Style\Color;
32
use PhpOffice\PhpPresentation\Style\Bullet;
33
34
/**
35
 * Serialized format reader
36
 */
37
class PowerPoint97 implements ReaderInterface
38
{
39
    const OFFICEARTBLIPEMF = 0xF01A;
40
    const OFFICEARTBLIPWMF = 0xF01B;
41
    const OFFICEARTBLIPPICT = 0xF01C;
42
    const OFFICEARTBLIPJPG = 0xF01D;
43
    const OFFICEARTBLIPPNG = 0xF01E;
44
    const OFFICEARTBLIPDIB = 0xF01F;
45
    const OFFICEARTBLIPTIFF = 0xF029;
46
    const OFFICEARTBLIPJPEG = 0xF02A;
47
48
    /**
49
     * @link http://msdn.microsoft.com/en-us/library/dd945336(v=office.12).aspx
50
     */
51
    const RT_ANIMATIONINFO = 0x1014;
52
    const RT_ANIMATIONINFOATOM = 0x0FF1;
53
    const RT_BINARYTAGDATABLOB = 0x138B;
54
    const RT_BLIPCOLLECTION9 = 0x07F8;
55
    const RT_BLIPENTITY9ATOM = 0x07F9;
56
    const RT_BOOKMARKCOLLECTION = 0x07E3;
57
    const RT_BOOKMARKENTITYATOM = 0x0FD0;
58
    const RT_BOOKMARKSEEDATOM = 0x07E9;
59
    const RT_BROADCASTDOCINFO9 = 0x177E;
60
    const RT_BROADCASTDOCINFO9ATOM = 0x177F;
61
    const RT_BUILDATOM = 0x2B03;
62
    const RT_BUILDLIST = 0x2B02;
63
    const RT_CHARTBUILD = 0x2B04;
64
    const RT_CHARTBUILDATOM = 0x2B05;
65
    const RT_COLORSCHEMEATOM = 0x07F0;
66
    const RT_COMMENT10 = 0x2EE0;
67
    const RT_COMMENT10ATOM = 0x2EE1;
68
    const RT_COMMENTINDEX10 = 0x2EE4;
69
    const RT_COMMENTINDEX10ATOM = 0x2EE5;
70
    const RT_CRYPTSESSION10CONTAINER = 0x2F14;
71
    const RT_CURRENTUSERATOM = 0x0FF6;
72
    const RT_CSTRING = 0x0FBA;
73
    const RT_DATETIMEMETACHARATOM = 0x0FF7;
74
    const RT_DEFAULTRULERATOM = 0x0FAB;
75
    const RT_DOCROUTINGSLIPATOM = 0x0406;
76
    const RT_DIAGRAMBUILD = 0x2B06;
77
    const RT_DIAGRAMBUILDATOM = 0x2B07;
78
    const RT_DIFF10 = 0x2EED;
79
    const RT_DIFF10ATOM = 0x2EEE;
80
    const RT_DIFFTREE10 = 0x2EEC;
81
    const RT_DOCTOOLBARSTATES10ATOM = 0x36B1;
82
    const RT_DOCUMENT = 0x03E8;
83
    const RT_DOCUMENTATOM = 0x03E9;
84
    const RT_DRAWING = 0x040C;
85
    const RT_DRAWINGGROUP = 0x040B;
86
    const RT_ENDDOCUMENTATOM = 0x03EA;
87
    const RT_EXTERNALAVIMOVIE = 0x1006;
88
    const RT_EXTERNALCDAUDIO = 0x100E;
89
    const RT_EXTERNALCDAUDIOATOM = 0x1012;
90
    const RT_EXTERNALHYPERLINK = 0x0FD7;
91
    const RT_EXTERNALHYPERLINK9 = 0x0FE4;
92
    const RT_EXTERNALHYPERLINKATOM = 0x0FD3;
93
    const RT_EXTERNALHYPERLINKFLAGSATOM = 0x1018;
94
    const RT_EXTERNALMCIMOVIE = 0x1007;
95
    const RT_EXTERNALMEDIAATOM = 0x1004;
96
    const RT_EXTERNALMIDIAUDIO = 0x100D;
97
    const RT_EXTERNALOBJECTLIST = 0x0409;
98
    const RT_EXTERNALOBJECTLISTATOM = 0x040A;
99
    const RT_EXTERNALOBJECTREFATOM = 0x0BC1;
100
    const RT_EXTERNALOLECONTROL = 0x0FEE;
101
    const RT_EXTERNALOLECONTROLATOM = 0x0FFB;
102
    const RT_EXTERNALOLEEMBED = 0x0FCC;
103
    const RT_EXTERNALOLEEMBEDATOM = 0x0FCD;
104
    const RT_EXTERNALOLELINK = 0x0FCE;
105
    const RT_EXTERNALOLELINKATOM = 0x0FD1;
106
    const RT_EXTERNALOLEOBJECTATOM = 0x0FC3;
107
    const RT_EXTERNALOLEOBJECTSTG = 0x1011;
108
    const RT_EXTERNALVIDEO = 0x1005;
109
    const RT_EXTERNALWAVAUDIOEMBEDDED = 0x100F;
110
    const RT_EXTERNALWAVAUDIOEMBEDDEDATOM = 0x1013;
111
    const RT_EXTERNALWAVAUDIOLINK = 0x1010;
112
    const RT_ENVELOPEDATA9ATOM = 0x1785;
113
    const RT_ENVELOPEFLAGS9ATOM = 0x1784;
114
    const RT_ENVIRONMENT = 0x03F2;
115
    const RT_FONTCOLLECTION = 0x07D5;
116
    const RT_FONTCOLLECTION10 = 0x07D6;
117
    const RT_FONTEMBEDDATABLOB = 0x0FB8;
118
    const RT_FONTEMBEDFLAGS10ATOM = 0x32C8;
119
    const RT_FILTERPRIVACYFLAGS10ATOM = 0x36B0;
120
    const RT_FONTENTITYATOM = 0x0FB7;
121
    const RT_FOOTERMETACHARATOM = 0x0FFA;
122
    const RT_GENERICDATEMETACHARATOM = 0x0FF8;
123
    const RT_GRIDSPACING10ATOM = 0x040D;
124
    const RT_GUIDEATOM = 0x03FB;
125
    const RT_HANDOUT = 0x0FC9;
126
    const RT_HASHCODEATOM = 0x2B00;
127
    const RT_HEADERSFOOTERS = 0x0FD9;
128
    const RT_HEADERSFOOTERSATOM = 0x0FDA;
129
    const RT_HEADERMETACHARATOM = 0x0FF9;
130
    const RT_HTMLDOCINFO9ATOM = 0x177B;
131
    const RT_HTMLPUBLISHINFOATOM = 0x177C;
132
    const RT_HTMLPUBLISHINFO9 = 0x177D;
133
    const RT_INTERACTIVEINFO = 0x0FF2;
134
    const RT_INTERACTIVEINFOATOM = 0x0FF3;
135
    const RT_KINSOKU = 0x0FC8;
136
    const RT_KINSOKUATOM = 0x0FD2;
137
    const RT_LEVELINFOATOM = 0x2B0A;
138
    const RT_LINKEDSHAPE10ATOM = 0x2EE6;
139
    const RT_LINKEDSLIDE10ATOM = 0x2EE7;
140
    const RT_LIST = 0x07D0;
141
    const RT_MAINMASTER = 0x03F8;
142
    const RT_MASTERTEXTPROPATOM = 0x0FA2;
143
    const RT_METAFILE = 0x0FC1;
144
    const RT_NAMEDSHOW = 0x0411;
145
    const RT_NAMEDSHOWS = 0x0410;
146
    const RT_NAMEDSHOWSLIDESATOM = 0x0412;
147
    const RT_NORMALVIEWSETINFO9 = 0x0414;
148
    const RT_NORMALVIEWSETINFO9ATOM = 0x0415;
149
    const RT_NOTES= 0x03F0;
150
    const RT_NOTESATOM = 0x03F1;
151
    const RT_NOTESTEXTVIEWINFO9 = 0x0413;
152
    const RT_OUTLINETEXTPROPS9 = 0x0FAE;
153
    const RT_OUTLINETEXTPROPS10 = 0x0FB3;
154
    const RT_OUTLINETEXTPROPS11 = 0x0FB5;
155
    const RT_OUTLINETEXTPROPSHEADER9ATOM = 0x0FAF;
156
    const RT_OUTLINETEXTREFATOM = 0x0F9E;
157
    const RT_OUTLINEVIEWINFO = 0x0407;
158
    const RT_PERSISTDIRECTORYATOM = 0x1772;
159
    const RT_PARABUILD = 0x2B08;
160
    const RT_PARABUILDATOM = 0x2B09;
161
    const RT_PHOTOALBUMINFO10ATOM = 0x36B2;
162
    const RT_PLACEHOLDERATOM = 0x0BC3;
163
    const RT_PRESENTATIONADVISORFLAGS9ATOM = 0x177A;
164
    const RT_PRINTOPTIONSATOM = 0x1770;
165
    const RT_PROGBINARYTAG = 0x138A;
166
    const RT_PROGSTRINGTAG = 0x1389;
167
    const RT_PROGTAGS = 0x1388;
168
    const RT_RECOLORINFOATOM = 0x0FE7;
169
    const RT_RTFDATETIMEMETACHARATOM = 0x1015;
170
    const RT_ROUNDTRIPANIMATIONATOM12ATOM = 0x2B0B;
171
    const RT_ROUNDTRIPANIMATIONHASHATOM12ATOM = 0x2B0D;
172
    const RT_ROUNDTRIPCOLORMAPPING12ATOM = 0x040F;
173
    const RT_ROUNDTRIPCOMPOSITEMASTERID12ATOM = 0x041D;
174
    const RT_ROUNDTRIPCONTENTMASTERID12ATOM = 0x0422;
175
    const RT_ROUNDTRIPCONTENTMASTERINFO12ATOM = 0x041E;
176
    const RT_ROUNDTRIPCUSTOMTABLESTYLES12ATOM = 0x0428;
177
    const RT_ROUNDTRIPDOCFLAGS12ATOM = 0x0425;
178
    const RT_ROUNDTRIPHEADERFOOTERDEFAULTS12ATOM = 0x0424;
179
    const RT_ROUNDTRIPHFPLACEHOLDER12ATOM = 0x0420;
180
    const RT_ROUNDTRIPNEWPLACEHOLDERID12ATOM = 0x0BDD;
181
    const RT_ROUNDTRIPNOTESMASTERTEXTSTYLES12ATOM = 0x0427;
182
    const RT_ROUNDTRIPOARTTEXTSTYLES12ATOM = 0x0423;
183
    const RT_ROUNDTRIPORIGINALMAINMASTERID12ATOM = 0x041C;
184
    const RT_ROUNDTRIPSHAPECHECKSUMFORCL12ATOM = 0x0426;
185
    const RT_ROUNDTRIPSHAPEID12ATOM = 0x041F;
186
    const RT_ROUNDTRIPSLIDESYNCINFO12 = 0x3714;
187
    const RT_ROUNDTRIPSLIDESYNCINFOATOM12 = 0x3715;
188
    const RT_ROUNDTRIPTHEME12ATOM = 0x040E;
189
    const RT_SHAPEATOM = 0x0BDB;
190
    const RT_SHAPEFLAGS10ATOM = 0x0BDC;
191
    const RT_SLIDE = 0x03EE;
192
    const RT_SLIDEATOM = 0x03EF;
193
    const RT_SLIDEFLAGS10ATOM = 0x2EEA;
194
    const RT_SLIDELISTENTRY10ATOM = 0x2EF0;
195
    const RT_SLIDELISTTABLE10 = 0x2EF1;
196
    const RT_SLIDELISTWITHTEXT = 0x0FF0;
197
    const RT_SLIDELISTTABLESIZE10ATOM = 0x2EEF;
198
    const RT_SLIDENUMBERMETACHARATOM = 0x0FD8;
199
    const RT_SLIDEPERSISTATOM = 0x03F3;
200
    const RT_SLIDESHOWDOCINFOATOM = 0x0401;
201
    const RT_SLIDESHOWSLIDEINFOATOM = 0x03F9;
202
    const RT_SLIDETIME10ATOM = 0x2EEB;
203
    const RT_SLIDEVIEWINFO = 0x03FA;
204
    const RT_SLIDEVIEWINFOATOM = 0x03FE;
205
    const RT_SMARTTAGSTORE11CONTAINER = 0x36B3;
206
    const RT_SOUND = 0x07E6;
207
    const RT_SOUNDCOLLECTION = 0x07E4;
208
    const RT_SOUNDCOLLECTIONATOM = 0x07E5;
209
    const RT_SOUNDDATABLOB = 0x07E7;
210
    const RT_SORTERVIEWINFO = 0x0408;
211
    const RT_STYLETEXTPROPATOM = 0x0FA1;
212
    const RT_STYLETEXTPROP10ATOM = 0x0FB1;
213
    const RT_STYLETEXTPROP11ATOM = 0x0FB6;
214
    const RT_STYLETEXTPROP9ATOM = 0x0FAC;
215
    const RT_SUMMARY = 0x0402;
216
    const RT_TEXTBOOKMARKATOM = 0x0FA7;
217
    const RT_TEXTBYTESATOM = 0x0FA8;
218
    const RT_TEXTCHARFORMATEXCEPTIONATOM = 0x0FA4;
219
    const RT_TEXTCHARSATOM = 0x0FA0;
220
    const RT_TEXTDEFAULTS10ATOM = 0x0FB4;
221
    const RT_TEXTDEFAULTS9ATOM = 0x0FB0;
222
    const RT_TEXTHEADERATOM = 0x0F9F;
223
    const RT_TEXTINTERACTIVEINFOATOM = 0x0FDF;
224
    const RT_TEXTMASTERSTYLEATOM = 0x0FA3;
225
    const RT_TEXTMASTERSTYLE10ATOM = 0x0FB2;
226
    const RT_TEXTMASTERSTYLE9ATOM = 0x0FAD;
227
    const RT_TEXTPARAGRAPHFORMATEXCEPTIONATOM = 0x0FA5;
228
    const RT_TEXTRULERATOM = 0x0FA6;
229
    const RT_TEXTSPECIALINFOATOM = 0x0FAA;
230
    const RT_TEXTSPECIALINFODEFAULTATOM = 0x0FA9;
231
    const RT_TIMEANIMATEBEHAVIOR = 0xF134;
232
    const RT_TIMEANIMATEBEHAVIORCONTAINER = 0xF12B;
233
    const RT_TIMEANIMATIONVALUE = 0xF143;
234
    const RT_TIMEANIMATIONVALUELIST = 0xF13F;
235
    const RT_TIMEBEHAVIOR = 0xF133;
236
    const RT_TIMEBEHAVIORCONTAINER = 0xF12A;
237
    const RT_TIMECOLORBEHAVIOR = 0xF135;
238
    const RT_TIMECOLORBEHAVIORCONTAINER = 0xF12C;
239
    const RT_TIMECLIENTVISUALELEMENT = 0xF13C;
240
    const RT_TIMECOMMANDBEHAVIOR = 0xF13B;
241
    const RT_TIMECOMMANDBEHAVIORCONTAINER = 0xF132;
242
    const RT_TIMECONDITION = 0xF128;
243
    const RT_TIMECONDITIONCONTAINER = 0xF125;
244
    const RT_TIMEEFFECTBEHAVIOR = 0xF136;
245
    const RT_TIMEEFFECTBEHAVIORCONTAINER = 0xF12D;
246
    const RT_TIMEEXTTIMENODECONTAINER = 0xF144;
247
    const RT_TIMEITERATEDATA = 0xF140;
248
    const RT_TIMEMODIFIER = 0xF129;
249
    const RT_TIMEMOTIONBEHAVIOR = 0xF137;
250
    const RT_TIMEMOTIONBEHAVIORCONTAINER = 0xF12E;
251
    const RT_TIMENODE = 0xF127;
252
    const RT_TIMEPROPERTYLIST = 0xF13D;
253
    const RT_TIMEROTATIONBEHAVIOR = 0xF138;
254
    const RT_TIMEROTATIONBEHAVIORCONTAINER = 0xF12F;
255
    const RT_TIMESCALEBEHAVIOR = 0xF139;
256
    const RT_TIMESCALEBEHAVIORCONTAINER = 0xF130;
257
    const RT_TIMESEQUENCEDATA = 0xF141;
258
    const RT_TIMESETBEHAVIOR = 0xF13A;
259
    const RT_TIMESETBEHAVIORCONTAINER = 0xF131;
260
    const RT_TIMESUBEFFECTCONTAINER = 0xF145;
261
    const RT_TIMEVARIANT = 0xF142;
262
    const RT_TIMEVARIANTLIST = 0xF13E;
263
    const RT_USEREDITATOM = 0x0FF5;
264
    const RT_VBAINFO = 0x03FF;
265
    const RT_VBAINFOATOM = 0x0400;
266
    const RT_VIEWINFOATOM = 0x03FD;
267
    const RT_VISUALPAGEATOM = 0x2B01;
268
    const RT_VISUALSHAPEATOM = 0x2AFB;
269
270
    /**
271
     * @var http://msdn.microsoft.com/en-us/library/dd926394(v=office.12).aspx
272
     */
273
    const SL_BIGOBJECT = 0x0000000F;
274
    const SL_BLANK = 0x00000010;
275
    const SL_COLUMNTWOROWS = 0x0000000A;
276
    const SL_FOUROBJECTS = 0x0000000E;
277
    const SL_MASTERTITLE = 0x00000002;
278
    const SL_TITLEBODY = 0x00000001;
279
    const SL_TITLEONLY = 0x00000007;
280
    const SL_TITLESLIDE = 0x00000000;
281
    const SL_TWOCOLUMNS = 0x00000008;
282
    const SL_TWOCOLUMNSROW = 0x0000000D;
283
    const SL_TWOROWS = 0x00000009;
284
    const SL_TWOROWSCOLUMN = 0x0000000B;
285
    const SL_VERTICALTITLEBODY = 0x00000011;
286
    const SL_VERTICALTWOROWS = 0x00000012;
287
288
    /**
289
     * Array with Fonts
290
     */
291
    private $arrayFonts = array();
292
    /**
293
     * Array with Hyperlinks
294
     */
295
    private $arrayHyperlinks = array();
296
    /**
297
     * Array with Notes
298
     */
299
    private $arrayNotes = array();
300
    /**
301
     * Array with Pictures
302
     */
303
    private $arrayPictures = array();
304
    /**
305
     * Offset (in bytes) from the beginning of the PowerPoint Document Stream to the UserEditAtom record for the most recent user edit.
306
     * @var int
307
     */
308
    private $offsetToCurrentEdit;
309
    /**
310
     * A structure that specifies a compressed table of sequential persist object identifiers and stream offsets to associated persist objects.
311
     * @var int[]
312
     */
313
    private $rgPersistDirEntry;
314
    /**
315
     * Offset (in bytes) from the beginning of the PowerPoint Document Stream to the PersistDirectoryAtom record for this user edit
316
     * @var int
317
     */
318
    private $offsetPersistDirectory;
319
    /**
320
     * Output Object
321
     * @var PhpPresentation
322
     */
323
    private $oPhpPresentation;
324
    /**
325
     * Group Object
326
     * @var Group
327
     */
328
    private $oCurrentGroup;
329
    /**
330
     * @var boolean
331
     */
332
    private $bFirstShapeGroup = false;
333
    /**
334
     * Stream "Powerpoint Document"
335
     * @var string
336
     */
337
    private $streamPowerpointDocument;
338
    /**
339
     * Stream "Current User"
340
     * @var string
341
     */
342
    private $streamCurrentUser;
343
    /**
344
     * Stream "Summary Information"
345
     * @var string
346
     */
347
    private $streamSummaryInformation;
348
    /**
349
     * Stream "Document Summary Information"
350
     * @var string
351
     */
352
    private $streamDocumentSummaryInformation;
353
    /**
354
     * Stream "Pictures"
355
     * @var string
356
     */
357
    private $streamPictures;
358
    /**
359
     * @var integer
360
     */
361
    private $inMainType;
362
    /**
363
     * @var integer
364
     */
365
    private $currentNote;
366
367
    /**
368
     * Can the current \PhpOffice\PhpPresentation\Reader\ReaderInterface read the file?
369
     *
370
     * @param  string $pFilename
371
     * @throws \Exception
372
     * @return boolean
373
     */
374 3
    public function canRead($pFilename)
375
    {
376 3
        return $this->fileSupportsUnserializePhpPresentation($pFilename);
377
    }
378
379
    /**
380
     * Does a file support UnserializePhpPresentation ?
381
     *
382
     * @param  string    $pFilename
383
     * @throws \Exception
384
     * @return boolean
385
     */
386 10
    public function fileSupportsUnserializePhpPresentation($pFilename = '')
387
    {
388
        // Check if file exists
389 10
        if (!file_exists($pFilename)) {
390 2
            throw new \Exception("Could not open " . $pFilename . " for reading! File does not exist.");
391
        }
392
393
        try {
394
            // Use ParseXL for the hard work.
395 8
            $ole = new OLERead();
396
            // get excel data
397 8
            $ole->read($pFilename);
398 5
            return true;
399 3
        } catch (\Exception $e) {
400 3
            return false;
401
        }
402
    }
403
404
    /**
405
     * Loads PhpPresentation Serialized file
406
     *
407
     * @param  string        $pFilename
408
     * @return \PhpOffice\PhpPresentation\PhpPresentation
409
     * @throws \Exception
410
     */
411 6
    public function load($pFilename)
412
    {
413
        // Unserialize... First make sure the file supports it!
414 6
        if (!$this->fileSupportsUnserializePhpPresentation($pFilename)) {
415 1
            throw new \Exception("Invalid file format for PhpOffice\PhpPresentation\Reader\PowerPoint97: " . $pFilename . ".");
416
        }
417
418 4
        return $this->loadFile($pFilename);
419
    }
420
421
    /**
422
     * Load PhpPresentation Serialized file
423
     *
424
     * @param  string $pFilename
425
     * @return \PhpOffice\PhpPresentation\PhpPresentation
426
     * @throws \Exception
427
     */
428 4
    private function loadFile($pFilename)
429
    {
430 4
        $this->oPhpPresentation = new PhpPresentation();
431 4
        $this->oPhpPresentation->removeSlideByIndex();
432
433
        // Read OLE Blocks
434 4
        $this->loadOLE($pFilename);
435
        // Read pictures in the Pictures Stream
436 4
        $this->loadPicturesStream();
437
        // Read information in the Current User Stream
438 4
        $this->loadCurrentUserStream();
439
        // Read information in the PowerPoint Document Stream
440 4
        $this->loadPowerpointDocumentStream();
441
442 4
        return $this->oPhpPresentation;
443
    }
444
445
    /**
446
     * Read OLE Part
447
     * @param string $pFilename
448
     * @throws \Exception
449
     */
450 4
    private function loadOLE($pFilename)
451
    {
452
        // OLE reader
453 4
        $oOLE = new OLERead();
454 4
        $oOLE->read($pFilename);
455
456
        // PowerPoint Document Stream
457 4
        $this->streamPowerpointDocument = $oOLE->getStream($oOLE->powerpointDocument);
458
459
        // Current User Stream
460 4
        $this->streamCurrentUser = $oOLE->getStream($oOLE->currentUser);
461
462
        // Get summary information data
463 4
        $this->streamSummaryInformation = $oOLE->getStream($oOLE->summaryInformation);
464
465
        // Get additional document summary information data
466 4
        $this->streamDocumentSummaryInformation = $oOLE->getStream($oOLE->docSummaryInfos);
467
468
        // Get pictures data
469 4
        $this->streamPictures = $oOLE->getStream($oOLE->pictures);
470 4
    }
471
472
    /**
473
     * Stream Pictures
474
     * @link http://msdn.microsoft.com/en-us/library/dd920746(v=office.12).aspx
475
     */
476 4
    private function loadPicturesStream()
477
    {
478 4
        $stream = $this->streamPictures;
479
480 4
        $pos = 0;
481
        do {
482 4
            $arrayRH = $this->loadRecordHeader($stream, $pos);
483 4
            $pos += 8;
484 4
            $readSuccess = false;
485 4
            if ($arrayRH['recVer'] == 0x00 && ($arrayRH['recType'] == 0xF007 || ($arrayRH['recType'] >= 0xF018 && $arrayRH['recType'] <= 0xF117))) {
486
                //@link : http://msdn.microsoft.com/en-us/library/dd950560(v=office.12).aspx
487 4
                if ($arrayRH['recType'] == 0xF007) {
488
                    // OfficeArtFBSE
489
                    throw new \Exception('Feature not implemented (l.'.__LINE__.')');
490
                }
491 4
                if ($arrayRH['recType'] >= 0xF018 && $arrayRH['recType'] <= 0xF117) {
492 4
                    $arrayRecord = $this->readRecordOfficeArtBlip($stream, $pos - 8);
493 4
                    if ($arrayRecord['length'] > 0) {
494 4
                        $pos += $arrayRecord['length'];
495 4
                        $this->arrayPictures[] = $arrayRecord['picture'];
496
                    }
497
                }
498 4
                $readSuccess = true;
499
            }
500 4
        } while ($readSuccess === true);
501 4
    }
502
503
    /**
504
     * Stream Current User
505
     * @link http://msdn.microsoft.com/en-us/library/dd908567(v=office.12).aspx
506
     */
507 4
    private function loadCurrentUserStream()
508
    {
509 4
        $pos = 0;
510
511
        /**
512
         * CurrentUserAtom : http://msdn.microsoft.com/en-us/library/dd948895(v=office.12).aspx
513
         */
514
        // RecordHeader : http://msdn.microsoft.com/en-us/library/dd926377(v=office.12).aspx
515 4
        $rHeader = $this->loadRecordHeader($this->streamCurrentUser, $pos);
516 4
        $pos += 8;
517 4
        if ($rHeader['recVer'] != 0x0 || $rHeader['recInstance'] != 0x000 || $rHeader['recType'] != self::RT_CURRENTUSERATOM) {
518
            throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > RecordHeader).');
519
        }
520
521
        // Size
522 4
        $size = self::getInt4d($this->streamCurrentUser, $pos);
523 4
        $pos += 4;
524 4
        if ($size !=  0x00000014) {
525
            throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > Size).');
526
        }
527
528
        // headerToken
529 4
        $headerToken = self::getInt4d($this->streamCurrentUser, $pos);
530 4
        $pos += 4;
531 4
        if ($headerToken == 0xF3D1C4DF && $headerToken != 0xE391C05F) {
532
            throw new \Exception('Feature not implemented (l.'.__LINE__.') : Encrypted file');
533
        }
534
535
        // offsetToCurrentEdit
536 4
        $this->offsetToCurrentEdit = self::getInt4d($this->streamCurrentUser, $pos);
537 4
        $pos += 4;
538
539
        // lenUserName
540 4
        $lenUserName = self::getInt2d($this->streamCurrentUser, $pos);
541 4
        $pos += 2;
542 4
        if ($lenUserName > 255) {
543
            throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > lenUserName).');
544
        }
545
546
        // docFileVersion
547 4
        $docFileVersion = self::getInt2d($this->streamCurrentUser, $pos);
548 4
        $pos += 2;
549 4
        if ($docFileVersion != 0x03F4) {
550
            throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > docFileVersion).');
551
        }
552
553
        // majorVersion
554 4
        $majorVersion = self::getInt1d($this->streamCurrentUser, $pos);
555 4
        $pos += 1;
556 4
        if ($majorVersion != 0x03) {
557
            throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > majorVersion).');
558
        }
559
560
        // minorVersion
561 4
        $minorVersion = self::getInt1d($this->streamCurrentUser, $pos);
562 4
        $pos += 1;
563 4
        if ($minorVersion != 0x00) {
564
            throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > minorVersion).');
565
        }
566
567
        // unused
568 4
        $pos += 2;
569
570
        // ansiUserName
571
        // $ansiUserName = '';
572
        do {
573 4
            $char = self::getInt1d($this->streamCurrentUser, $pos);
574 4
            if (($char >= 0x00 && $char <= 0x1F) || ($char >= 0x7F && $char <= 0x9F)) {
575 4
                $char = false;
576
            } else {
577
                // $ansiUserName .= chr($char);
578 4
                $pos += 1;
579
            }
580 4
        } while ($char !== false);
581
582
        // relVersion
583 4
        $relVersion = self::getInt4d($this->streamCurrentUser, $pos);
584 4
        $pos += 4;
585 4
        if ($relVersion != 0x00000008 && $relVersion != 0x00000009) {
586
            throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > relVersion).');
587
        }
588
589
        // unicodeUserName
590
        // $unicodeUserName = '';
591 4
        for ($inc = 0; $inc < $lenUserName; $inc++) {
592 4
            $char = self::getInt2d($this->streamCurrentUser, $pos);
593 4
            if (($char >= 0x00 && $char <= 0x1F) || ($char >= 0x7F && $char <= 0x9F)) {
594 4
                break;
595
            }
596
            // $unicodeUserName .= chr($char);
597
            $pos += 2;
598
        }
599 4
    }
600
601
    /**
602
     * Stream Powerpoint Document
603
     * @link http://msdn.microsoft.com/en-us/library/dd921564(v=office.12).aspx
604
     */
605 4
    private function loadPowerpointDocumentStream()
606
    {
607 4
        $this->readRecordUserEditAtom($this->streamPowerpointDocument, $this->offsetToCurrentEdit);
608
609 4
        $this->readRecordPersistDirectoryAtom($this->streamPowerpointDocument, $this->offsetPersistDirectory);
610
611 4
        foreach ($this->rgPersistDirEntry as $offsetDir) {
612 4
            $pos = $offsetDir;
613
614 4
            $rHeader = $this->loadRecordHeader($this->streamPowerpointDocument, $pos);
615 4
            $pos += 8;
616 4
            $this->inMainType = $rHeader['recType'];
617 4
            $this->currentNote = null;
618 4
            switch ($rHeader['recType']) {
619 4
                case self::RT_DOCUMENT:
620 4
                    $this->readRecordDocumentContainer($this->streamPowerpointDocument, $pos);
621 4
                    break;
622 4
                case self::RT_NOTES:
623 4
                    $this->readRecordNotesContainer($this->streamPowerpointDocument, $pos);
624 4
                    break;
625 4
                case self::RT_SLIDE:
626 4
                    $this->readRecordSlideContainer($this->streamPowerpointDocument, $pos);
627 4
                    break;
628
                default:
629
                    // throw new \Exception('Feature not implemented : l.'.__LINE__.'('.dechex($rh['recType']).')');
630 4
                    break;
631
            }
632
        }
633 4
    }
634
635
    /**
636
     * Read a record header
637
     * @param string $stream
638
     * @param integer $pos
639
     * @return array
640
     */
641 4
    private function loadRecordHeader($stream, $pos)
642
    {
643 4
        $rec = self::getInt2d($stream, $pos);
644 4
        $recType = self::getInt2d($stream, $pos + 2);
645 4
        $recLen = self::getInt4d($stream, $pos + 4);
646
        return array(
647 4
            'recVer' => ($rec >> 0) & bindec('1111'),
648 4
            'recInstance' => ($rec >> 4) & bindec('111111111111'),
649 4
            'recType' => $recType,
650 4
            'recLen' => $recLen,
651
        );
652
    }
653
654
    /**
655
     * Read 8-bit unsigned integer
656
     *
657
     * @param string $data
658
     * @param int $pos
659
     * @return int
660
     */
661 4
    public static function getInt1d($data, $pos)
662
    {
663 4
        return ord($data[$pos]);
664
    }
665
666
    /**
667
     * Read 16-bit unsigned integer
668
     *
669
     * @param string $data
670
     * @param int $pos
671
     * @return int
672
     */
673 4
    public static function getInt2d($data, $pos)
674
    {
675 4
        return ord($data[$pos]) | (ord($data[$pos+1]) << 8);
676
    }
677
678
    /**
679
     * Read 32-bit signed integer
680
     *
681
     * @param string $data
682
     * @param int $pos
683
     * @return int
684
     */
685 4
    public static function getInt4d($data, $pos)
686
    {
687
        // FIX: represent numbers correctly on 64-bit system
688
        // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
689
        // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
690 4
        $or24 = ord($data[$pos + 3]);
691
692 4
        $ord24 = ($or24 & 127) << 24;
693 4
        if ($or24 >= 128) {
694
            // negative number
695 4
            $ord24 = -abs((256 - $or24) << 24);
696
        }
697 4
        return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $ord24;
698
    }
699
700
    /**
701
     * A container record that specifies the animation and sound information for a shape.
702
     * @param string $stream
703
     * @param integer $pos
704
     * @return array
705
     * @throws \Exception
706
     * @link https://msdn.microsoft.com/en-us/library/dd772900(v=office.12).aspx
707
     */
708 4
    private function readRecordAnimationInfoContainer($stream, $pos)
709
    {
710
        $arrayReturn = array(
711 4
            'length' => 0,
712
        );
713
714 4
        $data = $this->loadRecordHeader($stream, $pos);
715 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_ANIMATIONINFO) {
716
            // Record Header
717
            $arrayReturn['length'] += 8;
718
            // animationAtom
719
            // animationSound
720
            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
721
        }
722
723 4
        return $arrayReturn;
724
    }
725
726
    /**
727
     * A container record that specifies information about the document.
728
     * @param string $stream
729
     * @param integer $pos
730
     * @throws \Exception
731
     * @link http://msdn.microsoft.com/en-us/library/dd947357(v=office.12).aspx
732
     */
733 4
    private function readRecordDocumentContainer($stream, $pos)
734
    {
735 4
        $documentAtom = $this->loadRecordHeader($stream, $pos);
736 4
        $pos += 8;
737 4
        if ($documentAtom['recVer'] != 0x1 || $documentAtom['recInstance'] != 0x000 || $documentAtom['recType'] != self::RT_DOCUMENTATOM) {
738
            throw new \Exception('File PowerPoint 97 in error (Location : RTDocument > DocumentAtom).');
739
        }
740 4
        $pos += $documentAtom['recLen'];
741
742 4
        $exObjList = $this->loadRecordHeader($stream, $pos);
743 4
        if ($exObjList['recVer'] == 0xF && $exObjList['recInstance'] == 0x000 && $exObjList['recType'] == self::RT_EXTERNALOBJECTLIST) {
744 1
            $pos += 8;
745
            // exObjListAtom > rh
746 1
            $exObjListAtom = $this->loadRecordHeader($stream, $pos);
747 1
            if ($exObjListAtom['recVer'] != 0x0 || $exObjListAtom['recInstance'] != 0x000 || $exObjListAtom['recType'] != self::RT_EXTERNALOBJECTLISTATOM || $exObjListAtom['recLen'] != 0x00000004) {
748
                throw new \Exception('File PowerPoint 97 in error (Location : RTDocument > DocumentAtom > exObjList > exObjListAtom).');
749
            }
750 1
            $pos += 8;
751
            // exObjListAtom > exObjIdSeed
752 1
            $pos += 4;
753
            // rgChildRec
754 1
            $exObjList['recLen'] -= 12;
755
            do {
756 1
                $childRec = $this->loadRecordHeader($stream, $pos);
757 1
                $pos += 8;
758 1
                $exObjList['recLen'] -= 8;
759 1
                switch ($childRec['recType']) {
760 1
                    case self::RT_EXTERNALHYPERLINK:
761
                        //@link : http://msdn.microsoft.com/en-us/library/dd944995(v=office.12).aspx
762
                        // exHyperlinkAtom > rh
763 1
                        $exHyperlinkAtom = $this->loadRecordHeader($stream, $pos);
764 1
                        if ($exHyperlinkAtom['recVer'] != 0x0 || $exHyperlinkAtom['recInstance'] != 0x000 || $exHyperlinkAtom['recType'] != self::RT_EXTERNALHYPERLINKATOM || $exObjListAtom['recLen'] != 0x00000004) {
765
                            throw new \Exception('File PowerPoint 97 in error (Location : RTDocument > DocumentAtom > exObjList > rgChildRec > RT_ExternalHyperlink).');
766
                        }
767 1
                        $pos += 8;
768 1
                        $exObjList['recLen'] -= 8;
769
                        // exHyperlinkAtom > exHyperlinkId
770 1
                        $exHyperlinkId = self::getInt4d($stream, $pos);
771 1
                        $pos += 4;
772 1
                        $exObjList['recLen'] -= 4;
773
774 1
                        $this->arrayHyperlinks[$exHyperlinkId] = array();
775
                        // friendlyNameAtom
776 1
                        $friendlyNameAtom  = $this->loadRecordHeader($stream, $pos);
777 1
                        if ($friendlyNameAtom['recVer'] == 0x0 && $friendlyNameAtom['recInstance'] == 0x000 && $friendlyNameAtom['recType'] == self::RT_CSTRING && $friendlyNameAtom['recLen'] % 2 == 0) {
778 1
                            $pos += 8;
779 1
                            $exObjList['recLen'] -= 8;
780 1
                            $this->arrayHyperlinks[$exHyperlinkId]['text'] = '';
781 1
                            for ($inc = 0; $inc < ($friendlyNameAtom['recLen'] / 2); $inc++) {
782 1
                                $char = self::getInt2d($stream, $pos);
783 1
                                $pos += 2;
784 1
                                $exObjList['recLen'] -= 2;
785 1
                                $this->arrayHyperlinks[$exHyperlinkId]['text'] .= chr($char);
786
                            }
787
                        }
788
                        // targetAtom
789 1
                        $targetAtom  = $this->loadRecordHeader($stream, $pos);
790 1
                        if ($targetAtom['recVer'] == 0x0 && $targetAtom['recInstance'] == 0x001 && $targetAtom['recType'] == self::RT_CSTRING && $targetAtom['recLen'] % 2 == 0) {
791 1
                            $pos += 8;
792 1
                            $exObjList['recLen'] -= 8;
793 1
                            $this->arrayHyperlinks[$exHyperlinkId]['url'] = '';
794 1
                            for ($inc = 0; $inc < ($targetAtom['recLen'] / 2); $inc++) {
795 1
                                $char = self::getInt2d($stream, $pos);
796 1
                                $pos += 2;
797 1
                                $exObjList['recLen'] -= 2;
798 1
                                $this->arrayHyperlinks[$exHyperlinkId]['url'] .= chr($char);
799
                            }
800
                        }
801
                        // locationAtom
802 1
                        $locationAtom  = $this->loadRecordHeader($stream, $pos);
803 1
                        if ($locationAtom['recVer'] == 0x0 && $locationAtom['recInstance'] == 0x003 && $locationAtom['recType'] == self::RT_CSTRING && $locationAtom['recLen'] % 2 == 0) {
804
                            $pos += 8;
805
                            $exObjList['recLen'] -= 8;
806
                            $string = '';
807
                            for ($inc = 0; $inc < ($locationAtom['recLen'] / 2); $inc++) {
808
                                $char = self::getInt2d($stream, $pos);
809
                                $pos += 2;
810
                                $exObjList['recLen'] -= 2;
811
                                $string .= chr($char);
812
                            }
813
                        }
814 1
                        break;
815
                    default:
816
                        throw new \Exception('Feature not implemented (l.'.__LINE__.' : '.dechex($childRec['recType'].')'));
817
                }
818 1
            } while ($exObjList['recLen'] > 0);
819
        }
820
821
        //@link : http://msdn.microsoft.com/en-us/library/dd907813(v=office.12).aspx
822 4
        $documentTextInfo = $this->loadRecordHeader($stream, $pos);
823 4
        if ($documentTextInfo['recVer'] == 0xF && $documentTextInfo['recInstance'] == 0x000 && $documentTextInfo['recType'] == self::RT_ENVIRONMENT) {
824 4
            $pos += 8;
825
            //@link : http://msdn.microsoft.com/en-us/library/dd952717(v=office.12).aspx
826 4
            $kinsoku = $this->loadRecordHeader($stream, $pos);
827 4
            if ($kinsoku['recVer'] == 0xF && $kinsoku['recInstance'] == 0x002 && $kinsoku['recType'] == self::RT_KINSOKU) {
828 4
                $pos += 8;
829 4
                $pos += $kinsoku['recLen'];
830
            }
831
832
            //@link : http://msdn.microsoft.com/en-us/library/dd948152(v=office.12).aspx
833 4
            $fontCollection = $this->loadRecordHeader($stream, $pos);
834 4
            if ($fontCollection['recVer'] == 0xF && $fontCollection['recInstance'] == 0x000 && $fontCollection['recType'] == self::RT_FONTCOLLECTION) {
835 4
                $pos += 8;
836
                do {
837 4
                    $fontEntityAtom = $this->loadRecordHeader($stream, $pos);
838 4
                    $pos += 8;
839 4
                    $fontCollection['recLen'] -= 8;
840 4
                    if ($fontEntityAtom['recVer'] != 0x0 || $fontEntityAtom['recInstance'] > 128 || $fontEntityAtom['recType'] != self::RT_FONTENTITYATOM) {
841
                        throw new \Exception('File PowerPoint 97 in error (Location : RTDocument > RT_Environment > RT_FontCollection > RT_FontEntityAtom).');
842
                    }
843 4
                    $string = '';
844 4
                    for ($inc = 0; $inc < 32; $inc++) {
845 4
                        $char = self::getInt2d($stream, $pos);
846 4
                        $pos += 2;
847 4
                        $fontCollection['recLen'] -= 2;
848 4
                        $string .= chr($char);
849
                    }
850 4
                    $this->arrayFonts[] = $string;
851
852
                    // lfCharSet (1 byte)
853 4
                    $pos += 1;
854 4
                    $fontCollection['recLen'] -= 1;
855
856
                    // fEmbedSubsetted (1 bit)
857
                    // unused (7 bits)
858 4
                    $pos += 1;
859 4
                    $fontCollection['recLen'] -= 1;
860
861
                    // rasterFontType (1 bit)
862
                    // deviceFontType (1 bit)
863
                    // truetypeFontType (1 bit)
864
                    // fNoFontSubstitution (1 bit)
865
                    // reserved (4 bits)
866 4
                    $pos += 1;
867 4
                    $fontCollection['recLen'] -= 1;
868
869
                    // lfPitchAndFamily (1 byte)
870 4
                    $pos += 1;
871 4
                    $fontCollection['recLen'] -= 1;
872
873 4
                    $fontEmbedData1 = $this->loadRecordHeader($stream, $pos);
874 4
                    if ($fontEmbedData1['recVer'] == 0x0 && $fontEmbedData1['recInstance'] >= 0x000 && $fontEmbedData1['recInstance'] <= 0x003 && $fontEmbedData1['recType'] == self::RT_FONTEMBEDDATABLOB) {
875
                        $pos += 8;
876
                        $fontCollection['recLen'] -= 8;
877
                        $pos += $fontEmbedData1['recLen'];
878
                        $fontCollection['recLen'] -= $fontEmbedData1['recLen'];
879
                    }
880
881 4
                    $fontEmbedData2 = $this->loadRecordHeader($stream, $pos);
882 4
                    if ($fontEmbedData2['recVer'] == 0x0 && $fontEmbedData2['recInstance'] >= 0x000 && $fontEmbedData2['recInstance'] <= 0x003 && $fontEmbedData2['recType'] == self::RT_FONTEMBEDDATABLOB) {
883
                        $pos += 8;
884
                        $fontCollection['recLen'] -= 8;
885
                        $pos += $fontEmbedData2['recLen'];
886
                        $fontCollection['recLen'] -= $fontEmbedData2['recLen'];
887
                    }
888
889 4
                    $fontEmbedData3 = $this->loadRecordHeader($stream, $pos);
890 4
                    if ($fontEmbedData3['recVer'] == 0x0 && $fontEmbedData3['recInstance'] >= 0x000 && $fontEmbedData3['recInstance'] <= 0x003 && $fontEmbedData3['recType'] == self::RT_FONTEMBEDDATABLOB) {
891
                        $pos += 8;
892
                        $fontCollection['recLen'] -= 8;
893
                        $pos += $fontEmbedData3['recLen'];
894
                        $fontCollection['recLen'] -= $fontEmbedData3['recLen'];
895
                    }
896
897 4
                    $fontEmbedData4 = $this->loadRecordHeader($stream, $pos);
898 4
                    if ($fontEmbedData4['recVer'] == 0x0 && $fontEmbedData4['recInstance'] >= 0x000 && $fontEmbedData4['recInstance'] <= 0x003 && $fontEmbedData4['recType'] == self::RT_FONTEMBEDDATABLOB) {
899
                        $pos += 8;
900
                        $fontCollection['recLen'] -= 8;
901
                        $pos += $fontEmbedData4['recLen'];
902
                        $fontCollection['recLen'] -= $fontEmbedData4['recLen'];
903
                    }
904 4
                } while ($fontCollection['recLen'] > 0);
905
            }
906
907 4
            $textCFDefaultsAtom = $this->loadRecordHeader($stream, $pos);
908 4
            if ($textCFDefaultsAtom['recVer'] == 0x0 && $textCFDefaultsAtom['recInstance'] == 0x000 && $textCFDefaultsAtom['recType'] == self::RT_TEXTCHARFORMATEXCEPTIONATOM) {
909 4
                $pos += 8;
910 4
                $pos += $textCFDefaultsAtom['recLen'];
911
            }
912
913 4
            $textPFDefaultsAtom = $this->loadRecordHeader($stream, $pos);
914 4
            if ($textPFDefaultsAtom['recVer'] == 0x0 && $textPFDefaultsAtom['recInstance'] == 0x000 && $textPFDefaultsAtom['recType'] == self::RT_TEXTPARAGRAPHFORMATEXCEPTIONATOM) {
915
                $pos += 8;
916
                $pos += $textPFDefaultsAtom['recLen'];
917
            }
918
919 4
            $defaultRulerAtom = $this->loadRecordHeader($stream, $pos);
920 4
            if ($defaultRulerAtom['recVer'] == 0x0 && $defaultRulerAtom['recInstance'] == 0x000 && $defaultRulerAtom['recType'] == self::RT_DEFAULTRULERATOM) {
921
                $pos += 8;
922
                $pos += $defaultRulerAtom['recLen'];
923
            }
924
925 4
            $textSIDefaultsAtom = $this->loadRecordHeader($stream, $pos);
926 4
            if ($textSIDefaultsAtom['recVer'] == 0x0 && $textSIDefaultsAtom['recInstance'] == 0x000 && $textSIDefaultsAtom['recType'] == self::RT_TEXTSPECIALINFODEFAULTATOM) {
927 4
                $pos += 8;
928 4
                $pos += $textSIDefaultsAtom['recLen'];
929
            }
930
931 4
            $textMasterStyleAtom = $this->loadRecordHeader($stream, $pos);
932 4
            if ($textMasterStyleAtom['recVer'] == 0x0 && $textMasterStyleAtom['recType'] == self::RT_TEXTMASTERSTYLEATOM) {
933 4
                $pos += 8;
934 4
                $pos += $textMasterStyleAtom['recLen'];
935
            }
936
        }
937
938 4
        $soundCollection = $this->loadRecordHeader($stream, $pos);
939 4
        if ($soundCollection['recVer'] == 0xF && $soundCollection['recInstance'] == 0x005 && $soundCollection['recType'] == self::RT_SOUNDCOLLECTION) {
940
            $pos += 8;
941
            $pos += $soundCollection['recLen'];
942
        }
943
944 4
        $drawingGroup = $this->loadRecordHeader($stream, $pos);
945 4
        if ($drawingGroup['recVer'] == 0xF && $drawingGroup['recInstance'] == 0x000 && $drawingGroup['recType'] == self::RT_DRAWINGGROUP) {
946 4
            $drawing = $this->readRecordDrawingGroupContainer($stream, $pos);
947 4
            $pos += 8;
948 4
            $pos += $drawing['length'];
949
        }
950
951 4
        $masterList = $this->loadRecordHeader($stream, $pos);
952 4
        if ($masterList['recVer'] == 0xF && $masterList['recInstance'] == 0x001 && $masterList['recType'] == self::RT_SLIDELISTWITHTEXT) {
953
            $pos += 8;
954
            $pos += $masterList['recLen'];
955
        }
956
957 4
        $docInfoList = $this->loadRecordHeader($stream, $pos);
958 4
        if ($docInfoList['recVer'] == 0xF && $docInfoList['recInstance'] == 0x000 && $docInfoList['recType'] == self::RT_LIST) {
959
            $pos += 8;
960
            $pos += $docInfoList['recLen'];
961
        }
962
963 4
        $slideHF = $this->loadRecordHeader($stream, $pos);
964 4
        if ($slideHF['recVer'] == 0xF && $slideHF['recInstance'] == 0x003 && $slideHF['recType'] == self::RT_HEADERSFOOTERS) {
965
            $pos += 8;
966
            $pos += $slideHF['recLen'];
967
        }
968
969 4
        $notesHF = $this->loadRecordHeader($stream, $pos);
970 4
        if ($notesHF['recVer'] == 0xF && $notesHF['recInstance'] == 0x004 && $notesHF['recType'] == self::RT_HEADERSFOOTERS) {
971
            $pos += 8;
972
            $pos += $notesHF['recLen'];
973
        }
974
975
        // SlideListWithTextContainer
976 4
        $slideList = $this->loadRecordHeader($stream, $pos);
977 4
        if ($slideList['recVer'] == 0xF && $slideList['recInstance'] == 0x000 && $slideList['recType'] == self::RT_SLIDELISTWITHTEXT) {
978
            $pos += 8;
979
            do {
980
                // SlideListWithTextSubContainerOrAtom
981
                $rhSlideList = $this->loadRecordHeader($stream, $pos);
982
                if ($rhSlideList['recVer'] == 0x0 && $rhSlideList['recInstance'] == 0x000 && $rhSlideList['recType'] == self::RT_SLIDEPERSISTATOM && $rhSlideList['recLen'] == 0x00000014) {
983
                    $pos += 8;
984
                    $slideList['recLen'] -= 8;
985
                    // persistIdRef
986
                    $pos += 4;
987
                    $slideList['recLen'] -= 4;
988
                    // reserved1 - fShouldCollapse - fNonOutlineData - reserved2
989
                    $pos += 4;
990
                    $slideList['recLen'] -= 4;
991
                    // cTexts
992
                    $pos += 4;
993
                    $slideList['recLen'] -= 4;
994
                    // slideId
995
                    $slideId = self::getInt4d($stream, $pos);
996
                    if ($slideId == -2147483648) {
997
                        $slideId = 0;
998
                    }
999
                    if ($slideId > 0) {
1000
                        $this->arrayNotes[$this->oPhpPresentation->getActiveSlideIndex()] = $slideId;
1001
                    }
1002
                    $pos += 4;
1003
                    $slideList['recLen'] -= 4;
1004
                    // reserved3
1005
                    $pos += 4;
1006
                    $slideList['recLen'] -= 4;
1007
                }
1008
            } while ($slideList['recLen'] > 0);
1009
        }
1010 4
    }
1011
1012
    /**
1013
     * An atom record that specifies information about a slide.
1014
     * @param string $stream
1015
     * @param integer $pos
1016
     * @return array
1017
     * @throws \Exception
1018
     * @link https://msdn.microsoft.com/en-us/library/dd923801(v=office.12).aspx
1019
     */
1020 4
    private function readRecordDrawingContainer($stream, $pos)
1021
    {
1022
        $arrayReturn = array(
1023 4
            'length' => 0,
1024
        );
1025
1026 4
        $data = $this->loadRecordHeader($stream, $pos);
1027 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_DRAWING) {
1028
            // Record Header
1029 4
            $arrayReturn['length'] += 8;
1030
1031 4
            $officeArtDg = $this->readRecordOfficeArtDgContainer($stream, $pos + $arrayReturn['length']);
1032 4
            $arrayReturn['length'] += $officeArtDg['length'];
1033
        }
1034 4
        return $arrayReturn;
1035
    }
1036
1037 4
    private function readRecordDrawingGroupContainer($stream, $pos)
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
1038
    {
1039
1040
        $arrayReturn = array(
1041 4
            'length' => 0,
1042
        );
1043
1044 4
        $data = $this->loadRecordHeader($stream, $pos);
1045 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_DRAWINGGROUP) {
1046
            // Record Header
1047 4
            $arrayReturn['length'] += 8;
1048 4
            $arrayReturn['length'] += $data['recLen'];
1049
        }
1050 4
        return $arrayReturn;
1051
    }
1052
1053
    /**
1054
     * An atom record that specifies a reference to an external object.
1055
     * @param string $stream
1056
     * @param integer $pos
1057
     * @return array
1058
     * @link https://msdn.microsoft.com/en-us/library/dd910388(v=office.12).aspx
1059
     */
1060 4
    private function readRecordExObjRefAtom($stream, $pos)
1061
    {
1062
        $arrayReturn = array(
1063 4
            'length' => 0,
1064
        );
1065
1066 4
        $data = $this->loadRecordHeader($stream, $pos);
1067 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_EXTERNALOBJECTREFATOM && $data['recLen'] == 0x00000004) {
1068
            // Record Header
1069
            $arrayReturn['length'] += 8;
1070
            // Datas
1071
            $arrayReturn['length'] += $data['recLen'];
1072
        }
1073
1074 4
        return $arrayReturn;
1075
    }
1076
1077
    /**
1078
     * An atom record that specifies a type of action to be performed.
1079
     * @param string $stream
1080
     * @param integer $pos
1081
     * @return array
1082
     * @link https://msdn.microsoft.com/en-us/library/dd953300(v=office.12).aspx
1083
     */
1084 1
    private function readRecordInteractiveInfoAtom($stream, $pos)
1085
    {
1086
        $arrayReturn = array(
1087 1
            'length' => 0,
1088
        );
1089
1090 1
        $data = $this->loadRecordHeader($stream, $pos);
1091 1
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_INTERACTIVEINFOATOM && $data['recLen'] == 0x00000010) {
1092
            // Record Header
1093 1
            $arrayReturn['length'] += 8;
1094
            // soundIdRef
1095 1
            $arrayReturn['length'] += 4;
1096
            // exHyperlinkIdRef
1097 1
            $arrayReturn['exHyperlinkIdRef'] = self::getInt4d($stream, $pos + $arrayReturn['length']);
1098 1
            $arrayReturn['length'] += 4;
1099
            // action
1100 1
            $arrayReturn['length'] += 1;
1101
            // oleVerb
1102 1
            $arrayReturn['length'] += 1;
1103
            // jump
1104 1
            $arrayReturn['length'] += 1;
1105
            // fAnimated (1 bit)
1106
            // fStopSound (1 bit)
1107
            // fCustomShowReturn (1 bit)
1108
            // fVisited (1 bit)
1109
            // reserved (4 bits)
1110 1
            $arrayReturn['length'] += 1;
1111
            // hyperlinkType
1112 1
            $arrayReturn['length'] += 1;
1113
            // unused
1114 1
            $arrayReturn['length'] += 3;
1115
        }
1116
1117 1
        return $arrayReturn;
1118
    }
1119
1120
    /**
1121
     * An atom record that specifies the name of a macro, a file name, or a named show.
1122
     * @param string $stream
1123
     * @param integer $pos
1124
     * @return array
1125
     * @link https://msdn.microsoft.com/en-us/library/dd925121(v=office.12).aspx
1126
     */
1127 1
    private function readRecordMacroNameAtom($stream, $pos)
1128
    {
1129
        $arrayReturn = array(
1130 1
            'length' => 0,
1131
        );
1132
1133 1
        $data = $this->loadRecordHeader($stream, $pos);
1134 1
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x002 && $data['recType'] == self::RT_CSTRING && $data['recLen'] % 2 == 0) {
1135
            // Record Header
1136
            $arrayReturn['length'] += 8;
1137
            // Datas
1138
            $arrayReturn['length'] += $data['recLen'];
1139
        }
1140
1141 1
        return $arrayReturn;
1142
    }
1143
1144
    /**
1145
     * A container record that specifies what actions to perform when interacting with an object by means of a mouse click.
1146
     * @param string $stream
1147
     * @param integer $pos
1148
     * @return array
1149
     * @link https://msdn.microsoft.com/en-us/library/dd952348(v=office.12).aspx
1150
     */
1151 4
    private function readRecordMouseClickInteractiveInfoContainer($stream, $pos)
1152
    {
1153
        $arrayReturn = array(
1154 4
            'length' => 0,
1155
        );
1156
1157 4
        $data = $this->loadRecordHeader($stream, $pos);
1158 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_INTERACTIVEINFO) {
1159
            // Record Header
1160 1
            $arrayReturn['length'] += 8;
1161
            // interactiveInfoAtom
1162 1
            $interactiveInfoAtom = $this->readRecordInteractiveInfoAtom($stream, $pos + $arrayReturn['length']);
1163 1
            $arrayReturn['length'] += $interactiveInfoAtom['length'];
1164 1
            if ($interactiveInfoAtom['length'] > 0) {
1165 1
                $arrayReturn['exHyperlinkIdRef'] = $interactiveInfoAtom['exHyperlinkIdRef'];
1166
            }
1167
            // macroNameAtom
1168 1
            $macroNameAtom = $this->readRecordMacroNameAtom($stream, $pos + $arrayReturn['length']);
1169 1
            $arrayReturn['length'] += $macroNameAtom['length'];
1170
        }
1171
1172 4
        return $arrayReturn;
1173
    }
1174
1175
    /**
1176
     * A container record that specifies what actions to perform when interacting with an object by moving the mouse cursor over it.
1177
     * @param string $stream
1178
     * @param integer $pos
1179
     * @return array
1180
     * @throws \Exception
1181
     * @link https://msdn.microsoft.com/en-us/library/dd925811(v=office.12).aspx
1182
     */
1183 4
    private function readRecordMouseOverInteractiveInfoContainer($stream, $pos)
1184
    {
1185
        $arrayReturn = array(
1186 4
            'length' => 0,
1187
        );
1188
1189 4
        $data = $this->loadRecordHeader($stream, $pos);
1190 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x001 && $data['recType'] == self::RT_INTERACTIVEINFO) {
1191
            // Record Header
1192
            $arrayReturn['length'] += 8;
1193
            // interactiveInfoAtom
1194
            // macroNameAtom
1195
            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
1196
        }
1197
1198 4
        return $arrayReturn;
1199
    }
1200
1201
    /**
1202
     * The OfficeArtBlip record specifies BLIP file data.
1203
     * @param string $stream
1204
     * @param integer $pos
1205
     * @return array
1206
     * @throws \Exception
1207
     * @link https://msdn.microsoft.com/en-us/library/dd910081(v=office.12).aspx
1208
     */
1209 4
    private function readRecordOfficeArtBlip($stream, $pos)
1210
    {
1211
        $arrayReturn = array(
1212 4
            'length' => 0,
1213
            'picture' => null
1214
        );
1215
1216 4
        $data = $this->loadRecordHeader($stream, $pos);
1217 4
        if ($data['recVer'] == 0x0 && ($data['recType'] >= 0xF018 && $data['recType'] <= 0xF117)) {
1218
            // Record Header
1219 4
            $arrayReturn['length'] += 8;
1220
            // Datas
1221 4
            switch ($data['recType']) {
1222 4
                case self::OFFICEARTBLIPJPG:
1223 3
                case self::OFFICEARTBLIPPNG:
1224
                    // rgbUid1
1225 4
                    $arrayReturn['length'] += 16;
1226 4
                    $data['recLen'] -= 16;
1227 4
                    if ($data['recInstance'] == 0x6E1) {
1228
                        // rgbUid2
1229
                        $arrayReturn['length'] += 16;
1230
                        $data['recLen'] -= 16;
1231
                    }
1232
                    // tag
1233 4
                    $arrayReturn['length'] += 1;
1234 4
                    $data['recLen'] -= 1;
1235
                    // BLIPFileData
1236 4
                    $arrayReturn['picture'] = substr($this->streamPictures, $pos + $arrayReturn['length'], $data['recLen']);
1237 4
                    $arrayReturn['length'] += $data['recLen'];
1238 4
                    break;
1239
                default:
1240
                    throw new \Exception('Feature not implemented (l.'.__LINE__.' : '.dechex($data['recType'].')'));
1241
            }
1242
        }
1243
1244 4
        return $arrayReturn;
1245
    }
1246
1247
    /**
1248
     * The OfficeArtChildAnchor record specifies four signed integers that specify the anchor for the shape that contains this record.
1249
     * @param string $stream
1250
     * @param integer $pos
1251
     * @return array
1252
     * @link https://msdn.microsoft.com/en-us/library/dd922720(v=office.12).aspx
1253
     */
1254 4
    private function readRecordOfficeArtChildAnchor($stream, $pos)
1255
    {
1256
        $arrayReturn = array(
1257 4
            'length' => 0
1258
        );
1259
1260 4
        $data = $this->loadRecordHeader($stream, $pos);
1261 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == 0xF00F && $data['recLen'] == 0x00000010) {
1262
            // Record Header
1263
            $arrayReturn['length'] += 8;
1264
            // Datas
1265
            $arrayReturn['left'] = (int) self::getInt4d($stream, $pos + $arrayReturn['length']);
1266
            $arrayReturn['length'] += 4;
1267
            $arrayReturn['top'] = (int) self::getInt4d($stream, $pos + $arrayReturn['length']);
1268
            $arrayReturn['length'] += 4;
1269
            $arrayReturn['width'] = (int) self::getInt4d($stream, $pos + $arrayReturn['length']) - $arrayReturn['left'];
1270
            $arrayReturn['length'] += 4;
1271
            $arrayReturn['height'] = (int) self::getInt4d($stream, $pos + $arrayReturn['length']) - $arrayReturn['top'];
1272
            $arrayReturn['length'] += 4;
1273
        }
1274
1275 4
        return $arrayReturn;
1276
    }
1277
1278
    /**
1279
     * An atom record that specifies the location of a shape.
1280
     * @param string $stream
1281
     * @param integer $pos
1282
     * @return array
1283
     * @throws \Exception
1284
     * @link https://msdn.microsoft.com/en-us/library/dd922797(v=office.12).aspx
1285
     */
1286 4
    private function readRecordOfficeArtClientAnchor($stream, $pos)
1287
    {
1288
        $arrayReturn = array(
1289 4
            'length' => 0
1290
        );
1291
1292 4
        $data = $this->loadRecordHeader($stream, $pos);
1293 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == 0xF010 && ($data['recLen'] == 0x00000008 || $data['recLen'] == 0x00000010)) {
1294
            // Record Header
1295 4
            $arrayReturn['length'] += 8;
1296
            // Datas
1297 4
            switch ($data['recLen']) {
1298 4
                case 0x00000008:
1299 4
                    $arrayReturn['top'] = (int) (self::getInt2d($stream, $pos + $arrayReturn['length']) / 6);
1300 4
                    $arrayReturn['length'] += 2;
1301 4
                    $arrayReturn['left'] = (int) (self::getInt2d($stream, $pos + $arrayReturn['length']) / 6);
1302 4
                    $arrayReturn['length'] += 2;
1303 4
                    $arrayReturn['width'] = (int) (self::getInt2d($stream, $pos + $arrayReturn['length']) / 6) - $arrayReturn['left'];
1304 4
                    $arrayReturn['length'] += 2;
1305 4
                    $arrayReturn['height'] = (int) (self::getInt2d($stream, $pos + $arrayReturn['length']) / 6) - $arrayReturn['left'];
1306 4
                    $arrayReturn['length'] += 2;
1307 4
                    $pos += 8;
1308 4
                    break;
1309
                case 0x00000010:
1310
                    throw new \Exception('PowerPoint97 Reader : record OfficeArtClientAnchor (0x00000010)');
1311
            }
1312
        }
1313
1314 4
        return $arrayReturn;
1315
    }
1316
1317
    /**
1318
     * A container record that specifies text related data for a shape.
1319
     * @param string $stream
1320
     * @param integer $pos
1321
     * @return array
1322
     * @throws \Exception
1323
     * @link https://msdn.microsoft.com/en-us/library/dd910958(v=office.12).aspx
1324
     */
1325 4
    private function readRecordOfficeArtClientTextbox($stream, $pos)
1326
    {
1327
        $arrayReturn = array(
1328 4
            'length' => 0,
1329
            'text' => '',
1330
            'numParts' => 0,
1331
            'numTexts' => 0,
1332
            'hyperlink' => array(),
1333
        );
1334
1335 4
        $data = $this->loadRecordHeader($stream, $pos);
1336
        // recVer 0xF
1337
        // Doc : 0x0    https://msdn.microsoft.com/en-us/library/dd910958(v=office.12).aspx
1338
        // Sample : 0xF https://msdn.microsoft.com/en-us/library/dd953497(v=office.12).aspx
1339 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == 0xF00D) {
1340
            // Record Header
1341 4
            $arrayReturn['length'] += 8;
1342
            // Datas
1343 4
            $strLen = 0;
1344
            do {
1345 4
                $rhChild = $this->loadRecordHeader($stream, $pos + $arrayReturn['length']);
1346
                /**
1347
                 * @link : https://msdn.microsoft.com/en-us/library/dd947039(v=office.12).aspx
1348
                 */
1349
                // echo dechex($rhChild['recType']).'-'.$rhChild['recType'].EOL;
1350 4
                switch ($rhChild['recType']) {
1351 4
                    case self::RT_INTERACTIVEINFO:
1352
                        //@link : http://msdn.microsoft.com/en-us/library/dd948623(v=office.12).aspx
1353 1
                        if ($rhChild['recInstance'] == 0x0000) {
1354 1
                            $mouseClickInfo = $this->readRecordMouseClickInteractiveInfoContainer($stream, $pos + $arrayReturn['length']);
1355 1
                            $arrayReturn['length'] += $mouseClickInfo['length'];
1356 1
                            $arrayReturn['hyperlink'][]['id'] = $mouseClickInfo['exHyperlinkIdRef'];
1357
                        }
1358 1
                        if ($rhChild['recInstance'] == 0x0001) {
1359
                            $mouseOverInfo = $this->readRecordMouseOverInteractiveInfoContainer($stream, $pos + $arrayReturn['length']);
1360
                            $arrayReturn['length'] += $mouseOverInfo['length'];
1361
                        }
1362 1
                        break;
1363 4
                    case self::RT_STYLETEXTPROPATOM:
1364 4
                        $arrayReturn['length'] += 8;
1365
                        // @link : http://msdn.microsoft.com/en-us/library/dd950647(v=office.12).aspx
1366
                        // rgTextPFRun
1367 4
                        $strLenRT = $strLen + 1;
1368
                        do {
1369 4
                            $strucTextPFRun = $this->readStructureTextPFRun($stream, $pos + $arrayReturn['length'], $strLenRT);
1370 4
                            $arrayReturn['numTexts']++;
1371 4
                            $arrayReturn['text'.$arrayReturn['numTexts']] = $strucTextPFRun;
1372 4
                            if (isset($strucTextPFRun['alignH'])) {
1373 4
                                $arrayReturn['alignH'] = $strucTextPFRun['alignH'];
1374
                            }
1375 4
                            $strLenRT = $strucTextPFRun['strLenRT'];
1376 4
                            $arrayReturn['length'] += $strucTextPFRun['length'];
1377 4
                        } while ($strLenRT > 0);
1378
                        // rgTextCFRun
1379 4
                        $strLenRT = $strLen + 1;
1380
                        do {
1381 4
                            $strucTextCFRun = $this->readStructureTextCFRun($stream, $pos + $arrayReturn['length'], $strLenRT);
1382 4
                            $arrayReturn['numParts']++;
1383 4
                            $arrayReturn['part'.$arrayReturn['numParts']] = $strucTextCFRun;
1384 4
                            $strLenRT = $strucTextCFRun['strLenRT'];
1385 4
                            $arrayReturn['length'] += $strucTextCFRun['length'];
1386 4
                        } while ($strLenRT > 0);
1387 4
                        break;
1388 4
                    case self::RT_TEXTBYTESATOM:
1389
                        $arrayReturn['length'] += 8;
1390
                        // @link : https://msdn.microsoft.com/en-us/library/dd947905(v=office.12).aspx
1391
                        $strLen = (int)$rhChild['recLen'];
1392
                        for ($inc = 0; $inc < $strLen; $inc++) {
1393
                            $char = self::getInt1d($stream, $pos + $arrayReturn['length']);
1394
                            if ($char == 0x0B) {
1395
                                $char = 0x20;
1396
                            }
1397
                            $arrayReturn['text'] .= Text::chr($char);
1398
                            $arrayReturn['length'] += 1;
1399
                        }
1400
                        break;
1401 4
                    case self::RT_TEXTCHARSATOM:
1402 4
                        $arrayReturn['length'] += 8;
1403
                        // @link : http://msdn.microsoft.com/en-us/library/dd772921(v=office.12).aspx
1404 4
                        $strLen = (int)($rhChild['recLen']/2);
1405 4
                        for ($inc = 0; $inc < $strLen; $inc++) {
1406 4
                            $char = self::getInt2d($stream, $pos + $arrayReturn['length']);
1407 4
                            if ($char == 0x0B) {
1408 1
                                $char = 0x20;
1409
                            }
1410 4
                            $arrayReturn['text'] .= Text::chr($char);
1411 4
                            $arrayReturn['length'] += 2;
1412
                        }
1413 4
                        break;
1414 4
                    case self::RT_TEXTHEADERATOM:
1415 4
                        $arrayReturn['length'] += 8;
1416
                        // @link : http://msdn.microsoft.com/en-us/library/dd905272(v=office.12).aspx
1417
                        // textType
1418 4
                        $arrayReturn['length'] += 4;
1419 4
                        break;
1420 4
                    case self::RT_TEXTINTERACTIVEINFOATOM:
1421 1
                        $arrayReturn['length'] += 8;
1422
                        //@link : http://msdn.microsoft.com/en-us/library/dd947973(v=office.12).aspx
1423 1
                        if ($rhChild['recInstance'] == 0x0000) {
1424
                            //@todo : MouseClickTextInteractiveInfoAtom
1425 1
                            $arrayReturn['hyperlink'][count($arrayReturn['hyperlink']) - 1]['start'] = self::getInt4d($stream, $pos +  + $arrayReturn['length']);
1426 1
                            $arrayReturn['length'] += 4;
1427
1428 1
                            $arrayReturn['hyperlink'][count($arrayReturn['hyperlink']) - 1]['end'] = self::getInt4d($stream, $pos +  + $arrayReturn['length']);
1429 1
                            $arrayReturn['length'] += 4;
1430
                        }
1431 1
                        if ($rhChild['recInstance'] == 0x0001) {
1432
                            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
1433
                        }
1434 1
                        break;
1435 4
                    case self::RT_TEXTSPECIALINFOATOM:
1436 4
                        $arrayReturn['length'] += 8;
1437
                        // @link : http://msdn.microsoft.com/en-us/library/dd945296(v=office.12).aspx
1438 4
                        $strLenRT = $strLen + 1;
1439
                        do {
1440 4
                            $structTextSIRun = $this->readStructureTextSIRun($stream, $pos + $arrayReturn['length'], $strLenRT);
1441 4
                            $strLenRT = $structTextSIRun['strLenRT'];
1442 4
                            $arrayReturn['length'] += $structTextSIRun['length'];
1443 4
                        } while ($strLenRT > 0);
1444 4
                        break;
1445 4
                    case self::RT_TEXTRULERATOM:
1446 4
                        $arrayReturn['length'] += 8;
1447
                        // @link : http://msdn.microsoft.com/en-us/library/dd953212(v=office.12).aspx
1448 4
                        $structRuler = $this->readStructureTextRuler($stream, $pos + $arrayReturn['length']);
1449 4
                        $arrayReturn['length'] += $structRuler['length'];
1450 4
                        break;
1451 4
                    case self::RT_SLIDENUMBERMETACHARATOM:
1452 4
                        $datasRecord = $this->readRecordSlideNumberMCAtom($stream, $pos + $arrayReturn['length']);
1453 4
                        $arrayReturn['length'] += $datasRecord['length'];
1454 4
                        break;
1455
                    default:
1456 4
                        $arrayReturn['length'] += 8;
1457 4
                        $arrayReturn['length'] += $rhChild['recLen'];
1458
                    // throw new \Exception('Feature not implemented (l.'.__LINE__.' : 0x'.dechex($rhChild['recType']).')');
1459
                }
1460 4
            } while (($data['recLen'] - $arrayReturn['length']) > 0);
1461
        }
1462 4
        return $arrayReturn;
1463
    }
1464
1465
    /**
1466
     * The OfficeArtSpContainer record specifies a shape container.
1467
     * @param string $stream
1468
     * @param integer $pos
1469
     * @return array
1470
     * @throws \Exception
1471
     * @link https://msdn.microsoft.com/en-us/library/dd943794(v=office.12).aspx
1472
     */
1473 4
    private function readRecordOfficeArtSpContainer($stream, $pos)
1474
    {
1475
        $arrayReturn = array(
1476 4
            'length' => 0,
1477
            'shape' => null,
1478
        );
1479
1480 4
        $data = $this->loadRecordHeader($stream, $pos);
1481 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == 0xF004) {
1482
            // Record Header
1483 4
            $arrayReturn['length'] += 8;
1484
            // shapeGroup
1485 4
            $shapeGroup = $this->readRecordOfficeArtFSPGR($stream, $pos + $arrayReturn['length']);
1486 4
            $arrayReturn['length'] += $shapeGroup['length'];
1487
1488
            // shapeProp
1489 4
            $shapeProp = $this->readRecordOfficeArtFSP($stream, $pos + $arrayReturn['length']);
1490 4
            if ($shapeProp['length'] == 0) {
1491
                throw new \Exception('PowerPoint97 Reader : record OfficeArtFSP');
1492
            }
1493 4
            $arrayReturn['length'] += $shapeProp['length'];
1494
1495 4
            if ($shapeProp['fDeleted'] == 0x1 && $shapeProp['fChild'] == 0x0) {
1496
                // deletedShape
1497
                $deletedShape = $this->readRecordOfficeArtFPSPL($stream, $pos + $arrayReturn['length']);
1498
                $arrayReturn['length'] += $deletedShape['length'];
1499
            }
1500
1501
            // shapePrimaryOptions
1502 4
            $shpPrimaryOptions = $this->readRecordOfficeArtFOPT($stream, $pos + $arrayReturn['length']);
1503 4
            $arrayReturn['length'] += $shpPrimaryOptions['length'];
1504
1505
            // shapeSecondaryOptions1
1506 4
            $shpSecondaryOptions1 = $this->readRecordOfficeArtSecondaryFOPT($stream, $pos + $arrayReturn['length']);
1507 4
            $arrayReturn['length'] += $shpSecondaryOptions1['length'];
1508
1509
            // shapeTertiaryOptions1
1510 4
            $shpTertiaryOptions1 = $this->readRecordOfficeArtTertiaryFOPT($stream, $pos + $arrayReturn['length']);
1511 4
            $arrayReturn['length'] += $shpTertiaryOptions1['length'];
1512
1513
            // childAnchor
1514 4
            $childAnchor = $this->readRecordOfficeArtChildAnchor($stream, $pos + $arrayReturn['length']);
1515 4
            $arrayReturn['length'] += $childAnchor['length'];
1516
1517
            // clientAnchor
1518 4
            $clientAnchor = $this->readRecordOfficeArtClientAnchor($stream, $pos + $arrayReturn['length']);
1519 4
            $arrayReturn['length'] += $clientAnchor['length'];
1520
1521
            // clientData
1522 4
            $clientData = $this->readRecordOfficeArtClientData($stream, $pos + $arrayReturn['length']);
1523 4
            $arrayReturn['length'] += $clientData['length'];
1524
1525
            // clientTextbox
1526 4
            $clientTextbox = $this->readRecordOfficeArtClientTextbox($stream, $pos + $arrayReturn['length']);
1527 4
            $arrayReturn['length'] += $clientTextbox['length'];
1528
1529
            // shapeSecondaryOptions2
1530 4
            if ($shpSecondaryOptions1['length'] == 0) {
1531 4
                $shpSecondaryOptions2 = $this->readRecordOfficeArtSecondaryFOPT($stream, $pos + $arrayReturn['length']);
1532 4
                $arrayReturn['length'] += $shpSecondaryOptions2['length'];
1533
            }
1534
1535
            // shapeTertiaryOptions2
1536 4
            if ($shpTertiaryOptions1['length'] == 0) {
1537 4
                $shpTertiaryOptions2 = $this->readRecordOfficeArtTertiaryFOPT($stream, $pos + $arrayReturn['length']);
1538 4
                $arrayReturn['length'] += $shpTertiaryOptions2['length'];
1539
            }
1540
1541
            // Core : Shape
1542
            // Informations about group are not defined
1543 4
            $arrayDimensions = array();
1544 4
            $bIsGroup = false;
1545 4
            if (is_object($this->oCurrentGroup)) {
1546
                if (!$this->bFirstShapeGroup) {
1547
                    if ($clientAnchor['length'] > 0) {
1548
                        // $this->oCurrentGroup->setOffsetX($clientAnchor['left']);
1549
                        // $this->oCurrentGroup->setOffsetY($clientAnchor['top']);
1550
                        // $this->oCurrentGroup->setHeight($clientAnchor['height']);
1551
                        // $this->oCurrentGroup->setWidth($clientAnchor['width']);
1552
                    }
1553
                    $bIsGroup = true;
1554
                    $this->bFirstShapeGroup = true;
1555
                } else {
1556
                    if ($childAnchor['length'] > 0) {
1557
                        $arrayDimensions = $childAnchor;
1558
                    }
1559
                }
1560
            } else {
1561 4
                if ($clientAnchor['length'] > 0) {
1562 4
                    $arrayDimensions = $clientAnchor;
1563
                }
1564
            }
1565 4
            if (!$bIsGroup) {
1566
                // *** Shape ***
1567 4
                if (isset($shpPrimaryOptions['pib'])) {
1568
                    // isDrawing
1569 4
                    $drawingPib = $shpPrimaryOptions['pib'];
1570 4
                    if (isset($this->arrayPictures[$drawingPib - 1])) {
1571 4
                        $gdImage = imagecreatefromstring($this->arrayPictures[$drawingPib - 1]);
1572 4
                        $arrayReturn['shape'] = new Drawing\Gd();
1573 4
                        $arrayReturn['shape']->setImageResource($gdImage);
1574
                    }
1575 4
                } elseif (isset($shpPrimaryOptions['line']) && $shpPrimaryOptions['line']) {
1576
                    // isLine
1577 1
                    $arrayReturn['shape'] = new Line(0, 0, 0, 0);
1578 4
                } elseif ($clientTextbox['length'] > 0) {
1579 4
                    $arrayReturn['shape'] = new RichText();
1580 4
                    if (isset($clientTextbox['alignH'])) {
1581 4
                        $arrayReturn['shape']->getActiveParagraph()->getAlignment()->setHorizontal($clientTextbox['alignH']);
1582
                    }
1583
1584 4
                    $start = 0;
1585 4
                    $lastLevel = -1;
1586 4
                    $lastMarginLeft = 0;
1587 4
                    for ($inc = 1; $inc <= $clientTextbox['numParts']; $inc++) {
1588 4
                        if ($clientTextbox['numParts'] == $clientTextbox['numTexts'] && isset($clientTextbox['text'.$inc])) {
1589 4
                            if (isset($clientTextbox['text'.$inc]['bulletChar'])) {
1590 1
                                $arrayReturn['shape']->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET);
1591 1
                                $arrayReturn['shape']->getActiveParagraph()->getBulletStyle()->setBulletChar($clientTextbox['text'.$inc]['bulletChar']);
1592
                            }
1593
                            // Indent
1594 4
                            $indent = 0;
1595 4
                            if (isset($clientTextbox['text'.$inc]['indent'])) {
1596 1
                                $indent = $clientTextbox['text'.$inc]['indent'];
1597
                            }
1598 4
                            if (isset($clientTextbox['text'.$inc]['leftMargin'])) {
1599 1
                                if ($lastMarginLeft > $clientTextbox['text'.$inc]['leftMargin']) {
1600 1
                                    $lastLevel--;
1601
                                }
1602 1
                                if ($lastMarginLeft < $clientTextbox['text'.$inc]['leftMargin']) {
1603 1
                                    $lastLevel++;
1604
                                }
1605 1
                                $arrayReturn['shape']->getActiveParagraph()->getAlignment()->setLevel($lastLevel);
1606 1
                                $lastMarginLeft = $clientTextbox['text'.$inc]['leftMargin'];
1607
1608 1
                                $arrayReturn['shape']->getActiveParagraph()->getAlignment()->setMarginLeft($clientTextbox['text'.$inc]['leftMargin']);
1609 1
                                $arrayReturn['shape']->getActiveParagraph()->getAlignment()->setIndent($indent - $clientTextbox['text'.$inc]['leftMargin']);
1610
                            }
1611
                        }
1612
                        // Texte
1613 4
                        $sText = substr(isset($clientTextbox['text']) ? $clientTextbox['text'] : '', $start, $clientTextbox['part'.$inc]['partLength']);
1614 4
                        $sHyperlinkURL = '';
1615 4
                        if (empty($sText)) {
1616
                            // Is there a hyperlink ?
1617 1
                            if (isset($clientTextbox['hyperlink']) && is_array($clientTextbox['hyperlink']) && !empty($clientTextbox['hyperlink'])) {
1618 1
                                foreach ($clientTextbox['hyperlink'] as $itmHyperlink) {
1619 1
                                    if ($itmHyperlink['start'] == $start && ($itmHyperlink['end'] - $itmHyperlink['start']) == $clientTextbox['part'.$inc]['partLength']) {
1620 1
                                        $sText = $this->arrayHyperlinks[$itmHyperlink['id']]['text'];
1621 1
                                        $sHyperlinkURL = $this->arrayHyperlinks[$itmHyperlink['id']]['url'];
1622 1
                                        break;
1623
                                    }
1624
                                }
1625
                            }
1626
                        }
1627
                        // New paragraph
1628 4
                        $bCreateParagraph = false;
1629 4
                        if (strpos($sText, "\r") !== false) {
1630 1
                            $bCreateParagraph = true;
1631 1
                            $sText = str_replace("\r", '', $sText);
1632
                        }
1633
                        // TextRun
1634 4
                        $txtRun = $arrayReturn['shape']->createTextRun($sText);
1635 4
                        if (isset($clientTextbox['part'.$inc]['bold'])) {
1636 3
                            $txtRun->getFont()->setBold($clientTextbox['part'.$inc]['bold']);
1637
                        }
1638 4
                        if (isset($clientTextbox['part'.$inc]['italic'])) {
1639 3
                            $txtRun->getFont()->setItalic($clientTextbox['part'.$inc]['italic']);
1640
                        }
1641 4
                        if (isset($clientTextbox['part'.$inc]['underline'])) {
1642 3
                            $txtRun->getFont()->setUnderline($clientTextbox['part'.$inc]['underline']);
1643
                        }
1644 4
                        if (isset($clientTextbox['part'.$inc]['fontName'])) {
1645 4
                            $txtRun->getFont()->setName($clientTextbox['part'.$inc]['fontName']);
1646
                        }
1647 4
                        if (isset($clientTextbox['part'.$inc]['fontSize'])) {
1648 4
                            $txtRun->getFont()->setSize($clientTextbox['part'.$inc]['fontSize']);
1649
                        }
1650 4
                        if (isset($clientTextbox['part'.$inc]['color'])) {
1651 4
                            $txtRun->getFont()->setColor($clientTextbox['part'.$inc]['color']);
1652
                        }
1653
                        // Hyperlink
1654 4
                        if (!empty($sHyperlinkURL)) {
1655 1
                            $txtRun->setHyperlink(new Hyperlink($sHyperlinkURL));
1656
                        }
1657
1658 4
                        $start += $clientTextbox['part'.$inc]['partLength'];
1659 4
                        if ($bCreateParagraph) {
1660 1
                            $arrayReturn['shape']->createParagraph();
1661
                        }
1662
                    }
1663
                }
1664
1665
                // *** Properties ***
1666
                // Dimensions
1667 4
                if ($arrayReturn['shape'] instanceof AbstractShape) {
1668 4
                    if (!empty($arrayDimensions)) {
1669 4
                        $arrayReturn['shape']->setOffsetX($arrayDimensions['left']);
1670 4
                        $arrayReturn['shape']->setOffsetY($arrayDimensions['top']);
1671 4
                        $arrayReturn['shape']->setHeight($arrayDimensions['height']);
1672 4
                        $arrayReturn['shape']->setWidth($arrayDimensions['width']);
1673
                    }
1674
                    // Rotation
1675 4
                    if (isset($shpPrimaryOptions['rotation'])) {
1676
                        $rotation = $shpPrimaryOptions['rotation'];
1677
                        $arrayReturn['shape']->setRotation($rotation);
1678
                    }
1679
                    // Shadow
1680 4
                    if (isset($shpPrimaryOptions['shadowOffsetX']) && isset($shpPrimaryOptions['shadowOffsetY'])) {
1681 3
                        $shadowOffsetX = $shpPrimaryOptions['shadowOffsetX'];
1682 3
                        $shadowOffsetY = $shpPrimaryOptions['shadowOffsetY'];
1683 3
                        if ($shadowOffsetX != 0 && $shadowOffsetX != 0) {
1684 3
                            $arrayReturn['shape']->getShadow()->setVisible(true);
1685 3
                            if ($shadowOffsetX > 0 && $shadowOffsetX == $shadowOffsetY) {
1686 3
                                $arrayReturn['shape']->getShadow()->setDistance($shadowOffsetX)->setDirection(45);
1687
                            }
1688
                        }
1689
                    }
1690
                    // Specific Line
1691 4
                    if ($arrayReturn['shape'] instanceof Line) {
1692 1
                        if (isset($shpPrimaryOptions['lineColor'])) {
1693 1
                            $arrayReturn['shape']->getBorder()->getColor()->setARGB('FF'.$shpPrimaryOptions['lineColor']);
1694
                        }
1695 1
                        if (isset($shpPrimaryOptions['lineWidth'])) {
1696 1
                            $arrayReturn['shape']->setHeight($shpPrimaryOptions['lineWidth']);
1697
                        }
1698
                    }
1699
                    // Specific RichText
1700 4
                    if ($arrayReturn['shape'] instanceof RichText) {
1701 4
                        if (isset($shpPrimaryOptions['insetBottom'])) {
1702 4
                            $arrayReturn['shape']->setInsetBottom($shpPrimaryOptions['insetBottom']);
1703
                        }
1704 4
                        if (isset($shpPrimaryOptions['insetLeft'])) {
1705 4
                            $arrayReturn['shape']->setInsetLeft($shpPrimaryOptions['insetLeft']);
1706
                        }
1707 4
                        if (isset($shpPrimaryOptions['insetRight'])) {
1708 4
                            $arrayReturn['shape']->setInsetRight($shpPrimaryOptions['insetRight']);
1709
                        }
1710 4
                        if (isset($shpPrimaryOptions['insetTop'])) {
1711 4
                            $arrayReturn['shape']->setInsetTop($shpPrimaryOptions['insetTop']);
1712
                        }
1713
                    }
1714
                }
1715
            } else {
1716
                // Rotation
1717
                if (isset($shpPrimaryOptions['rotation'])) {
1718
                    $rotation = $shpPrimaryOptions['rotation'];
1719
                    $this->oCurrentGroup->setRotation($rotation);
1720
                }
1721
            }
1722
        }
1723
1724 4
        return $arrayReturn;
1725
    }
1726
1727
    /**
1728
     * The OfficeArtSpgrContainer record specifies a container for groups of shapes.
1729
     * @param string $stream
1730
     * @param integer $pos
1731
     * @param boolean $bInGroup
1732
     * @return array
1733
     * @throws \Exception
1734
     * @link : https://msdn.microsoft.com/en-us/library/dd910416(v=office.12).aspx
1735
     */
1736 4
    private function readRecordOfficeArtSpgrContainer($stream, $pos, $bInGroup = false)
1737
    {
1738
        $arrayReturn = array(
1739 4
            'length' => 0,
1740
        );
1741
1742 4
        $data = $this->loadRecordHeader($stream, $pos);
1743 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == 0xF003) {
1744 4
            $arrayReturn['length'] += 8;
1745
1746
            do {
1747 4
                $rhFileBlock = $this->loadRecordHeader($stream, $pos + $arrayReturn['length']);
1748 4
                if (!($rhFileBlock['recVer'] == 0xF && $rhFileBlock['recInstance'] == 0x0000 && ($rhFileBlock['recType'] == 0xF003 || $rhFileBlock['recType'] == 0xF004))) {
1749
                    throw new \Exception('PowerPoint97 Reader : readRecordOfficeArtSpgrContainer.');
1750
                }
1751
1752 4
                switch ($rhFileBlock['recType']) {
1753 4
                    case 0xF003:
1754
                        // Core
1755
                        $this->oCurrentGroup = $this->oPhpPresentation->getActiveSlide()->createGroup();
1756
                        $this->bFirstShapeGroup = false;
1757
                        // OfficeArtSpgrContainer
1758
                        $fileBlock = $this->readRecordOfficeArtSpgrContainer($stream, $pos + $arrayReturn['length'], true);
1759
                        $arrayReturn['length'] += $fileBlock['length'];
1760
                        $data['recLen'] -= $fileBlock['length'];
1761
                        break;
1762 4
                    case 0xF004:
1763
                        // Core
1764 4
                        if (!$bInGroup) {
1765 4
                            $this->oCurrentGroup = null;
1766
                        }
1767
                        // OfficeArtSpContainer
1768 4
                        $fileBlock = $this->readRecordOfficeArtSpContainer($stream, $pos + $arrayReturn['length']);
1769 4
                        $arrayReturn['length'] += $fileBlock['length'];
1770 4
                        $data['recLen'] -= $fileBlock['length'];
1771
                        // Core
1772
                        //@todo
1773 4
                        if (!is_null($fileBlock['shape'])) {
1774 4
                            switch ($this->inMainType) {
1775 4
                                case self::RT_NOTES:
1776 4
                                    $arrayIdxSlide = array_flip($this->arrayNotes);
1777 4
                                    if ($this->currentNote > 0 && isset($arrayIdxSlide[$this->currentNote])) {
1778
                                        $oSlide = $this->oPhpPresentation->getSlide($arrayIdxSlide[$this->currentNote]);
1779
                                        if ($oSlide->getNote()->getShapeCollection()->count() == 0) {
1780
                                            $oSlide->getNote()->addShape($fileBlock['shape']);
1781
                                        }
1782
                                    }
1783 4
                                    break;
1784 4
                                case self::RT_SLIDE:
1785 4
                                    if ($bInGroup) {
1786
                                        $this->oCurrentGroup->addShape($fileBlock['shape']);
1787
                                    } else {
1788 4
                                        $this->oPhpPresentation->getActiveSlide()->addShape($fileBlock['shape']);
1789
                                    }
1790 4
                                    break;
1791
                            }
1792
                        }
1793
1794 4
                        break;
1795
                }
1796 4
            } while ($data['recLen'] > 0);
1797
        }
1798 4
        return $arrayReturn;
1799
    }
1800
1801
    /**
1802
     * The OfficeArtTertiaryFOPT record specifies a table of OfficeArtRGFOPTE records,.
1803
     * @param string $stream
1804
     * @param integer $pos
1805
     * @return array
1806
     * @throws \Exception
1807
     * @link https://msdn.microsoft.com/en-us/library/dd950206(v=office.12).aspx
1808
     */
1809 4
    private function readRecordOfficeArtTertiaryFOPT($stream, $pos)
1810
    {
1811
        $arrayReturn = array(
1812 4
            'length' => 0,
1813
        );
1814
1815 4
        $data = $this->loadRecordHeader($stream, $pos);
1816 4
        if ($data['recVer'] == 0x3 && $data['recType'] == 0xF122) {
1817
            // Record Header
1818
            $arrayReturn['length'] += 8;
1819
1820
            $officeArtFOPTE = array();
1821
            for ($inc = 0; $inc < $data['recInstance']; $inc++) {
1822
                $opid = self::getInt2d($this->streamPowerpointDocument, $pos + $arrayReturn['length']);
1823
                $arrayReturn['length'] += 2;
1824
                $optOp = self::getInt4d($this->streamPowerpointDocument, $pos + $arrayReturn['length']);
1825
                $arrayReturn['length'] += 4;
1826
                $officeArtFOPTE[] = array(
1827
                    'opid' => ($opid >> 0) & bindec('11111111111111'),
1828
                    'fBid' => ($opid >> 14) & bindec('1'),
1829
                    'fComplex' => ($opid >> 15) & bindec('1'),
1830
                    'op' => $optOp,
1831
                );
1832
            }
1833
            //@link : http://code.metager.de/source/xref/kde/calligra/filters/libmso/OPID
1834
            foreach ($officeArtFOPTE as $opt) {
1835
                switch ($opt['opid']) {
1836
                    case 0x039F:
1837
                        // Table properties
1838
                        //@link : https://msdn.microsoft.com/en-us/library/dd922773(v=office.12).aspx
1839
                        break;
1840
                    case 0x03A0:
1841
                        // Table Row Properties
1842
                        //@link : https://msdn.microsoft.com/en-us/library/dd923419(v=office.12).aspx
1843
                        if ($opt['fComplex'] == 0x1) {
1844
                            $arrayReturn['length'] += $opt['op'];
1845
                        }
1846
                        break;
1847
                    case 0x03A9:
1848
                        // GroupShape : metroBlob
1849
                        //@link : https://msdn.microsoft.com/en-us/library/dd943388(v=office.12).aspx
1850
                        if ($opt['fComplex'] == 0x1) {
1851
                            $arrayReturn['length'] += $opt['op'];
1852
                        }
1853
                        break;
1854
                    case 0x01FF:
1855
                        // Line Style Boolean
1856
                        //@link : https://msdn.microsoft.com/en-us/library/dd951605(v=office.12).aspx
1857
                        break;
1858
                    default:
1859
                        throw new \Exception('Feature not implemented (l.'.__LINE__.' : 0x'.dechex($opt['opid']).')');
1860
                }
1861
            }
1862
        }
1863 4
        return $arrayReturn;
1864
    }
1865
1866
    /**
1867
     * The OfficeArtDgContainer record specifies the container for all the file records for the objects in a drawing.
1868
     * @param string $stream
1869
     * @param integer $pos
1870
     * @return array
1871
     * @throws \Exception
1872
     * @link : https://msdn.microsoft.com/en-us/library/dd924455(v=office.12).aspx
1873
     */
1874 4
    private function readRecordOfficeArtDgContainer($stream, $pos)
1875
    {
1876
        $arrayReturn = array(
1877 4
            'length' => 0,
1878
        );
1879
1880 4
        $data = $this->loadRecordHeader($stream, $pos);
1881 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == 0xF002) {
1882
            // Record Header
1883 4
            $arrayReturn['length'] += 8;
1884
            // drawingData
1885 4
            $drawingData  = $this->readRecordOfficeArtFDG($stream, $pos + $arrayReturn['length']);
1886 4
            $arrayReturn['length'] += $drawingData['length'];
1887
            // regroupItems
1888
            //@todo
1889
            // groupShape
1890 4
            $groupShape = $this->readRecordOfficeArtSpgrContainer($stream, $pos + $arrayReturn['length']);
1891 4
            $arrayReturn['length'] += $groupShape['length'];
1892
            // shape
1893 4
            $shape = $this->readRecordOfficeArtSpContainer($stream, $pos + $arrayReturn['length']);
1894 4
            $arrayReturn['length'] += $shape['length'];
1895
            // solvers1
1896
            //@todo
1897
            // deletedShapes
1898
            //@todo
1899
            // solvers1
1900
            //@todo
1901
        }
1902
1903 4
        return $arrayReturn;
1904
    }
1905
1906
    /**
1907
     * The OfficeArtFDG record specifies the number of shapes, the drawing identifier, and the shape identifier of the last shape in a drawing.
1908
     * @param string $stream
1909
     * @param integer $pos
1910
     * @return array
1911
     * @link : https://msdn.microsoft.com/en-us/library/dd946757(v=office.12).aspx
1912
     */
1913 4
    private function readRecordOfficeArtFDG($stream, $pos)
1914
    {
1915
        $arrayReturn = array(
1916 4
            'length' => 0,
1917
        );
1918
1919 4
        $data = $this->loadRecordHeader($stream, $pos);
1920 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] <= 0xFFE && $data['recType'] == 0xF008 && $data['recLen'] == 0x00000008) {
1921
            // Record Header
1922 4
            $arrayReturn['length'] += 8;
1923
            // Length
1924 4
            $arrayReturn['length'] += $data['recLen'];
1925
        }
1926
1927 4
        return $arrayReturn;
1928
    }
1929
1930
    /**
1931
     * The OfficeArtFOPT record specifies a table of OfficeArtRGFOPTE records.
1932
     * @param string $stream
1933
     * @param integer $pos
1934
     * @return array
1935
     * @link https://msdn.microsoft.com/en-us/library/dd943404(v=office.12).aspx
1936
     */
1937 4
    private function readRecordOfficeArtFOPT($stream, $pos)
1938
    {
1939
        $arrayReturn = array(
1940 4
            'length' => 0,
1941
        );
1942
1943 4
        $data = $this->loadRecordHeader($stream, $pos);
1944 4
        if ($data['recVer'] == 0x3 && $data['recType'] == 0xF00B) {
1945
            // Record Header
1946 4
            $arrayReturn['length'] += 8;
1947
1948
            //@link : http://msdn.microsoft.com/en-us/library/dd906086(v=office.12).aspx
1949 4
            $officeArtFOPTE = array();
1950 4
            for ($inc = 0; $inc < $data['recInstance']; $inc++) {
1951 4
                $opid = self::getInt2d($this->streamPowerpointDocument, $pos + $arrayReturn['length']);
1952 4
                $arrayReturn['length'] += 2;
1953 4
                $data['recLen'] -= 2;
1954 4
                $optOp = self::getInt4d($this->streamPowerpointDocument, $pos + $arrayReturn['length']);
1955 4
                $arrayReturn['length'] += 4;
1956 4
                $data['recLen'] -= 4;
1957 4
                $officeArtFOPTE[] = array(
1958 4
                    'opid' => ($opid >> 0) & bindec('11111111111111'),
1959 4
                    'fBid' => ($opid >> 14) & bindec('1'),
1960 4
                    'fComplex' => ($opid >> 15) & bindec('1'),
1961 4
                    'op' => $optOp,
1962
                );
1963
            }
1964
            //@link : http://code.metager.de/source/xref/kde/calligra/filters/libmso/OPID
1965 4
            foreach ($officeArtFOPTE as $opt) {
1966
                // echo $opt['opid'].'-0x'.dechex($opt['opid']).EOL;
1967 4
                switch ($opt['opid']) {
1968 4
                    case 0x0004:
1969
                        // Transform : rotation
1970
                        //@link : https://msdn.microsoft.com/en-us/library/dd949750(v=office.12).aspx
1971
                        $arrayReturn['rotation'] = $opt['op'];
1972
                        break;
1973 4
                    case 0x007F:
1974
                        // Transform : Protection Boolean Properties
1975
                        //@link : http://msdn.microsoft.com/en-us/library/dd909131(v=office.12).aspx
1976 4
                        break;
1977 4
                    case 0x0080:
1978
                        // Text : ltxid
1979
                        //@link : http://msdn.microsoft.com/en-us/library/dd947446(v=office.12).aspx
1980 4
                        break;
1981 4
                    case 0x0081:
1982
                        // Text : dxTextLeft
1983
                        //@link : http://msdn.microsoft.com/en-us/library/dd953234(v=office.12).aspx
1984 4
                        $arrayReturn['insetLeft'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']);
1985 4
                        break;
1986 4
                    case 0x0082:
1987
                        // Text : dyTextTop
1988
                        //@link : http://msdn.microsoft.com/en-us/library/dd925068(v=office.12).aspx
1989 4
                        $arrayReturn['insetTop'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']);
1990 4
                        break;
1991 4
                    case 0x0083:
1992
                        // Text : dxTextRight
1993
                        //@link : http://msdn.microsoft.com/en-us/library/dd906782(v=office.12).aspx
1994 4
                        $arrayReturn['insetRight'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']);
1995 4
                        break;
1996 4
                    case 0x0084:
1997
                        // Text : dyTextBottom
1998
                        //@link : http://msdn.microsoft.com/en-us/library/dd772858(v=office.12).aspx
1999 4
                        $arrayReturn['insetBottom'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']);
2000 4
                        break;
2001 4
                    case 0x0085:
2002
                        // Text : WrapText
2003
                        //@link : http://msdn.microsoft.com/en-us/library/dd924770(v=office.12).aspx
2004 4
                        break;
2005 4
                    case 0x0087:
2006
                        // Text : anchorText
2007
                        //@link : http://msdn.microsoft.com/en-us/library/dd948575(v=office.12).aspx
2008 4
                        break;
2009 4
                    case 0x00BF:
2010
                        // Text : Text Boolean Properties
2011
                        //@link : http://msdn.microsoft.com/en-us/library/dd950905(v=office.12).aspx
2012 4
                        break;
2013 4
                    case 0x0104:
2014
                        // Blip : pib
2015
                        //@link : http://msdn.microsoft.com/en-us/library/dd772837(v=office.12).aspx
2016 4
                        if ($opt['fComplex'] == 0) {
2017 4
                            $arrayReturn['pib'] = $opt['op'];
2018 4
                            $data['recLen'] -= $opt['op'];
2019
                        } else {
2020
                            // pib Complex
2021
                        }
2022 4
                        break;
2023 4
                    case 0x13F:
2024
                        // Blip Boolean Properties
2025
                        //@link : https://msdn.microsoft.com/en-us/library/dd944215(v=office.12).aspx
2026
                        break;
2027 4
                    case 0x140:
2028
                        // Geometry : geoLeft
2029
                        //@link : http://msdn.microsoft.com/en-us/library/dd947489(v=office.12).aspx
2030
                        // print_r('geoLeft : '.$opt['op'].EOL);
2031 2
                        break;
2032 4
                    case 0x141:
2033
                        // Geometry : geoTop
2034
                        //@link : http://msdn.microsoft.com/en-us/library/dd949459(v=office.12).aspx
2035
                        // print_r('geoTop : '.$opt['op'].EOL);
2036 2
                        break;
2037 4
                    case 0x142:
2038
                        // Geometry : geoRight
2039
                        //@link : http://msdn.microsoft.com/en-us/library/dd947117(v=office.12).aspx
2040
                        // print_r('geoRight : '.$opt['op'].EOL);
2041 2
                        break;
2042 4
                    case 0x143:
2043
                        // Geometry : geoBottom
2044
                        //@link : http://msdn.microsoft.com/en-us/library/dd948602(v=office.12).aspx
2045
                        // print_r('geoBottom : '.$opt['op'].EOL);
2046 2
                        break;
2047 4
                    case 0x144:
2048
                        // Geometry : shapePath
2049
                        //@link : http://msdn.microsoft.com/en-us/library/dd945249(v=office.12).aspx
2050 1
                        $arrayReturn['line'] = true;
2051 1
                        break;
2052 4
                    case 0x145:
2053
                        // Geometry : pVertices
2054
                        //@link : http://msdn.microsoft.com/en-us/library/dd949814(v=office.12).aspx
2055 2
                        if ($opt['fComplex'] == 1) {
2056 2
                            $arrayReturn['length'] += $opt['op'];
2057 2
                            $data['recLen'] -= $opt['op'];
2058
                        }
2059 2
                        break;
2060 4
                    case 0x146:
2061
                        // Geometry : pSegmentInfo
2062
                        //@link : http://msdn.microsoft.com/en-us/library/dd905742(v=office.12).aspx
2063 2
                        if ($opt['fComplex'] == 1) {
2064 2
                            $arrayReturn['length'] += $opt['op'];
2065 2
                            $data['recLen'] -= $opt['op'];
2066
                        }
2067 2
                        break;
2068 4
                    case 0x155:
2069
                        // Geometry : pAdjustHandles
2070
                        //@link : http://msdn.microsoft.com/en-us/library/dd905890(v=office.12).aspx
2071 2
                        if ($opt['fComplex'] == 1) {
2072 2
                            $arrayReturn['length'] += $opt['op'];
2073 2
                            $data['recLen'] -= $opt['op'];
2074
                        }
2075 2
                        break;
2076 4
                    case 0x156:
2077
                        // Geometry : pGuides
2078
                        //@link : http://msdn.microsoft.com/en-us/library/dd910801(v=office.12).aspx
2079 2
                        if ($opt['fComplex'] == 1) {
2080 2
                            $arrayReturn['length'] += $opt['op'];
2081 2
                            $data['recLen'] -= $opt['op'];
2082
                        }
2083 2
                        break;
2084 4
                    case 0x157:
2085
                        // Geometry : pInscribe
2086
                        //@link : http://msdn.microsoft.com/en-us/library/dd904889(v=office.12).aspx
2087 2
                        if ($opt['fComplex'] == 1) {
2088 2
                            $arrayReturn['length'] += $opt['op'];
2089 2
                            $data['recLen'] -= $opt['op'];
2090
                        }
2091 2
                        break;
2092 4
                    case 0x17F:
2093
                        // Geometry Boolean Properties
2094
                        //@link : http://msdn.microsoft.com/en-us/library/dd944968(v=office.12).aspx
2095 1
                        break;
2096 4
                    case 0x0180:
2097
                        // Fill : fillType
2098
                        //@link : http://msdn.microsoft.com/en-us/library/dd947909(v=office.12).aspx
2099 4
                        break;
2100 4
                    case 0x0181:
2101
                        // Fill : fillColor
2102
                        //@link : http://msdn.microsoft.com/en-us/library/dd921332(v=office.12).aspx
2103 4
                        $strColor = str_pad(dechex(($opt['op'] >> 0) & bindec('11111111')), 2, STR_PAD_LEFT, '0');
2104 4
                        $strColor .= str_pad(dechex(($opt['op'] >> 8) & bindec('11111111')), 2, STR_PAD_LEFT, '0');
2105 4
                        $strColor .= str_pad(dechex(($opt['op'] >> 16) & bindec('11111111')), 2, STR_PAD_LEFT, '0');
2106
                        // echo 'fillColor  : '.$strColor.EOL;
2107 4
                        break;
2108 4
                    case 0x0183:
2109
                        // Fill : fillBackColor
2110
                        //@link : http://msdn.microsoft.com/en-us/library/dd950634(v=office.12).aspx
2111 4
                        $strColor = str_pad(dechex(($opt['op'] >> 0) & bindec('11111111')), 2, STR_PAD_LEFT, '0');
2112 4
                        $strColor .= str_pad(dechex(($opt['op'] >> 8) & bindec('11111111')), 2, STR_PAD_LEFT, '0');
2113 4
                        $strColor .= str_pad(dechex(($opt['op'] >> 16) & bindec('11111111')), 2, STR_PAD_LEFT, '0');
2114
                        // echo 'fillBackColor  : '.$strColor.EOL;
2115 4
                        break;
2116 4
                    case 0x0193:
2117
                        // Fill : fillRectRight
2118
                        //@link : http://msdn.microsoft.com/en-us/library/dd951294(v=office.12).aspx
2119
                        // echo 'fillRectRight  : '.\PhpOffice\Common\Drawing::emuToPixels($opt['op']).EOL;
2120 4
                        break;
2121 4
                    case 0x0194:
2122
                        // Fill : fillRectBottom
2123
                        //@link : http://msdn.microsoft.com/en-us/library/dd910194(v=office.12).aspx
2124
                        // echo 'fillRectBottom   : '.\PhpOffice\Common\Drawing::emuToPixels($opt['op']).EOL;
2125 4
                        break;
2126 4
                    case 0x01BF:
2127
                        // Fill : Fill Style Boolean Properties
2128
                        //@link : http://msdn.microsoft.com/en-us/library/dd909380(v=office.12).aspx
2129 4
                        break;
2130 4
                    case 0x01C0:
2131
                        // Line Style : lineColor
2132
                        //@link : http://msdn.microsoft.com/en-us/library/dd920397(v=office.12).aspx
2133 4
                        $strColor = str_pad(dechex(($opt['op'] >> 0) & bindec('11111111')), 2, STR_PAD_LEFT, '0');
2134 4
                        $strColor .= str_pad(dechex(($opt['op'] >> 8) & bindec('11111111')), 2, STR_PAD_LEFT, '0');
2135 4
                        $strColor .= str_pad(dechex(($opt['op'] >> 16) & bindec('11111111')), 2, STR_PAD_LEFT, '0');
2136 4
                        $arrayReturn['lineColor'] = $strColor;
2137 4
                        break;
2138 4
                    case 0x01C1:
2139
                        // Line Style : lineOpacity
2140
                        //@link : http://msdn.microsoft.com/en-us/library/dd923433(v=office.12).aspx
2141
                        // echo 'lineOpacity : '.dechex($opt['op']).EOL;
2142 4
                        break;
2143 4
                    case 0x01C2:
2144
                        // Line Style : lineBackColor
2145
                        //@link : http://msdn.microsoft.com/en-us/library/dd947669(v=office.12).aspx
2146 4
                        break;
2147 4
                    case 0x01CB:
2148
                        // Line Style : lineWidth
2149
                        //@link : http://msdn.microsoft.com/en-us/library/dd926964(v=office.12).aspx
2150 2
                        $arrayReturn['lineWidth'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']);
2151 2
                        break;
2152 4
                    case 0x01D6:
2153
                        // Line Style : lineJoinStyle
2154
                        //@link : http://msdn.microsoft.com/en-us/library/dd909643(v=office.12).aspx
2155 4
                        break;
2156 4
                    case 0x01D7:
2157
                        // Line Style : lineEndCapStyle
2158
                        //@link : http://msdn.microsoft.com/en-us/library/dd925071(v=office.12).aspx
2159 4
                        break;
2160 4
                    case 0x01FF:
2161
                        // Line Style : Line Style Boolean Properties
2162
                        //@link : http://msdn.microsoft.com/en-us/library/dd951605(v=office.12).aspx
2163 4
                        break;
2164 4
                    case 0x0201:
2165
                        // Shadow Style : shadowColor
2166
                        //@link : http://msdn.microsoft.com/en-us/library/dd923454(v=office.12).aspx
2167 4
                        break;
2168 4
                    case 0x0204:
2169
                        // Shadow Style : shadowOpacity
2170
                        //@link : http://msdn.microsoft.com/en-us/library/dd920720(v=office.12).aspx
2171 3
                        break;
2172 4
                    case 0x0205:
2173
                        // Shadow Style : shadowOffsetX
2174
                        //@link : http://msdn.microsoft.com/en-us/library/dd945280(v=office.12).aspx
2175 3
                        $arrayReturn['shadowOffsetX'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']);
2176 3
                        break;
2177 4
                    case 0x0206:
2178
                        // Shadow Style : shadowOffsetY
2179
                        //@link : http://msdn.microsoft.com/en-us/library/dd907855(v=office.12).aspx
2180 3
                        $arrayReturn['shadowOffsetY'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']);
2181 3
                        break;
2182 4
                    case 0x023F:
2183
                        // Shadow Style : Shadow Style Boolean Properties
2184
                        //@link : http://msdn.microsoft.com/en-us/library/dd947887(v=office.12).aspx
2185 4
                        break;
2186 4
                    case 0x0304:
2187
                        // Shape : bWMode
2188
                        //@link : http://msdn.microsoft.com/en-us/library/dd947659(v=office.12).aspx
2189 4
                        break;
2190 4
                    case 0x033F:
2191
                        // Shape Boolean Properties
2192
                        //@link : http://msdn.microsoft.com/en-us/library/dd951345(v=office.12).aspx
2193 4
                        break;
2194 1
                    case 0x0380:
2195
                        // Group Shape Property Set : wzName
2196
                        //@link : http://msdn.microsoft.com/en-us/library/dd950681(v=office.12).aspx
2197
                        if ($opt['fComplex'] == 1) {
2198
                            $arrayReturn['length'] += $opt['op'];
2199
                            $data['recLen'] -= $opt['op'];
2200
                        }
2201
                        break;
2202 1
                    case 0x03BF:
2203
                        // Group Shape Property Set : Group Shape Boolean Properties
2204
                        //@link : http://msdn.microsoft.com/en-us/library/dd949807(v=office.12).aspx
2205
                        break;
2206
                    default:
2207
                        // throw new \Exception('Feature not implemented (l.'.__LINE__.' : 0x'.dechex($opt['opid']).')');
2208
                }
2209
            }
2210 4
            if ($data['recLen'] > 0) {
2211 2
                $arrayReturn['length'] += $data['recLen'];
2212
            }
2213
        }
2214
2215 4
        return $arrayReturn;
2216
    }
2217
2218
    /**
2219
     * The OfficeArtFPSPL record specifies the former hierarchical position of the containing object that is either a shape or a group of shapes.
2220
     * @param string $stream
2221
     * @param integer $pos
2222
     * @return array
2223
     * @link https://msdn.microsoft.com/en-us/library/dd947479(v=office.12).aspx
2224
     */
2225
    private function readRecordOfficeArtFPSPL($stream, $pos)
2226
    {
2227
        $arrayReturn = array(
2228
            'length' => 0,
2229
        );
2230
2231
        $data = $this->loadRecordHeader($stream, $pos);
2232
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == 0xF11D && $data['recLen'] == 0x00000004) {
2233
            $arrayReturn['length'] += 8;
2234
            $arrayReturn['length'] += $data['recLen'];
2235
        }
2236
2237
        return $arrayReturn;
2238
    }
2239
2240
    /**
2241
     * The OfficeArtFSP record specifies an instance of a shape.
2242
     * @param string $stream
2243
     * @param integer $pos
2244
     * @return array
2245
     * @link https://msdn.microsoft.com/en-us/library/dd925898(v=office.12).aspx
2246
     */
2247 4
    private function readRecordOfficeArtFSP($stream, $pos)
2248
    {
2249
        $arrayReturn = array(
2250 4
            'length' => 0,
2251
        );
2252
2253 4
        $data = $this->loadRecordHeader($stream, $pos);
2254 4
        if ($data['recVer'] == 0x2 && $data['recType'] == 0xF00A && $data['recLen'] == 0x00000008) {
2255 4
            $arrayReturn['length'] += 8;
2256
            // spid
2257 4
            $arrayReturn['length'] += 4;
2258
            // data
2259 4
            $data = self::getInt4d($this->streamPowerpointDocument, $pos + $arrayReturn['length']);
2260 4
            $arrayReturn['length'] += 4;
2261 4
            $arrayReturn['fGroup'] = ($data >> 0) & bindec('1');
2262 4
            $arrayReturn['fChild'] = ($data >> 1) & bindec('1');
2263 4
            $arrayReturn['fPatriarch'] = ($data >> 2) & bindec('1');
2264 4
            $arrayReturn['fDeleted'] = ($data >> 3) & bindec('1');
2265
        }
2266
2267 4
        return $arrayReturn;
2268
    }
2269
2270
    /**
2271
     * The OfficeArtFSPGR record specifies the coordinate system of the group shape that the anchors of the child shape are expressed in.
2272
     * @param string $stream
2273
     * @param integer $pos
2274
     * @return array
2275
     * @link https://msdn.microsoft.com/en-us/library/dd925381(v=office.12).aspx
2276
     */
2277 4
    private function readRecordOfficeArtFSPGR($stream, $pos)
2278
    {
2279
        $arrayReturn = array(
2280 4
            'length' => 0,
2281
        );
2282
2283 4
        $data = $this->loadRecordHeader($stream, $pos);
2284 4
        if ($data['recVer'] == 0x1 && $data['recInstance'] == 0x000 && $data['recType'] == 0xF009 && $data['recLen'] == 0x00000010) {
2285 4
            $arrayReturn['length'] += 8;
2286
            //$arrShapeGroup['xLeft'] = self::getInt4d($this->streamPowerpointDocument, $pos);
2287 4
            $arrayReturn['length'] += 4;
2288
            //$arrShapeGroup['yTop'] = self::getInt4d($this->streamPowerpointDocument, $pos);
2289 4
            $arrayReturn['length'] += 4;
2290
            //$arrShapeGroup['xRight'] = self::getInt4d($this->streamPowerpointDocument, $pos);
2291 4
            $arrayReturn['length'] += 4;
2292
            //$arrShapeGroup['yBottom'] = self::getInt4d($this->streamPowerpointDocument, $pos);
2293 4
            $arrayReturn['length'] += 4;
2294
        }
2295
2296 4
        return $arrayReturn;
2297
    }
2298
2299
    /**
2300
     * The OfficeArtSecondaryFOPT record specifies a table of OfficeArtRGFOPTE records.
2301
     * @param string $stream
2302
     * @param integer $pos
2303
     * @return array
2304
     * @link https://msdn.microsoft.com/en-us/library/dd950259(v=office.12).aspx
2305
     */
2306 4
    private function readRecordOfficeArtSecondaryFOPT($stream, $pos)
2307
    {
2308
        $arrayReturn = array(
2309 4
            'length' => 0,
2310
        );
2311
2312 4
        $data = $this->loadRecordHeader($stream, $pos);
2313 4
        if ($data['recVer'] == 0x3 && $data['recType'] == 0xF121) {
2314
            // Record Header
2315
            $arrayReturn['length'] += 8;
2316
            // Length
2317
            $arrayReturn['length'] += $data['recLen'];
2318
        }
2319 4
        return $arrayReturn;
2320
    }
2321
2322
    /**
2323
     * A container record that specifies information about a shape.
2324
     * @param string $stream
2325
     * @param integer $pos
2326
     * @return array
2327
     * @throws \Exception
2328
     * @link : https://msdn.microsoft.com/en-us/library/dd950927(v=office.12).aspx
2329
     */
2330 4
    private function readRecordOfficeArtClientData($stream, $pos)
2331
    {
2332
        $arrayReturn = array(
2333 4
            'length' => 0,
2334
        );
2335
2336 4
        $data = $this->loadRecordHeader($stream, $pos);
2337 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == 0xF011) {
2338 4
            $arrayReturn['length'] += 8;
2339
            // shapeFlagsAtom (9 bytes)
2340 4
            $dataShapeFlagsAtom = $this->readRecordShapeFlagsAtom($stream, $pos + $arrayReturn['length']);
2341 4
            $arrayReturn['length'] += $dataShapeFlagsAtom['length'];
2342
2343
            // shapeFlags10Atom (9 bytes)
2344 4
            $dataShapeFlags10Atom = $this->readRecordShapeFlags10Atom($stream, $pos + $arrayReturn['length']);
2345 4
            $arrayReturn['length'] += $dataShapeFlags10Atom['length'];
2346
2347
            // exObjRefAtom (12 bytes)
2348 4
            $dataExObjRefAtom = $this->readRecordExObjRefAtom($stream, $pos + $arrayReturn['length']);
2349 4
            $arrayReturn['length'] += $dataExObjRefAtom['length'];
2350
2351
            // animationInfo (variable)
2352 4
            $dataAnimationInfo = $this->readRecordAnimationInfoContainer($stream, $pos + $arrayReturn['length']);
2353 4
            $arrayReturn['length'] += $dataAnimationInfo['length'];
2354
2355
            // mouseClickInteractiveInfo (variable)
2356 4
            $mouseClickInfo = $this->readRecordMouseClickInteractiveInfoContainer($stream, $pos + $arrayReturn['length']);
2357 4
            $arrayReturn['length'] += $mouseClickInfo['length'];
2358
2359
            // mouseOverInteractiveInfo (variable)
2360 4
            $mouseOverInfo = $this->readRecordMouseOverInteractiveInfoContainer($stream, $pos + $arrayReturn['length']);
2361 4
            $arrayReturn['length'] += $mouseOverInfo['length'];
2362
2363
            // placeholderAtom (16 bytes)
2364 4
            $dataPlaceholderAtom = $this->readRecordPlaceholderAtom($stream, $pos + $arrayReturn['length']);
2365 4
            $arrayReturn['length'] += $dataPlaceholderAtom['length'];
2366
2367
            // recolorInfoAtom (variable)
2368 4
            $dataRecolorInfo = $this->readRecordRecolorInfoAtom($stream, $pos + $arrayReturn['length']);
2369 4
            $arrayReturn['length'] += $dataRecolorInfo['length'];
2370
2371
            // rgShapeClientRoundtripData (variable)
2372
            $array = array(
2373 4
                self::RT_PROGTAGS,
2374 4
                self::RT_ROUNDTRIPNEWPLACEHOLDERID12ATOM,
2375 4
                self::RT_ROUNDTRIPSHAPEID12ATOM,
2376 4
                self::RT_ROUNDTRIPHFPLACEHOLDER12ATOM,
2377 4
                self::RT_ROUNDTRIPSHAPECHECKSUMFORCL12ATOM,
2378
            );
2379
            do {
2380 4
                $dataHeaderRG = $this->loadRecordHeader($stream, $pos + $arrayReturn['length']);
2381 4
                if (in_array($dataHeaderRG['recType'], $array)) {
2382
                    switch ($dataHeaderRG['recType']) {
2383
                        case self::RT_PROGTAGS:
2384
                            $dataRG = $this->readRecordShapeProgTagsContainer($stream, $pos + $arrayReturn['length']);
2385
                            $arrayReturn['length'] += $dataRG['length'];
2386
                            break;
2387
                        case self::RT_ROUNDTRIPHFPLACEHOLDER12ATOM:
2388
                            $dataRG = $this->readRecordRoundTripHFPlaceholder12Atom($stream, $pos + $arrayReturn['length']);
2389
                            $arrayReturn['length'] += $dataRG['length'];
2390
                            break;
2391
                        case self::RT_ROUNDTRIPSHAPEID12ATOM:
2392
                            $dataRG = $this->readRecordRoundTripShapeId12Atom($stream, $pos + $arrayReturn['length']);
2393
                            $arrayReturn['length'] += $dataRG['length'];
2394
                            break;
2395
                        default:
2396
                            throw new \Exception('Feature not implemented (l.'.__LINE__.' : 0x'.dechex($dataHeaderRG['recType']).')');
2397
                    }
2398
                }
2399 4
            } while (in_array($dataHeaderRG['recType'], $array));
2400
        }
2401
2402 4
        return $arrayReturn;
2403
    }
2404
2405
    /**
2406
     * An atom record that specifies a persist object directory. Each persist object identifier specified MUST be unique in that persist object directory.
2407
     * @link http://msdn.microsoft.com/en-us/library/dd952680(v=office.12).aspx
2408
     * @param string $stream
2409
     * @param integer $pos
2410
     * @throws \Exception
2411
     */
2412 4
    private function readRecordPersistDirectoryAtom($stream, $pos)
2413
    {
2414 4
        $rHeader = $this->loadRecordHeader($stream, $pos);
2415 4
        $pos += 8;
2416 4
        if ($rHeader['recVer'] != 0x0 || $rHeader['recInstance'] != 0x000 || $rHeader['recType'] != self::RT_PERSISTDIRECTORYATOM) {
2417
            throw new \Exception('File PowerPoint 97 in error (Location : PersistDirectoryAtom > RecordHeader).');
2418
        }
2419
        // rgPersistDirEntry
2420
        // @link : http://msdn.microsoft.com/en-us/library/dd947347(v=office.12).aspx
2421
        do {
2422 4
            $data = self::getInt4d($stream, $pos);
2423 4
            $pos += 4;
2424 4
            $rHeader['recLen'] -= 4;
2425
            //$persistId  = ($data >> 0) & bindec('11111111111111111111');
2426 4
            $cPersist  = ($data >> 20) & bindec('111111111111');
2427
2428 4
            $rgPersistOffset = array();
2429 4
            for ($inc = 0; $inc < $cPersist; $inc++) {
2430 4
                $rgPersistOffset[] = self::getInt4d($stream, $pos);
2431 4
                $pos += 4;
2432 4
                $rHeader['recLen'] -= 4;
2433
            }
2434 4
        } while ($rHeader['recLen'] > 0);
2435 4
        $this->rgPersistDirEntry = $rgPersistOffset;
2436 4
    }
2437
2438
    /**
2439
     * A container record that specifies information about the headers (1) and footers within a slide.
2440
     * @param string $stream
2441
     * @param integer $pos
2442
     * @link https://msdn.microsoft.com/en-us/library/dd904856(v=office.12).aspx
2443
     * @return array
2444
     */
2445 4
    private function readRecordPerSlideHeadersFootersContainer($stream, $pos)
2446
    {
2447
        $arrayReturn = array(
2448 4
            'length' => 0,
2449
        );
2450
2451 4
        $data = $this->loadRecordHeader($stream, $pos);
2452 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_HEADERSFOOTERS) {
2453
            // Record Header
2454 4
            $arrayReturn['length'] += 8;
2455
            // Length
2456 4
            $arrayReturn['length'] += $data['recLen'];
2457
        }
2458
2459 4
        return $arrayReturn;
2460
    }
2461
2462
    /**
2463
     * An atom record that specifies whether a shape is a placeholder shape.
2464
     * @param string $stream
2465
     * @param integer $pos
2466
     * @link https://msdn.microsoft.com/en-us/library/dd923930(v=office.12).aspx
2467
     * @return array
2468
     */
2469 4
    private function readRecordPlaceholderAtom($stream, $pos)
2470
    {
2471
        $arrayReturn = array(
2472 4
            'length' => 0,
2473
        );
2474
2475 4
        $data = $this->loadRecordHeader($stream, $pos);
2476 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_PLACEHOLDERATOM && $data['recLen'] == 0x00000008) {
2477
            // Record Header
2478 4
            $arrayReturn['length'] += 8;
2479
            // Datas
2480 4
            $arrayReturn['length'] += $data['recLen'];
2481
        }
2482
2483 4
        return $arrayReturn;
2484
    }
2485
2486
    /**
2487
     * An atom record that specifies a collection of re-color mappings for a metafile ([MS-WMF]).
2488
     * @param string $stream
2489
     * @param integer $pos
2490
     * @link https://msdn.microsoft.com/en-us/library/dd904899(v=office.12).aspx
2491
     * @return array
2492
     */
2493 4
    private function readRecordRecolorInfoAtom($stream, $pos)
2494
    {
2495
        $arrayReturn = array(
2496 4
            'length' => 0,
2497
        );
2498
2499 4
        $data = $this->loadRecordHeader($stream, $pos);
2500 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_RECOLORINFOATOM) {
2501
            // Record Header
2502
            $arrayReturn['length'] += 8;
2503
            // Datas
2504
            $arrayReturn['length'] += $data['recLen'];
2505
        }
2506
2507 4
        return $arrayReturn;
2508
    }
2509
2510
    /**
2511
     * An atom record that specifies that a shape is a header or footerplaceholder shape.
2512
     * @param string $stream
2513
     * @param integer $pos
2514
     * @link https://msdn.microsoft.com/en-us/library/dd910800(v=office.12).aspx
2515
     * @return array
2516
     */
2517
    private function readRecordRoundTripHFPlaceholder12Atom($stream, $pos)
2518
    {
2519
        $arrayReturn = array(
2520
            'length' => 0,
2521
        );
2522
2523
        $data = $this->loadRecordHeader($stream, $pos);
2524
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_ROUNDTRIPHFPLACEHOLDER12ATOM && $data['recLen'] == 0x00000001) {
2525
            // Record Header
2526
            $arrayReturn['length'] += 8;
2527
            // Datas
2528
            $arrayReturn['length'] += $data['recLen'];
2529
        }
2530
2531
        return $arrayReturn;
2532
    }
2533
2534
    /**
2535
     * An atom record that specifies a shape identifier.
2536
     * @param string $stream
2537
     * @param integer $pos
2538
     * @link https://msdn.microsoft.com/en-us/library/dd772926(v=office.12).aspx
2539
     * @return array
2540
     */
2541
    private function readRecordRoundTripShapeId12Atom($stream, $pos)
2542
    {
2543
        $arrayReturn = array(
2544
            'length' => 0,
2545
        );
2546
2547
        $data = $this->loadRecordHeader($stream, $pos);
2548
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_ROUNDTRIPSHAPEID12ATOM && $data['recLen'] == 0x00000004) {
2549
            // Record Header
2550
            $arrayReturn['length'] += 8;
2551
            // Length
2552
            $arrayReturn['length'] += $data['recLen'];
2553
        }
2554
2555
        return $arrayReturn;
2556
    }
2557
2558
    /**
2559
     * A container record that specifies information about a slide that synchronizes to a slide in a slide library.
2560
     * @param string $stream
2561
     * @param integer $pos
2562
     * @link https://msdn.microsoft.com/en-us/library/dd923801(v=office.12).aspx
2563
     * @return array
2564
     */
2565 4
    private function readRecordRoundTripSlideSyncInfo12Container($stream, $pos)
2566
    {
2567
        $arrayReturn = array(
2568 4
            'length' => 0,
2569
        );
2570
2571 4
        $data = $this->loadRecordHeader($stream, $pos);
2572 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_ROUNDTRIPSLIDESYNCINFO12) {
2573
            // Record Header
2574
            $arrayReturn['length'] += 8;
2575
            // Length
2576
            $arrayReturn['length'] += $data['recLen'];
2577
        }
2578
2579 4
        return $arrayReturn;
2580
    }
2581
2582
    /**
2583
     * An atom record that specifies shape-level Boolean flags.
2584
     * @param string $stream
2585
     * @param integer $pos
2586
     * @link https://msdn.microsoft.com/en-us/library/dd908949(v=office.12).aspx
2587
     * @return array
2588
     */
2589 4
    private function readRecordShapeFlags10Atom($stream, $pos)
2590
    {
2591
        $arrayReturn = array(
2592 4
            'length' => 0,
2593
        );
2594
2595 4
        $data = $this->loadRecordHeader($stream, $pos);
2596 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_SHAPEFLAGS10ATOM && $data['recLen'] == 0x00000001) {
2597
            // Record Header
2598
            $arrayReturn['length'] += 8;
2599
            // Datas
2600
            $arrayReturn['length'] += $data['recLen'];
2601
        }
2602
2603 4
        return $arrayReturn;
2604
    }
2605
2606
    /**
2607
     * An atom record that specifies shape-level Boolean flags.
2608
     * @param string $stream
2609
     * @param integer $pos
2610
     * @link https://msdn.microsoft.com/en-us/library/dd925824(v=office.12).aspx
2611
     * @return array
2612
     */
2613 4
    private function readRecordShapeFlagsAtom($stream, $pos)
2614
    {
2615
        $arrayReturn = array(
2616 4
                'length' => 0,
2617
        );
2618
2619 4
        $data = $this->loadRecordHeader($stream, $pos);
2620 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_SHAPEATOM && $data['recLen'] == 0x00000001) {
2621
            // Record Header
2622
            $arrayReturn['length'] += 8;
2623
            // Datas
2624
            $arrayReturn['length'] += $data['recLen'];
2625
        }
2626
2627 4
        return $arrayReturn;
2628
    }
2629
2630
    /**
2631
     * A container record that specifies programmable tags with additional binary shape data.
2632
     * @param string $stream
2633
     * @param integer $pos
2634
     * @link https://msdn.microsoft.com/en-us/library/dd911033(v=office.12).aspx
2635
     * @return array
2636
     */
2637
    private function readRecordShapeProgBinaryTagContainer($stream, $pos)
2638
    {
2639
        $arrayReturn = array(
2640
            'length' => 0,
2641
        );
2642
2643
        $data = $this->loadRecordHeader($stream, $pos);
2644
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_PROGBINARYTAG) {
2645
            // Record Header
2646
            $arrayReturn['length'] += 8;
2647
            // Datas
2648
            $arrayReturn['length'] += $data['recLen'];
2649
        }
2650
2651
        return $arrayReturn;
2652
    }
2653
2654
    /**
2655
     * A container record that specifies programmable tags with additional shape data.
2656
     * @param string $stream
2657
     * @param integer $pos
2658
     * @return array
2659
     * @throws \Exception
2660
     * @link https://msdn.microsoft.com/en-us/library/dd911266(v=office.12).aspx
2661
     */
2662
    private function readRecordShapeProgTagsContainer($stream, $pos)
2663
    {
2664
        $arrayReturn = array(
2665
            'length' => 0,
2666
        );
2667
2668
        $data = $this->loadRecordHeader($stream, $pos);
2669
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_PROGTAGS) {
2670
            // Record Header
2671
            $arrayReturn['length'] += 8;
2672
2673
            $length = 0;
2674
            do {
2675
                $dataHeaderRG = $this->loadRecordHeader($stream, $pos + $arrayReturn['length'] + $length);
2676
                switch ($dataHeaderRG['recType']) {
2677
                    case self::RT_PROGBINARYTAG:
2678
                        $dataRG = $this->readRecordShapeProgBinaryTagContainer($stream, $pos + $arrayReturn['length'] + $length);
2679
                        $length += $dataRG['length'];
2680
                        break;
2681
                    //case self::RT_PROGSTRINGTAG:
2682
                    default:
2683
                        throw new \Exception('Feature not implemented (l.'.__LINE__.')');
2684
                }
2685
            } while ($length < $data['recLen']);
2686
            // Datas
2687
            $arrayReturn['length'] += $data['recLen'];
2688
        }
2689
2690
        return $arrayReturn;
2691
    }
2692
2693
    /**
2694
     * An atom record that specifies information about a slide.
2695
     * @param string $stream
2696
     * @param integer $pos
2697
     * @return array
2698
     * @link https://msdn.microsoft.com/en-us/library/dd923801(v=office.12).aspx
2699
     */
2700 4
    private function readRecordSlideAtom($stream, $pos)
2701
    {
2702
        $arrayReturn = array(
2703 4
            'length' => 0,
2704
        );
2705
2706 4
        $data = $this->loadRecordHeader($stream, $pos);
2707 4
        if ($data['recVer'] == 0x2 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_SLIDEATOM) {
2708
            // Record Header
2709 4
            $arrayReturn['length'] += 8;
2710
            // slideAtom > geom
2711 4
            $arrayReturn['length'] += 4;
2712
            // slideAtom > rgPlaceholderTypes
2713 4
            $rgPlaceholderTypes = array();
2714 4
            for ($inc = 0; $inc < 8; $inc++) {
2715 4
                $rgPlaceholderTypes[] = self::getInt1d($this->streamPowerpointDocument, $pos);
2716 4
                $arrayReturn['length'] += 1;
2717
            }
2718
2719
            // slideAtom > masterIdRef
2720 4
            $arrayReturn['length'] += 4;
2721
            // slideAtom > notesIdRef
2722 4
            $arrayReturn['length'] += 4;
2723
            // slideAtom > slideFlags
2724 4
            $arrayReturn['length'] += 2;
2725
            // slideAtom > unused;
2726 4
            $arrayReturn['length'] += 2;
2727
        }
2728
2729 4
        return $arrayReturn;
2730
    }
2731
2732
    /**
2733
     * A container record that specifies a presentation slide or title master slide.
2734
     * @param string $stream
2735
     * @param int $pos
2736
     * @throws \Exception
2737
     * @link http://msdn.microsoft.com/en-us/library/dd946323(v=office.12).aspx
2738
     */
2739 4
    private function readRecordSlideContainer($stream, $pos)
2740
    {
2741
        // Core
2742 4
        $this->oPhpPresentation->createSlide();
2743 4
        $this->oPhpPresentation->setActiveSlideIndex($this->oPhpPresentation->getSlideCount() - 1);
2744
2745
        // *** slideAtom (32 bytes)
2746 4
        $slideAtom = $this->readRecordSlideAtom($stream, $pos);
2747 4
        if ($slideAtom['length'] == 0) {
2748
            throw new \Exception('PowerPoint97 Reader : record SlideAtom');
2749
        }
2750 4
        $pos += $slideAtom['length'];
2751
2752
        // *** slideShowSlideInfoAtom (24 bytes)
2753 4
        $slideShowInfoAtom = $this->readRecordSlideShowSlideInfoAtom($stream, $pos);
2754 4
        $pos += $slideShowInfoAtom['length'];
2755
2756
        // *** perSlideHFContainer (variable) : optional
2757 4
        $perSlideHFContainer = $this->readRecordPerSlideHeadersFootersContainer($stream, $pos);
2758 4
        $pos += $perSlideHFContainer['length'];
2759
2760
        // *** rtSlideSyncInfo12 (variable) : optional
2761 4
        $rtSlideSyncInfo12 = $this->readRecordRoundTripSlideSyncInfo12Container($stream, $pos);
2762 4
        $pos += $rtSlideSyncInfo12['length'];
2763
2764
        // *** drawing (variable)
2765 4
        $drawing = $this->readRecordDrawingContainer($stream, $pos);
2766 4
        $pos += $drawing['length'];
2767
2768
        // *** slideSchemeColorSchemeAtom (40 bytes)
2769 4
        $slideSchemeColorAtom = $this->readRecordSlideSchemeColorSchemeAtom($stream, $pos);
2770 4
        if ($slideSchemeColorAtom['length'] == 0) {
2771
            throw new \Exception('PowerPoint97 Reader : record SlideSchemeColorSchemeAtom');
2772
        }
2773 4
        $pos += $slideSchemeColorAtom['length'];
2774
2775
        // *** slideNameAtom (variable)
2776 4
        $slideNameAtom = $this->readRecordSlideNameAtom($stream, $pos);
2777 4
        $pos += $slideNameAtom['length'];
2778
2779
        // *** slideProgTagsContainer (variable).
2780 4
        $slideProgTags = $this->readRecordSlideProgTagsContainer($stream, $pos);
2781 4
        $pos += $slideProgTags['length'];
2782
2783
        // *** rgRoundTripSlide (variable)
2784 4
    }
2785
2786
    /**
2787
     * An atom record that specifies the name of a slide.
2788
     * @param string $stream
2789
     * @param integer $pos
2790
     * @link https://msdn.microsoft.com/en-us/library/dd906297(v=office.12).aspx
2791
     * @return array
2792
     */
2793 4
    private function readRecordSlideNameAtom($stream, $pos)
2794
    {
2795
        $arrayReturn = array(
2796 4
            'length' => 0,
2797
            'slideName' => '',
2798
        );
2799
2800 4
        $data = $this->loadRecordHeader($stream, $pos);
2801 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x003 && $data['recType'] == self::RT_CSTRING && $data['recLen'] % 2 == 0) {
2802
            // Record Header
2803
            $arrayReturn['length'] += 8;
2804
            // Length
2805
            $strLen = ($data['recLen'] / 2);
2806
            for ($inc = 0; $inc < $strLen; $inc++) {
2807
                $char = self::getInt2d($stream, $pos + $arrayReturn['length']);
2808
                $arrayReturn['length'] += 2;
2809
                $arrayReturn['slideName'] .= Text::chr($char);
2810
            }
2811
        }
2812
2813 4
        return $arrayReturn;
2814
    }
2815
2816
    /**
2817
     * An atom record that specifies a slide number metacharacter.
2818
     * @param string $stream
2819
     * @param integer $pos
2820
     * @link https://msdn.microsoft.com/en-us/library/dd945703(v=office.12).aspx
2821
     * @return array
2822
     */
2823 4
    private function readRecordSlideNumberMCAtom($stream, $pos)
2824
    {
2825
        $arrayReturn = array(
2826 4
            'length' => 0,
2827
        );
2828
2829 4
        $data = $this->loadRecordHeader($stream, $pos);
2830 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_SLIDENUMBERMETACHARATOM && $data['recLen'] == 0x00000004) {
2831
            // Record Header
2832 4
            $arrayReturn['length'] += 8;
2833
            // Datas
2834 4
            $arrayReturn['length'] += $data['recLen'];
2835
        }
2836
2837 4
        return $arrayReturn;
2838
    }
2839
2840
    /**
2841
     * A container record that specifies programmable tags with additional slide data.
2842
     * @param string $stream
2843
     * @param integer $pos
2844
     * @link https://msdn.microsoft.com/en-us/library/dd951946(v=office.12).aspx
2845
     * @return array
2846
     */
2847 4
    private function readRecordSlideProgTagsContainer($stream, $pos)
2848
    {
2849
        $arrayReturn = array(
2850 4
            'length' => 0,
2851
        );
2852
2853 4
        $data = $this->loadRecordHeader($stream, $pos);
2854 4
        if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_PROGTAGS) {
2855
            // Record Header
2856 4
            $arrayReturn['length'] += 8;
2857
            // Length
2858 4
            $arrayReturn['length'] += $data['recLen'];
2859
        }
2860
2861 4
        return $arrayReturn;
2862
    }
2863
2864
    /**
2865
     * A container record that specifies the color scheme used by a slide.
2866
     * @param string $stream
2867
     * @param integer $pos
2868
     * @link https://msdn.microsoft.com/en-us/library/dd949420(v=office.12).aspx
2869
     * @return array
2870
     */
2871 4
    private function readRecordSlideSchemeColorSchemeAtom($stream, $pos)
2872
    {
2873
        $arrayReturn = array(
2874 4
            'length' => 0,
2875
        );
2876
2877 4
        $data = $this->loadRecordHeader($stream, $pos);
2878 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x001 && $data['recType'] == self::RT_COLORSCHEMEATOM && $data['recLen'] == 0x00000020) {
2879
            // Record Header
2880 4
            $arrayReturn['length'] += 8;
2881
            // Length
2882 4
            $rgSchemeColor = array();
2883 4
            for ($inc = 0; $inc <= 7; $inc++) {
2884 4
                $rgSchemeColor[] = array(
2885 4
                    'red' => self::getInt1d($stream, $pos + $arrayReturn['length'] + $inc * 4),
2886 4
                    'green' => self::getInt1d($stream, $pos + $arrayReturn['length'] + $inc * 4 + 1),
2887 4
                    'blue' => self::getInt1d($stream, $pos + $arrayReturn['length'] + $inc * 4 + 2),
2888
                );
2889
            }
2890 4
            $arrayReturn['length'] += (8 * 4);
2891
        }
2892
2893 4
        return $arrayReturn;
2894
    }
2895
2896
    /**
2897
     * An atom record that specifies what transition effect to perform during a slide show, and how to advance to the next presentation slide.
2898
     * @param string $stream
2899
     * @param integer $pos
2900
     * @link https://msdn.microsoft.com/en-us/library/dd943408(v=office.12).aspx
2901
     * @return array
2902
     */
2903 4
    private function readRecordSlideShowSlideInfoAtom($stream, $pos)
2904
    {
2905
        $arrayReturn = array(
2906 4
            'length' => 0,
2907
        );
2908
2909 4
        $data = $this->loadRecordHeader($stream, $pos);
2910 4
        if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_SLIDESHOWSLIDEINFOATOM && $data['recLen'] == 0x00000010) {
2911
            // Record Header
2912 4
            $arrayReturn['length'] += 8;
2913
            // Length;
2914 4
            $arrayReturn['length'] += $data['recLen'];
2915
        }
2916
2917 4
        return $arrayReturn;
2918
    }
2919
2920
    /**
2921
     * UserEditAtom
2922
     * @link http://msdn.microsoft.com/en-us/library/dd945746(v=office.12).aspx
2923
     * @param string $stream
2924
     * @param integer $pos
2925
     * @throws \Exception
2926
     */
2927 4
    private function readRecordUserEditAtom($stream, $pos)
2928
    {
2929 4
        $rHeader = $this->loadRecordHeader($stream, $pos);
2930 4
        $pos += 8;
2931 4
        if ($rHeader['recVer'] != 0x0 || $rHeader['recInstance'] != 0x000 || $rHeader['recType'] != self::RT_USEREDITATOM || ($rHeader['recLen'] != 0x0000001C && $rHeader['recLen'] != 0x00000020)) {
2932
            throw new \Exception('File PowerPoint 97 in error (Location : UserEditAtom > RecordHeader).');
2933
        }
2934
2935
        // lastSlideIdRef
2936 4
        $pos += 4;
2937
        // version
2938 4
        $pos += 2;
2939
2940
        // minorVersion
2941 4
        $minorVersion = self::getInt1d($stream, $pos);
2942 4
        $pos += 1;
2943 4
        if ($minorVersion != 0x00) {
2944
            throw new \Exception('File PowerPoint 97 in error (Location : UserEditAtom > minorVersion).');
2945
        }
2946
2947
        // majorVersion
2948 4
        $majorVersion = self::getInt1d($stream, $pos);
2949 4
        $pos += 1;
2950 4
        if ($majorVersion != 0x03) {
2951
            throw new \Exception('File PowerPoint 97 in error (Location : UserEditAtom > majorVersion).');
2952
        }
2953
2954
        // offsetLastEdit
2955 4
        $pos += 4;
2956
        // offsetPersistDirectory
2957 4
        $this->offsetPersistDirectory = self::getInt4d($stream, $pos);
2958 4
        $pos += 4;
2959
2960
        // docPersistIdRef
2961 4
        $docPersistIdRef  = self::getInt4d($stream, $pos);
2962 4
        $pos += 4;
2963 4
        if ($docPersistIdRef != 0x00000001) {
2964
            throw new \Exception('File PowerPoint 97 in error (Location : UserEditAtom > docPersistIdRef).');
2965
        }
2966
2967
        // persistIdSeed
2968 4
        $pos += 4;
2969
        // lastView
2970 4
        $pos += 2;
2971
        // unused
2972 4
        $pos += 2;
2973 4
    }
2974
2975
    /**
2976
     * A structure that specifies the character-level formatting of a run of text.
2977
     * @param string $stream
2978
     * @param int $pos
2979
     * @param int $strLenRT
2980
     * @return array
2981
     * @throws \Exception
2982
     * @link https://msdn.microsoft.com/en-us/library/dd945870(v=office.12).aspx
2983
     */
2984 4
    private function readStructureTextCFRun($stream, $pos, $strLenRT)
2985
    {
2986
        $arrayReturn = array(
2987 4
            'length' => 0,
2988 4
            'strLenRT' => $strLenRT,
2989
        );
2990
2991
        // rgTextCFRun
2992 4
        $countRgTextCFRun = self::getInt4d($stream, $pos + $arrayReturn['length']);
2993 4
        $arrayReturn['strLenRT'] -= $countRgTextCFRun;
2994 4
        $arrayReturn['length'] += 4;
2995 4
        $arrayReturn['partLength'] = $countRgTextCFRun;
2996
2997 4
        $masks = self::getInt4d($stream, $pos + $arrayReturn['length']);
2998 4
        $arrayReturn['length'] += 4;
2999
3000 4
        $masksData = array();
3001 4
        $masksData['bold'] = ($masks >> 0) & bindec('1');
3002 4
        $masksData['italic'] = ($masks >> 1) & bindec('1');
3003 4
        $masksData['underline'] = ($masks >> 2) & bindec('1');
3004 4
        $masksData['unused1'] = ($masks >> 3) & bindec('1');
3005 4
        $masksData['shadow'] = ($masks >> 4) & bindec('1');
3006 4
        $masksData['fehint'] = ($masks >> 5) & bindec('1');
3007 4
        $masksData['unused2'] = ($masks >> 6) & bindec('1');
3008 4
        $masksData['kumi'] = ($masks >> 7) & bindec('1');
3009 4
        $masksData['unused3'] = ($masks >> 8) & bindec('1');
3010 4
        $masksData['emboss'] = ($masks >> 9) & bindec('1');
3011 4
        $masksData['fHasStyle'] = ($masks >> 10) & bindec('1111');
3012 4
        $masksData['unused4'] = ($masks >> 14) & bindec('11');
3013 4
        $masksData['typeface'] = ($masks >> 16) & bindec('1');
3014 4
        $masksData['size'] = ($masks >> 17) & bindec('1');
3015 4
        $masksData['color'] = ($masks >> 18) & bindec('1');
3016 4
        $masksData['position'] = ($masks >> 19) & bindec('1');
3017 4
        $masksData['pp10ext'] = ($masks >> 20) & bindec('1');
3018 4
        $masksData['oldEATypeface'] = ($masks >> 21) & bindec('1');
3019 4
        $masksData['ansiTypeface'] = ($masks >> 22) & bindec('1');
3020 4
        $masksData['symbolTypeface'] = ($masks >> 23) & bindec('1');
3021 4
        $masksData['newEATypeface'] = ($masks >> 24) & bindec('1');
3022 4
        $masksData['csTypeface'] = ($masks >> 25) & bindec('1');
3023 4
        $masksData['pp11ext'] = ($masks >> 26) & bindec('1');
3024 4
        if ($masksData['bold'] == 1 || $masksData['italic'] == 1 || $masksData['underline'] == 1 || $masksData['shadow'] == 1 || $masksData['fehint'] == 1 ||  $masksData['kumi'] == 1 ||  $masksData['emboss'] == 1 ||  $masksData['fHasStyle'] == 1) {
3025 3
            $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3026 3
            $arrayReturn['length'] += 2;
3027
3028 3
            $fontStyleFlags = array();
3029 3
            $fontStyleFlags['bold'] = ($data >> 0) & bindec('1');
3030 3
            $fontStyleFlags['italic'] = ($data >> 1) & bindec('1');
3031 3
            $fontStyleFlags['underline'] = ($data >> 2) & bindec('1');
3032 3
            $fontStyleFlags['unused1'] = ($data >> 3) & bindec('1');
3033 3
            $fontStyleFlags['shadow'] = ($data >> 4) & bindec('1');
3034 3
            $fontStyleFlags['fehint'] = ($data >> 5) & bindec('1');
3035 3
            $fontStyleFlags['unused2'] = ($data >> 6) & bindec('1');
3036 3
            $fontStyleFlags['kumi'] = ($data >> 7) & bindec('1');
3037 3
            $fontStyleFlags['unused3'] = ($data >> 8) & bindec('1');
3038 3
            $fontStyleFlags['emboss'] = ($data >> 9) & bindec('1');
3039 3
            $fontStyleFlags['pp9rt'] = ($data >> 10) & bindec('1111');
3040 3
            $fontStyleFlags['unused4'] = ($data >> 14) & bindec('11');
3041
3042 3
            $arrayReturn['bold'] = ($fontStyleFlags['bold'] == 1) ? true : false;
3043 3
            $arrayReturn['italic'] = ($fontStyleFlags['italic'] == 1) ? true : false;
3044 3
            $arrayReturn['underline'] = ($fontStyleFlags['underline'] == 1) ? true : false;
3045
        }
3046 4
        if ($masksData['typeface'] == 1) {
3047 4
            $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3048 4
            $arrayReturn['length'] += 2;
3049 4
            $arrayReturn['fontName'] = isset($this->arrayFonts[$data]) ? $this->arrayFonts[$data] : '';
3050
        }
3051 4
        if ($masksData['oldEATypeface'] == 1) {
3052
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3053 4
            $arrayReturn['length'] += 2;
3054
        }
3055 4
        if ($masksData['ansiTypeface'] == 1) {
3056
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3057
            $arrayReturn['length'] += 2;
3058
        }
3059 4
        if ($masksData['symbolTypeface'] == 1) {
3060
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3061
            $arrayReturn['length'] += 2;
3062
        }
3063 4
        if ($masksData['size'] == 1) {
3064 4
            $arrayReturn['fontSize'] = self::getInt2d($stream, $pos + $arrayReturn['length']);
3065 4
            $arrayReturn['length'] += 2;
3066
        }
3067 4
        if ($masksData['color'] == 1) {
3068 4
            $red = self::getInt1d($stream, $pos + $arrayReturn['length']);
3069 4
            $arrayReturn['length'] += 1;
3070 4
            $green = self::getInt1d($stream, $pos + $arrayReturn['length']);
3071 4
            $arrayReturn['length'] += 1;
3072 4
            $blue = self::getInt1d($stream, $pos + $arrayReturn['length']);
3073 4
            $arrayReturn['length'] += 1;
3074 4
            $index = self::getInt1d($stream, $pos + $arrayReturn['length']);
3075 4
            $arrayReturn['length'] += 1;
3076
3077 4
            if ($index == 0xFE) {
3078 4
                $strColor = str_pad(dechex($red), 2, STR_PAD_LEFT, '0');
3079 4
                $strColor .= str_pad(dechex($green), 2, STR_PAD_LEFT, '0');
3080 4
                $strColor .= str_pad(dechex($blue), 2, STR_PAD_LEFT, '0');
3081
3082 4
                $arrayReturn['color'] = new Color('FF'.$strColor);
3083
            }
3084
        }
3085 4
        if ($masksData['position'] == 1) {
3086
            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
3087
        }
3088
3089 4
        return $arrayReturn;
3090
    }
3091
3092
    /**
3093
     * A structure that specifies the paragraph-level formatting of a run of text.
3094
     * @param string $stream
3095
     * @param integer $pos
3096
     * @param integer $strLenRT
3097
     * @return array
3098
     * @throws \Exception
3099
     * @link https://msdn.microsoft.com/en-us/library/dd923535(v=office.12).aspx
3100
     */
3101 4
    private function readStructureTextPFRun($stream, $pos, $strLenRT)
3102
    {
3103
        $arrayReturn = array(
3104 4
            'length' => 0,
3105 4
            'strLenRT' => $strLenRT,
3106
        );
3107
3108
        // rgTextPFRun
3109 4
        $countRgTextPFRun = self::getInt4d($stream, $pos + $arrayReturn['length']);
3110 4
        $arrayReturn['strLenRT'] -= $countRgTextPFRun;
3111 4
        $arrayReturn['length'] += 4;
3112
3113
        // indent
3114 4
        $arrayReturn['length'] += 2;
3115
3116 4
        $masks = self::getInt4d($stream, $pos + $arrayReturn['length']);
3117 4
        $arrayReturn['length'] += 4;
3118
3119 4
        $masksData = array();
3120 4
        $masksData['hasBullet'] = ($masks >> 0) & bindec('1');
3121 4
        $masksData['bulletHasFont'] = ($masks >> 1) & bindec('1');
3122 4
        $masksData['bulletHasColor'] = ($masks >> 2) & bindec('1');
3123 4
        $masksData['bulletHasSize'] = ($masks >> 3) & bindec('1');
3124 4
        $masksData['bulletFont'] = ($masks >> 4) & bindec('1');
3125 4
        $masksData['bulletColor'] = ($masks >> 5) & bindec('1');
3126 4
        $masksData['bulletSize'] = ($masks >> 6) & bindec('1');
3127 4
        $masksData['bulletChar'] = ($masks >> 7) & bindec('1');
3128 4
        $masksData['leftMargin'] = ($masks >> 8) & bindec('1');
3129 4
        $masksData['unused'] = ($masks >> 9) & bindec('1');
3130 4
        $masksData['indent'] = ($masks >> 10) & bindec('1');
3131 4
        $masksData['align'] = ($masks >> 11) & bindec('1');
3132 4
        $masksData['lineSpacing'] = ($masks >> 12) & bindec('1');
3133 4
        $masksData['spaceBefore'] = ($masks >> 13) & bindec('1');
3134 4
        $masksData['spaceAfter'] = ($masks >> 14) & bindec('1');
3135 4
        $masksData['defaultTabSize'] = ($masks >> 15) & bindec('1');
3136 4
        $masksData['fontAlign'] = ($masks >> 16) & bindec('1');
3137 4
        $masksData['charWrap'] = ($masks >> 17) & bindec('1');
3138 4
        $masksData['wordWrap'] = ($masks >> 18) & bindec('1');
3139 4
        $masksData['overflow'] = ($masks >> 19) & bindec('1');
3140 4
        $masksData['tabStops'] = ($masks >> 20) & bindec('1');
3141 4
        $masksData['textDirection'] = ($masks >> 21) & bindec('1');
3142 4
        $masksData['reserved1'] = ($masks >> 22) & bindec('1');
3143 4
        $masksData['bulletBlip'] = ($masks >> 23) & bindec('1');
3144 4
        $masksData['bulletScheme'] = ($masks >> 24) & bindec('1');
3145 4
        $masksData['bulletHasScheme'] = ($masks >> 25) & bindec('1');
3146
3147 4
        $bulletFlags = array();
3148 4
        if ($masksData['hasBullet'] == 1 || $masksData['bulletHasFont'] == 1  || $masksData['bulletHasColor'] == 1  || $masksData['bulletHasSize'] == 1) {
3149 4
            $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3150 4
            $arrayReturn['length'] += 2;
3151
3152 4
            $bulletFlags['fHasBullet'] = ($data >> 0) & bindec('1');
3153 4
            $bulletFlags['fBulletHasFont'] = ($data >> 1) & bindec('1');
3154 4
            $bulletFlags['fBulletHasColor'] = ($data >> 2) & bindec('1');
3155 4
            $bulletFlags['fBulletHasSize'] = ($data >> 3) & bindec('1');
3156
        }
3157 4
        if ($masksData['bulletChar'] == 1) {
3158 1
            $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3159 1
            $arrayReturn['length'] += 2;
3160 1
            $arrayReturn['bulletChar'] = chr($data);
3161
        }
3162 4
        if ($masksData['bulletFont'] == 1) {
3163
            // $data = self::getInt2d($stream, $pos);
3164 1
            $arrayReturn['length'] += 2;
3165
        }
3166 4
        if ($masksData['bulletSize'] == 1) {
3167
            // $data = self::getInt2d($stream, $pos);
3168 2
            $arrayReturn['length'] += 2;
3169
        }
3170 4
        if ($masksData['bulletColor'] == 1) {
3171
            // $red = self::getInt1d($stream, $pos + $arrayReturn['length']);
3172 1
            $arrayReturn['length'] += 1;
3173
            // $green = self::getInt1d($stream, $pos + $arrayReturn['length']);
3174 1
            $arrayReturn['length'] += 1;
3175
            // $blue = self::getInt1d($stream, $pos + $arrayReturn['length']);
3176 1
            $arrayReturn['length'] += 1;
3177 1
            $index = self::getInt1d($stream, $pos + $arrayReturn['length']);
3178 1
            $arrayReturn['length'] += 1;
3179
3180 1
            if ($index == 0xFE) {
3181
                // $strColor = str_pad(dechex($red), 2, STR_PAD_LEFT, '0');
3182
                // $strColor .= str_pad(dechex($green), 2, STR_PAD_LEFT, '0');
3183
                // $strColor .= str_pad(dechex($blue), 2, STR_PAD_LEFT, '0');
3184
            }
3185
        }
3186 4
        if ($masksData['align'] == 1) {
3187 4
            $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3188 4
            $arrayReturn['length'] += 2;
3189 4
            switch ($data) {
3190 4
                case 0x0000:
3191 1
                    $arrayReturn['alignH'] = Alignment::HORIZONTAL_LEFT;
3192 1
                    break;
3193 4
                case 0x0001:
3194 2
                    $arrayReturn['alignH'] = Alignment::HORIZONTAL_CENTER;
3195 2
                    break;
3196 4
                case 0x0002:
3197 4
                    $arrayReturn['alignH'] = Alignment::HORIZONTAL_RIGHT;
3198 4
                    break;
3199
                case 0x0003:
3200
                    $arrayReturn['alignH'] = Alignment::HORIZONTAL_JUSTIFY;
3201
                    break;
3202
                case 0x0004:
3203
                    $arrayReturn['alignH'] = Alignment::HORIZONTAL_DISTRIBUTED;
3204
                    break;
3205
                case 0x0005:
3206
                    $arrayReturn['alignH'] = Alignment::HORIZONTAL_DISTRIBUTED;
3207
                    break;
3208
                case 0x0006:
3209
                    $arrayReturn['alignH'] = Alignment::HORIZONTAL_JUSTIFY;
3210
                    break;
3211
                default:
3212
                    break;
3213
            }
3214
        }
3215 4
        if ($masksData['lineSpacing'] == 1) {
3216
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3217 4
            $arrayReturn['length'] += 2;
3218
        }
3219 4
        if ($masksData['spaceBefore'] == 1) {
3220
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3221 2
            $arrayReturn['length'] += 2;
3222
        }
3223 4
        if ($masksData['spaceAfter'] == 1) {
3224
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3225 2
            $arrayReturn['length'] += 2;
3226
        }
3227 4
        if ($masksData['leftMargin'] == 1) {
3228 1
            $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3229 1
            $arrayReturn['length'] += 2;
3230 1
            $arrayReturn['leftMargin'] = (int)round($data/6);
3231
        }
3232 4
        if ($masksData['indent'] == 1) {
3233 1
            $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3234 1
            $arrayReturn['length'] += 2;
3235 1
            $arrayReturn['indent'] = (int)round($data/6);
3236
        }
3237 4
        if ($masksData['defaultTabSize'] == 1) {
3238
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3239
            $arrayReturn['length'] += 2;
3240
        }
3241 4
        if ($masksData['tabStops'] == 1) {
3242
            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
3243
        }
3244 4
        if ($masksData['fontAlign'] == 1) {
3245
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3246
            $arrayReturn['length'] += 2;
3247
        }
3248 4
        if ($masksData['charWrap'] == 1 || $masksData['wordWrap'] == 1 || $masksData['overflow'] == 1) {
3249
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3250 4
            $arrayReturn['length'] += 2;
3251
        }
3252 4
        if ($masksData['textDirection'] == 1) {
3253
            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
3254
        }
3255
3256 4
        return $arrayReturn;
3257
    }
3258
3259
    /**
3260
     * A structure that specifies language and spelling information for a run of text.
3261
     * @param string $stream
3262
     * @param integer $pos
3263
     * @param string $strLenRT
3264
     * @return array
3265
     * @throws \Exception
3266
     * @link https://msdn.microsoft.com/en-us/library/dd909603(v=office.12).aspx
3267
     */
3268 4
    private function readStructureTextSIRun($stream, $pos, $strLenRT)
3269
    {
3270
        $arrayReturn = array(
3271 4
            'length' => 0,
3272 4
            'strLenRT' => $strLenRT,
3273
        );
3274
3275 4
        $arrayReturn['strLenRT'] -= self::getInt4d($stream, $pos + $arrayReturn['length']);
3276 4
        $arrayReturn['length'] += 4;
3277
3278 4
        $data = self::getInt4d($stream, $pos + $arrayReturn['length']);
3279 4
        $arrayReturn['length'] += 4;
3280 4
        $masksData = array();
3281 4
        $masksData['spell'] = ($data >> 0) & bindec('1');
3282 4
        $masksData['lang'] = ($data >> 1) & bindec('1');
3283 4
        $masksData['altLang'] = ($data >> 2) & bindec('1');
3284 4
        $masksData['unused1'] = ($data >> 3) & bindec('1');
3285 4
        $masksData['unused2'] = ($data >> 4) & bindec('1');
3286 4
        $masksData['fPp10ext'] = ($data >> 5) & bindec('1');
3287 4
        $masksData['fBidi'] = ($data >> 6) & bindec('1');
3288 4
        $masksData['unused3'] = ($data >> 7) & bindec('1');
3289 4
        $masksData['reserved1'] = ($data >> 8) & bindec('1');
3290 4
        $masksData['smartTag'] = ($data >> 9) & bindec('1');
3291
3292 4
        if ($masksData['spell'] == 1) {
3293 4
            $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3294 4
            $arrayReturn['length'] += 2;
3295 4
            $masksSpell = array();
3296 4
            $masksSpell['error'] = ($data >> 0) & bindec('1');
3297 4
            $masksSpell['clean'] = ($data >> 1) & bindec('1');
3298 4
            $masksSpell['grammar'] = ($data >> 2) & bindec('1');
3299
        }
3300 4
        if ($masksData['lang'] == 1) {
3301
            // $data = self::getInt2d($stream, $pos);
3302 4
            $arrayReturn['length'] += 2;
3303
        }
3304 4
        if ($masksData['altLang'] == 1) {
3305
            // $data = self::getInt2d($stream, $pos);
3306 4
            $arrayReturn['length'] += 2;
3307
        }
3308 4
        if ($masksData['fBidi'] == 1) {
3309
            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
3310
        }
3311 4
        if ($masksData['fPp10ext'] == 1) {
3312
            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
3313
        }
3314 4
        if ($masksData['smartTag'] == 1) {
3315
            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
3316
        }
3317
3318 4
        return $arrayReturn;
3319
    }
3320
3321
    /**
3322
     * A structure that specifies tabbing, margins, and indentation for text.
3323
     * @param string $stream
3324
     * @param integer $pos
3325
     * @return array
3326
     * @throws \Exception
3327
     * @link https://msdn.microsoft.com/en-us/library/dd922749(v=office.12).aspx
3328
     */
3329 4
    private function readStructureTextRuler($stream, $pos)
3330
    {
3331
        $arrayReturn = array(
3332 4
            'length' => 0,
3333
        );
3334
3335 4
        $data = self::getInt4d($stream, $pos + $arrayReturn['length']);
3336 4
        $arrayReturn['length'] += 4;
3337
3338 4
        $masksData = array();
3339 4
        $masksData['fDefaultTabSize'] = ($data >> 0) & bindec('1');
3340 4
        $masksData['fCLevels'] = ($data >> 1) & bindec('1');
3341 4
        $masksData['fTabStops'] = ($data >> 2) & bindec('1');
3342 4
        $masksData['fLeftMargin1'] = ($data >> 3) & bindec('1');
3343 4
        $masksData['fLeftMargin2'] = ($data >> 4) & bindec('1');
3344 4
        $masksData['fLeftMargin3'] = ($data >> 5) & bindec('1');
3345 4
        $masksData['fLeftMargin4'] = ($data >> 6) & bindec('1');
3346 4
        $masksData['fLeftMargin5'] = ($data >> 7) & bindec('1');
3347 4
        $masksData['fIndent1'] = ($data >> 8) & bindec('1');
3348 4
        $masksData['fIndent2'] = ($data >> 9) & bindec('1');
3349 4
        $masksData['fIndent3'] = ($data >> 10) & bindec('1');
3350 4
        $masksData['fIndent4'] = ($data >> 11) & bindec('1');
3351 4
        $masksData['fIndent5'] = ($data >> 12) & bindec('1');
3352
3353 4
        if ($masksData['fCLevels'] == 1) {
3354
            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
3355
        }
3356 4
        if ($masksData['fDefaultTabSize'] == 1) {
3357
            throw new \Exception('Feature not implemented (l.'.__LINE__.')');
3358
        }
3359 4
        if ($masksData['fTabStops'] == 1) {
3360 4
            $count = self::getInt2d($stream, $pos + $arrayReturn['length']);
3361 4
            $arrayReturn['length'] += 2;
3362 4
            $arrayTabStops = array();
3363 4
            for ($inc = 0; $inc < $count; $inc++) {
3364 4
                $position = self::getInt2d($stream, $pos + $arrayReturn['length']);
3365 4
                $arrayReturn['length'] += 2;
3366 4
                $type = self::getInt2d($stream, $pos + $arrayReturn['length']);
3367 4
                $arrayReturn['length'] += 2;
3368 4
                $arrayTabStops[] = array(
3369 4
                    'position' => $position,
3370 4
                    'type' => $type,
3371
                );
3372
            }
3373
        }
3374 4
        if ($masksData['fLeftMargin1'] == 1) {
3375
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3376 1
            $arrayReturn['length'] += 2;
3377
        }
3378 4
        if ($masksData['fIndent1'] == 1) {
3379
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3380 1
            $arrayReturn['length'] += 2;
3381
        }
3382 4
        if ($masksData['fLeftMargin2'] == 1) {
3383
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3384 1
            $arrayReturn['length'] += 2;
3385
        }
3386 4
        if ($masksData['fIndent2'] == 1) {
3387
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3388 1
            $arrayReturn['length'] += 2;
3389
        }
3390 4
        if ($masksData['fLeftMargin3'] == 1) {
3391
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3392
            $arrayReturn['length'] += 2;
3393
        }
3394 4
        if ($masksData['fIndent3'] == 1) {
3395
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3396
            $arrayReturn['length'] += 2;
3397
        }
3398 4
        if ($masksData['fLeftMargin4'] == 1) {
3399
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3400
            $arrayReturn['length'] += 2;
3401
        }
3402 4
        if ($masksData['fIndent4'] == 1) {
3403
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3404
            $arrayReturn['length'] += 2;
3405
        }
3406 4
        if ($masksData['fLeftMargin5'] == 1) {
3407
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3408
            $arrayReturn['length'] += 2;
3409
        }
3410 4
        if ($masksData['fIndent5'] == 1) {
3411
            // $data = self::getInt2d($stream, $pos + $arrayReturn['length']);
3412
            $arrayReturn['length'] += 2;
3413
        }
3414
3415 4
        return $arrayReturn;
3416
    }
3417
3418
    /**
3419
     * @param $stream
3420
     * @param int $pos
3421
     * @throws \Exception
3422
     */
3423 4
    private function readRecordNotesContainer($stream, $pos)
3424
    {
3425
        // notesAtom
3426 4
        $notesAtom = $this->readRecordNotesAtom($stream, $pos);
3427 4
        $pos += $notesAtom['length'];
3428
3429
        // drawing
3430 4
        $drawing = $this->readRecordDrawingContainer($stream, $pos);
3431 4
        $pos += $drawing['length'];
3432
3433
        // slideSchemeColorSchemeAtom
3434
        // slideNameAtom
3435
        // slideProgTagsContainer
3436
        // rgNotesRoundTripAtom
3437 4
    }
3438
3439
    /**
3440
     * @param $stream
3441
     * @param int $pos
3442
     * @return array
3443
     * @throws \Exception
3444
     */
3445 4
    private function readRecordNotesAtom($stream, $pos)
3446
    {
3447
        $arrayReturn = array(
3448 4
            'length' => 0,
3449
        );
3450
3451 4
        $data = $this->loadRecordHeader($stream, $pos);
3452 4
        if ($data['recVer'] != 0x1 || $data['recInstance'] != 0x000 || $data['recType'] != self::RT_NOTESATOM || $data['recLen'] != 0x00000008) {
3453
            throw new \Exception('File PowerPoint 97 in error (Location : NotesAtom > RecordHeader)');
3454
        }
3455
        // Record Header
3456 4
        $arrayReturn['length'] += 8;
3457
        // NotesAtom > slideIdRef
3458 4
        $notesIdRef = self::getInt4d($stream, $pos + $arrayReturn['length']);
3459 4
        if ($notesIdRef == -2147483648) {
3460
            $notesIdRef = 0;
3461
        }
3462 4
        $this->currentNote = $notesIdRef;
3463 4
        $arrayReturn['length'] += 4;
3464
3465
        // NotesAtom > slideFlags
3466 4
        $arrayReturn['length'] += 2;
3467
        // NotesAtom > unused
3468 4
        $arrayReturn['length'] += 2;
3469
3470 4
        return $arrayReturn;
3471
    }
3472
}
3473