1<?php
2/* vim: set expandtab tabstop=4 shiftwidth=4: */
3// +----------------------------------------------------------------------+
4// | PHP Version 4                                                        |
5// +----------------------------------------------------------------------+
6// | Copyright (c) 1997-2002 The PHP Group                                |
7// +----------------------------------------------------------------------+
8// | This source file is subject to version 2.02 of the PHP license,      |
9// | that is bundled with this package in the file LICENSE, and is        |
10// | available at through the world-wide-web at                           |
11// | http://www.php.net/license/2_02.txt.                                 |
12// | If you did not receive a copy of the PHP license and are unable to   |
13// | obtain it through the world-wide-web, please send a note to          |
14// | license@php.net so we can mail you a copy immediately.               |
15// +----------------------------------------------------------------------+
16// | Author: Xavier Noguer <xnoguer@php.net>                              |
17// | Based on OLE::Storage_Lite by Kawai, Takanori                        |
18// +----------------------------------------------------------------------+
19//
20// $Id$
21
22
23if (!class_exists('PEAR')) {
24    require_once 'PEAR.php';
25}
26
27if (!class_exists('OLE')) {
28    require_once 'OLE.php';
29}
30
31/**
32* Class for creating PPS's for OLE containers
33*
34* @author   Xavier Noguer <xnoguer@php.net>
35* @category Structures
36* @package  OLE
37*/
38class OLE_PPS extends PEAR
39{
40    /**
41    * The PPS index
42    * @var integer
43    */
44    var $No;
45
46    /**
47    * The PPS name (in Unicode)
48    * @var string
49    */
50    var $Name;
51
52    /**
53    * The PPS type. Dir, Root or File
54    * @var integer
55    */
56    var $Type;
57
58    /**
59    * The index of the previous PPS
60    * @var integer
61    */
62    var $PrevPps;
63
64    /**
65    * The index of the next PPS
66    * @var integer
67    */
68    var $NextPps;
69
70    /**
71    * The index of it's first child if this is a Dir or Root PPS
72    * @var integer
73    */
74    var $DirPps;
75
76    /**
77    * A timestamp
78    * @var integer
79    */
80    var $Time1st;
81
82    /**
83    * A timestamp
84    * @var integer
85    */
86    var $Time2nd;
87
88    /**
89    * Starting block (small or big) for this PPS's data  inside the container
90    * @var integer
91    */
92    var $_StartBlock;
93
94    /**
95    * The size of the PPS's data (in bytes)
96    * @var integer
97    */
98    var $Size;
99
100    /**
101    * The PPS's data (only used if it's not using a temporary file)
102    * @var string
103    */
104    var $_data;
105
106    /**
107    * Array of child PPS's (only used by Root and Dir PPS's)
108    * @var array
109    */
110    var $children = array();
111
112    /**
113    * Pointer to OLE container
114    * @var OLE
115    */
116    var $ole;
117
118    /**
119    * The constructor
120    *
121    * @access public
122    * @param integer $No   The PPS index
123    * @param string  $name The PPS name
124    * @param integer $type The PPS type. Dir, Root or File
125    * @param integer $prev The index of the previous PPS
126    * @param integer $next The index of the next PPS
127    * @param integer $dir  The index of it's first child if this is a Dir or Root PPS
128    * @param integer $time_1st A timestamp
129    * @param integer $time_2nd A timestamp
130    * @param string  $data  The (usually binary) source data of the PPS
131    * @param array   $children Array containing children PPS for this PPS
132    */
133    function __construct($No, $name, $type, $prev, $next, $dir, $time_1st, $time_2nd, $data, $children)
134    {
135        $this->No      = $No;
136        $this->Name    = $name;
137        $this->Type    = $type;
138        $this->PrevPps = $prev;
139        $this->NextPps = $next;
140        $this->DirPps  = $dir;
141        $this->Time1st = $time_1st;
142        $this->Time2nd = $time_2nd;
143        $this->_data      = $data;
144        $this->children   = $children;
145        if ($data != '') {
146            $this->Size = strlen($data);
147        } else {
148            $this->Size = 0;
149        }
150    }
151
152    /**
153    * Returns the amount of data saved for this PPS
154    *
155    * @access private
156    * @return integer The amount of data (in bytes)
157    */
158    function _DataLen()
159    {
160        if (!isset($this->_data)) {
161            return 0;
162        }
163        if (isset($this->_PPS_FILE)) {
164            fseek($this->_PPS_FILE, 0);
165            $stats = fstat($this->_PPS_FILE);
166            return $stats[7];
167        } else {
168            return strlen($this->_data);
169        }
170    }
171
172    /**
173    * Returns a string with the PPS's WK (What is a WK?)
174    *
175    * @access private
176    * @return string The binary string
177    */
178    function _getPpsWk()
179    {
180        $ret = $this->Name;
181        for ($i = 0; $i < (64 - strlen($this->Name)); $i++) {
182            $ret .= "\x00";
183        }
184        $ret .= pack("v", strlen($this->Name) + 2)  // 66
185              . pack("c", $this->Type)              // 67
186              . pack("c", 0x00) //UK                // 68
187              . pack("V", $this->PrevPps) //Prev    // 72
188              . pack("V", $this->NextPps) //Next    // 76
189              . pack("V", $this->DirPps)  //Dir     // 80
190              . "\x00\x09\x02\x00"                  // 84
191              . "\x00\x00\x00\x00"                  // 88
192              . "\xc0\x00\x00\x00"                  // 92
193              . "\x00\x00\x00\x46"                  // 96 // Seems to be ok only for Root
194              . "\x00\x00\x00\x00"                  // 100
195              . OLE::LocalDate2OLE($this->Time1st)       // 108
196              . OLE::LocalDate2OLE($this->Time2nd)       // 116
197              . pack("V", isset($this->_StartBlock)?
198                        $this->_StartBlock:0)        // 120
199              . pack("V", $this->Size)               // 124
200              . pack("V", 0);                        // 128
201        return $ret;
202    }
203
204    /**
205    * Updates index and pointers to previous, next and children PPS's for this
206    * PPS. I don't think it'll work with Dir PPS's.
207    *
208    * @access private
209    * @param array &$pps_array Reference to the array of PPS's for the whole OLE
210    *                          container
211    * @return integer          The index for this PPS
212    */
213    static function _savePpsSetPnt(&$raList, $to_save, $depth = 0)
214    {
215      if ( !is_array($to_save) || (count($to_save) == 0) ) {
216        return 0xFFFFFFFF;
217      }
218      elseif( count($to_save) == 1 ) {
219        $cnt = count($raList);
220        // If the first entry, it's the root... Don't clone it!
221        $raList[$cnt] = ( $depth == 0 ) ? $to_save[0] : clone $to_save[0];
222        $raList[$cnt]->No = $cnt;
223        $raList[$cnt]->PrevPps = 0xFFFFFFFF;
224        $raList[$cnt]->NextPps = 0xFFFFFFFF;
225        $raList[$cnt]->DirPps  = self::_savePpsSetPnt($raList, @$raList[$cnt]->children, $depth++);
226        return $cnt;
227      }
228      else {
229        $iPos  = floor(count($to_save) / 2);
230        $aPrev = array_slice($to_save, 0, $iPos);
231        $aNext = array_slice($to_save, $iPos + 1);
232
233        $cnt   = count($raList);
234        // If the first entry, it's the root... Don't clone it!
235        $raList[$cnt] = ( $depth == 0 ) ? $to_save[$iPos] : clone $to_save[$iPos];
236        $raList[$cnt]->No = $cnt;
237        $raList[$cnt]->PrevPps = self::_savePpsSetPnt($raList, $aPrev, $depth++);
238        $raList[$cnt]->NextPps = self::_savePpsSetPnt($raList, $aNext, $depth++);
239        $raList[$cnt]->DirPps  = self::_savePpsSetPnt($raList, @$raList[$cnt]->children, $depth++);
240
241        return $cnt;
242      }
243    }
244}
245?>
246