Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * This file holds the Net_DIME_Message and Net_DIME_Record classes and all
4
 * constants defined for the Net_DIME package.
5
 *
6
 * PHP versions 4 and 5
7
 *
8
 * Copyright (c) 2002-2007 The PHP Group
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions are met:
13
 *
14
 * 1. Redistributions of source code must retain the above copyright notice,
15
 *    this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright notice,
17
 *    this list of conditions and the following disclaimer in the documentation
18
 *    and/or other materials provided with the distribution.
19
 * 3. The name of the authors may not be used to endorse or promote products
20
 *    derived from this software without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
 * POSSIBILITY OF SUCH DAMAGE.
33
 *
34
 * @category   Networking
35
 * @package    Net_DIME
36
 * @author     Shane Caraveo <shane@caraveo.com>
37
 * @author     Ralf Hofmann <ralf.hofmann@verdisoft.com>
38
 * @author     Jan Schneider <jan@horde.org>
39
 * @copyright  2002-2007 The PHP Group
40
 * @license    http://www.opensource.org/licenses/bsd-license.php BSD License
41
 * @link       http://pear.php.net/package/Net_DIME
42
 * @example    test/dime_record_test.php For example of usage.
43
 */
44
 
45
/** PEAR */
46
require_once 'PEAR.php';
47
 
48
define('NET_DIME_TYPE_UNCHANGED', 0x00);
49
define('NET_DIME_TYPE_MEDIA', 0x01);
50
define('NET_DIME_TYPE_URI', 0x02);
51
define('NET_DIME_TYPE_UNKNOWN', 0x03);
52
define('NET_DIME_TYPE_NONE', 0x04);
53
 
54
define('NET_DIME_VERSION', 0x0001);
55
 
56
define('NET_DIME_RECORD_HEADER', 12);
57
 
58
define('NET_DIME_FLAGS', 0);
59
define('NET_DIME_OPTS_LEN', 1);
60
define('NET_DIME_ID_LEN', 2);
61
define('NET_DIME_TYPE_LEN', 3);
62
define('NET_DIME_DATA_LEN', 4);
63
define('NET_DIME_OPTS', 5);
64
define('NET_DIME_ID', 6);
65
define('NET_DIME_TYPE', 7);
66
define('NET_DIME_DATA', 8);
67
 
68
/**
69
 * Net_DIME_Record encodes and decodes single DIME records.
70
 *
71
 * @category   Networking
72
 * @package    Net_DIME
73
 * @author     Shane Caraveo <shane@caraveo.com>
74
 * @author     Ralf Hofmann <ralf.hofmann@verdisoft.com>
75
 * @author     Jan Schneider <jan@horde.org>
76
 * @copyright  2002-2007 The PHP Group
77
 * @license    http://www.opensource.org/licenses/bsd-license.php BSD License
78
 * @see        Net_DIME_Message
79
 * @link       http://pear.php.net/package/Net_DIME
80
 * @link       http://www.ietf.org/internet-drafts/draft-nielsen-dime-02.txt
81
 */
82
class Net_DIME_Record {
83
 
84
    // these are used to hold the padded length
85
    var $OPTS_LENGTH = 0;
86
    var $ID_LENGTH = 0;
87
    var $TYPE_LENGTH = 0;
88
    var $DATA_LENGTH = 0;
89
    var $_haveOpts = false;
90
    var $_haveID = false;
91
    var $_haveType = false;
92
    var $_haveData = false;
93
    var $debug = false;
94
    var $padstr = "\0";
95
 
96
    /**
97
     * Elements
98
     * [NET_DIME_FLAGS],    16 bits: VERSION:MB:ME:CF:TYPE_T
99
     * [NET_DIME_OPTS_LEN], 16 bits: OPTIONS_LENGTH
100
     * [NET_DIME_ID_LEN],   16 bits: ID_LENGTH
101
     * [NET_DIME_TYPE_LEN], 16 bits: TYPE_LENGTH
102
     * [NET_DIME_DATA_LEN], 32 bits: DATA_LENGTH
103
	 * [NET_DIME_OPTS]             : OPTIONS
104
	 * [NET_DIME_ID]     		   : ID
105
	 * [NET_DIME_TYPE]             : TYPE
106
	 * [NET_DIME_DATA]             : DATA
107
     */
108
    var $Elements = array(NET_DIME_FLAGS => 0,  NET_DIME_OPTS_LEN => 0,
109
	                      NET_DIME_ID_LEN => 0, NET_DIME_TYPE_LEN => 0,
110
     					  NET_DIME_DATA_LEN => 0,
111
	 					  NET_DIME_OPTS => '',
112
						  NET_DIME_ID => '',
113
						  NET_DIME_TYPE => '',
114
						  NET_DIME_DATA => '');
115
 
116
    function Net_DIME_Record($debug = false)
117
    {
118
        $this->debug = $debug;
119
        if ($debug) {
120
            $this->padstr = '*';
121
        }
122
    }
123
 
124
    function setMB()
125
    {
126
        $this->Elements[NET_DIME_FLAGS] |= 0x0400;
127
    }
128
 
129
    function setME()
130
    {
131
        $this->Elements[NET_DIME_FLAGS] |= 0x0200;
132
    }
133
 
134
    function setCF()
135
    {
136
        $this->Elements[NET_DIME_FLAGS] |= 0x0100;
137
    }
138
 
139
    function isChunk()
140
    {
141
        return $this->Elements[NET_DIME_FLAGS] & 0x0100;
142
    }
143
 
144
    function isEnd()
145
    {
146
        return $this->Elements[NET_DIME_FLAGS] & 0x0200;
147
    }
148
 
149
    function isStart()
150
    {
151
        return $this->Elements[NET_DIME_FLAGS] & 0x0400;
152
    }
153
 
154
    function getID()
155
    {
156
        return $this->Elements[NET_DIME_ID];
157
    }
158
 
159
    function getType()
160
    {
161
        return $this->Elements[NET_DIME_TYPE];
162
    }
163
 
164
    function getData()
165
    {
166
        return $this->Elements[NET_DIME_DATA];
167
    }
168
 
169
    function getDataLength()
170
    {
171
        return $this->Elements[NET_DIME_DATA_LEN];
172
    }
173
 
174
    function setType($typestring, $type = NET_DIME_TYPE_UNKNOWN)
175
    {
176
        $typelen = strlen($typestring) & 0xFFFF;
177
        $type = $type << 4;
178
        $this->Elements[NET_DIME_FLAGS] = ($this->Elements[NET_DIME_FLAGS] & 0xFF0F) | $type;
179
        $this->Elements[NET_DIME_TYPE_LEN] = $typelen;
180
        $this->TYPE_LENGTH = $this->_getPadLength($typelen);
181
        $this->Elements[NET_DIME_TYPE] = $typestring;
182
    }
183
 
184
    function generateID()
185
    {
186
        $id = md5(time());
187
        $this->setID($id);
188
        return $id;
189
    }
190
 
191
    function setID($id)
192
    {
193
        $idlen = strlen($id) & 0xFFFF;
194
        $this->Elements[NET_DIME_ID_LEN] = $idlen;
195
        $this->ID_LENGTH = $this->_getPadLength($idlen);
196
        $this->Elements[NET_DIME_ID] = $id;
197
    }
198
 
199
    function setData($data, $size = 0)
200
    {
201
        $datalen = $size ? $size : strlen($data);
202
        $this->Elements[NET_DIME_DATA_LEN] = $datalen;
203
        $this->DATA_LENGTH = $this->_getPadLength($datalen);
204
        $this->Elements[NET_DIME_DATA] = $data;
205
    }
206
 
207
    function encode()
208
    {
209
		// Insert version.
210
	    $this->Elements[NET_DIME_FLAGS] = ($this->Elements[NET_DIME_FLAGS] & 0x07FF) | (NET_DIME_VERSION << 11);
211
 
212
        // The real DIME encoding.
213
        $format = '%c%c%c%c%c%c%c%c%c%c%c%c'
214
            . '%' . $this->OPTS_LENGTH . 's'
215
            . '%' . $this->ID_LENGTH . 's'
216
            . '%' . $this->TYPE_LENGTH . 's'
217
            . '%' . $this->DATA_LENGTH . 's';
218
 
219
        return sprintf($format,
220
	                   ($this->Elements[NET_DIME_FLAGS] & 0x0000FF00) >> 8,
221
    	               ($this->Elements[NET_DIME_FLAGS] & 0x000000FF),
222
        	           ($this->Elements[NET_DIME_OPTS_LEN] & 0x0000FF00) >> 8,
223
            	       ($this->Elements[NET_DIME_OPTS_LEN] & 0x000000FF),
224
        	           ($this->Elements[NET_DIME_ID_LEN] & 0x0000FF00) >> 8,
225
            	       ($this->Elements[NET_DIME_ID_LEN] & 0x000000FF),
226
        	           ($this->Elements[NET_DIME_TYPE_LEN] & 0x0000FF00) >> 8,
227
            	       ($this->Elements[NET_DIME_TYPE_LEN] & 0x000000FF),
228
                	   ($this->Elements[NET_DIME_DATA_LEN] & 0xFF000000) >> 24,
229
	                   ($this->Elements[NET_DIME_DATA_LEN] & 0x00FF0000) >> 16,
230
    	               ($this->Elements[NET_DIME_DATA_LEN] & 0x0000FF00) >> 8,
231
        	           ($this->Elements[NET_DIME_DATA_LEN] & 0x000000FF),
232
            	       str_pad($this->Elements[NET_DIME_OPTS], $this->OPTS_LENGTH, $this->padstr),
233
            	       str_pad($this->Elements[NET_DIME_ID], $this->ID_LENGTH, $this->padstr),
234
                	   str_pad($this->Elements[NET_DIME_TYPE], $this->TYPE_LENGTH, $this->padstr),
235
	                   str_pad($this->Elements[NET_DIME_DATA], $this->DATA_LENGTH, $this->padstr));
236
    }
237
 
238
    function _getPadLength($len)
239
    {
240
        $pad = 0;
241
        if ($len) {
242
            $pad = $len % 4;
243
            if ($pad) $pad = 4 - $pad;
244
        }
245
        return $len + $pad;
246
    }
247
 
248
    function decode($data)
249
    {
250
        // Real DIME decoding.
251
        $this->Elements[NET_DIME_FLAGS]    = (hexdec(bin2hex($data[0])) << 8)
252
            + hexdec(bin2hex($data[1]));
253
        $this->Elements[NET_DIME_OPTS_LEN] = (hexdec(bin2hex($data[2])) << 8)
254
            + hexdec(bin2hex($data[3]));
255
        $this->Elements[NET_DIME_ID_LEN]   = (hexdec(bin2hex($data[4])) << 8)
256
            + hexdec(bin2hex($data[5]));
257
        $this->Elements[NET_DIME_TYPE_LEN] = (hexdec(bin2hex($data[6])) << 8)
258
            + hexdec(bin2hex($data[7]));
259
        $this->Elements[NET_DIME_DATA_LEN] = (hexdec(bin2hex($data[8])) << 24)
260
            + (hexdec(bin2hex($data[9])) << 16)
261
            + (hexdec(bin2hex($data[10])) << 8)
262
            + hexdec(bin2hex($data[11]));
263
        $p = 12;
264
 
265
		$version = (($this->Elements[NET_DIME_FLAGS] >> 11) & 0x001F);
266
 
267
		if ($version == NET_DIME_VERSION) {
268
	        $this->OPTS_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_OPTS_LEN]);
269
	        $this->ID_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_ID_LEN]);
270
	        $this->TYPE_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_TYPE_LEN]);
271
	        $this->DATA_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_DATA_LEN]);
272
 
273
	        $datalen = strlen($data);
274
	        $this->Elements[NET_DIME_OPTS] = substr($data, $p, $this->Elements[NET_DIME_OPTS_LEN]);
275
	        $this->_haveOpts = (strlen($this->Elements[NET_DIME_OPTS]) == $this->Elements[NET_DIME_OPTS_LEN]);
276
	        if ($this->_haveOpts) {
277
	            $p += $this->OPTS_LENGTH;
278
		        $this->Elements[NET_DIME_ID] = substr($data, $p, $this->Elements[NET_DIME_ID_LEN]);
279
		        $this->_haveID = (strlen($this->Elements[NET_DIME_ID]) == $this->Elements[NET_DIME_ID_LEN]);
280
		        if ($this->_haveID) {
281
		            $p += $this->ID_LENGTH;
282
		            $this->Elements[NET_DIME_TYPE] = substr($data, $p, $this->Elements[NET_DIME_TYPE_LEN]);
283
		            $this->_haveType = (strlen($this->Elements[NET_DIME_TYPE]) == $this->Elements[NET_DIME_TYPE_LEN]);
284
		            if ($this->_haveType) {
285
		                $p += $this->TYPE_LENGTH;
286
		                $this->Elements[NET_DIME_DATA] = substr($data, $p, $this->Elements[NET_DIME_DATA_LEN]);
287
		                $this->_haveData = (strlen($this->Elements[NET_DIME_DATA]) == $this->Elements[NET_DIME_DATA_LEN]);
288
		                if ($this->_haveData) {
289
		                    $p += $this->DATA_LENGTH;
290
		                } else {
291
		                    $p += strlen($this->Elements[NET_DIME_DATA]);
292
		                }
293
		            } else {
294
		                $p += strlen($this->Elements[NET_DIME_TYPE]);
295
					}
296
		        } else {
297
		            $p += strlen($this->Elements[NET_DIME_ID]);
298
				}
299
		    } else {
300
		    	$p += strlen($this->Elements[NET_DIME_OPTS]);
301
	        }
302
		}
303
        return substr($data, $p);
304
    }
305
 
306
    function addData($data)
307
    {
308
        $datalen = strlen($data);
309
        $p = 0;
310
        if (!$this->_haveOpts) {
311
            $have = strlen($this->Elements[NET_DIME_OPTS]);
312
            $this->Elements[NET_DIME_OPTS] .= substr($data, $p, $this->Elements[NET_DIME_OPTS_LEN] - $have);
313
            $this->_haveOpts = strlen($this->Elements[NET_DIME_OPTS]) == $this->Elements[NET_DIME_OPTS_LEN];
314
            if (!$this->_haveOpts) {
315
                return null;
316
            }
317
            $p += $this->OPTS_LENGTH - $have;
318
        }
319
        if (!$this->_haveID) {
320
            $have = strlen($this->Elements[NET_DIME_ID]);
321
            $this->Elements[NET_DIME_ID] .= substr($data, $p, $this->Elements[NET_DIME_ID_LEN] - $have);
322
            $this->_haveID = strlen($this->Elements[NET_DIME_ID]) == $this->Elements[NET_DIME_ID_LEN];
323
            if (!$this->_haveID) {
324
                return null;
325
            }
326
            $p += $this->ID_LENGTH - $have;
327
        }
328
        if (!$this->_haveType && $p < $datalen) {
329
            $have = strlen($this->Elements[NET_DIME_TYPE]);
330
            $this->Elements[NET_DIME_TYPE] .= substr($data, $p, $this->Elements[NET_DIME_TYPE_LEN] - $have);
331
            $this->_haveType = strlen($this->Elements[NET_DIME_TYPE]) == $this->Elements[NET_DIME_TYPE_LEN];
332
            if (!$this->_haveType) {
333
                return null;
334
            }
335
            $p += $this->TYPE_LENGTH - $have;
336
        }
337
        if (!$this->_haveData && $p < $datalen) {
338
            $have = strlen($this->Elements[NET_DIME_DATA]);
339
            $this->Elements[NET_DIME_DATA] .= substr($data, $p, $this->Elements[NET_DIME_DATA_LEN] - $have);
340
            $this->_haveData = strlen($this->Elements[NET_DIME_DATA]) == $this->Elements[NET_DIME_DATA_LEN];
341
            if (!$this->_haveData) {
342
                return null;
343
            }
344
            $p += $this->DATA_LENGTH - $have;
345
        }
346
        return substr($data, $p);
347
    }
348
}
349
 
350
/**
351
 * Net_DIME_Message enables you to manipulate and build a DIME encapsulated
352
 * message.
353
 *
354
 * @category   Networking
355
 * @package    Net_DIME
356
 * @author     Shane Caraveo <shane@caraveo.com>
357
 * @author     Ralf Hofmann <ralf.hofmann@verdisoft.com>
358
 * @author     Jan Schneider <jan@horde.org>
359
 * @copyright  2002-2007 The PHP Group
360
 * @license    http://www.opensource.org/licenses/bsd-license.php BSD License
361
 * @see        Net_DIME_Message
362
 * @link       http://pear.php.net/package/Net_DIME
363
 * @link       http://www.ietf.org/internet-drafts/draft-nielsen-dime-02.txt
364
 * @example    test/dime_message_test.php For example of usage.
365
 * @todo       - Lots of stuff needs to be tested.
366
 *             - Definitely have to go through DIME spec and make things work
367
 *               right, most importantly, sec 3.3.
368
 *             - Make examples, document.
369
 */
370
class Net_DIME_Message {
371
 
372
    var $record_size = 4096;
373
    var $parts = array();
374
    var $currentPart = -1;
375
    var $stream = null;
376
    var $_currentRecord;
377
    var $_proc = array();
378
    var $type;
379
    var $typestr;
380
    var $mb = 1;
381
    var $me = 0;
382
    var $cf = 0;
383
    var $id = null;
384
    var $debug = false;
385
 
386
    /**
387
     * Constructor.
388
     *
389
     * @todo Integrate with PHP streams.
390
     *
391
     * @param resource $stream      A file pointer.
392
     * @param integer $record_size
393
     * @param boolean $debug
394
     */
395
    function Net_DIME_Message($stream = null, $record_size = 4096,
396
                              $debug = false)
397
    {
398
        $this->stream = $stream;
399
        $this->record_size = $record_size;
400
        $this->debug = $debug;
401
    }
402
 
403
    function _makeRecord($data, $typestr = '', $id = null,
404
                         $type = NET_DIME_TYPE_UNKNOWN)
405
    {
406
        $record = new Net_DIME_Record($this->debug);
407
        if ($this->mb) {
408
            $record->setMB();
409
            // all subsequent records are not message begin!
410
            $this->mb = 0;
411
        }
412
        if ($this->me) {
413
            $record->setME();
414
        }
415
        if ($this->cf) {
416
            $record->setCF();
417
        }
418
        $record->setData($data);
419
        $record->setType($typestr,$type);
420
        if ($id) {
421
            $record->setID($id);
422
        }
423
 
424
        return $record->encode();
425
    }
426
 
427
    function startChunk($data, $typestr = '', $id = null,
428
                        $type = NET_DIME_TYPE_UNKNOWN)
429
    {
430
        $this->me = 0;
431
        $this->cf = 1;
432
        $this->type = $type;
433
        $this->typestr = $typestr;
434
        if ($id) {
435
            $this->id = $id;
436
        } else {
437
            $this->id = md5(time());
438
        }
439
 
440
        return $this->_makeRecord($data, $this->typestr, $this->id, $this->type);
441
    }
442
 
443
    function doChunk($data)
444
    {
445
        $this->me = 0;
446
        $this->cf = 1;
447
 
448
        return $this->_makeRecord($data, null, null, NET_DIME_TYPE_UNCHANGED);
449
    }
450
 
451
    function endChunk()
452
    {
453
        $this->cf = 0;
454
        $data = null;
455
        $rec = $this->_makeRecord($data, null, null, NET_DIME_TYPE_UNCHANGED);
456
        $this->id = 0;
457
        $this->cf = 0;
458
        $this->id = 0;
459
        $this->type = NET_DIME_TYPE_UNKNOWN;
460
        $this->typestr = null;
461
 
462
        return $rec;
463
    }
464
 
465
    function endMessage()
466
    {
467
        $this->me = 1;
468
        $data = null;
469
        $rec = $this->_makeRecord($data, null, null, NET_DIME_TYPE_NONE);
470
        $this->me = 0;
471
        $this->mb = 1;
472
        $this->id = 0;
473
 
474
        return $rec;
475
    }
476
 
477
    /**
478
     * Creates DIME records from a chunk of data and writes them to the stream
479
     * provided in the constructor.
480
     *
481
     * @param string $data
482
     * @param string $typestr
483
     * @param string $id
484
     * @param integer $type    One of the NET_DIME_TYPE_* constants.
485
     */
486
    function sendData($data, $typestr='', $id = null,
487
                      $type = NET_DIME_TYPE_UNKNOWN)
488
    {
489
        $len = strlen($data);
490
        if ($len > $this->record_size) {
491
            $chunk = substr($data, 0, $this->record_size);
492
            $p = $this->record_size;
493
            $rec = $this->startChunk($chunk, $typestr, $id, $type);
494
            fwrite($this->stream, $rec);
495
            while ($p < $len) {
496
                $chunk = substr($data, $p, $this->record_size);
497
                $p += $this->record_size;
498
                $rec = $this->doChunk($chunk);
499
                fwrite($this->stream, $rec);
500
            }
501
            $rec = $this->endChunk();
502
            fwrite($this->stream, $rec);
503
            return;
504
        }
505
        $rec = $this->_makeRecord($data, $typestr, $id, $type);
506
        fwrite($this->stream, $rec);
507
    }
508
 
509
    function sendEndMessage()
510
    {
511
        $rec = $this->endMessage();
512
        fwrite($this->stream, $rec);
513
    }
514
 
515
    /**
516
     * Reads a file, creates records and writes them to the stream provided in
517
     * the constructor.
518
     *
519
     * @param string $filename  A file name.
520
     * @param string $typestr
521
     * @param string $id
522
     * @param integer $type     One of the NET_DIME_TYPE_* constants.
523
     */
524
    function sendFile($filename, $typestr='', $id = null,
525
                      $type = NET_DIME_TYPE_UNKNOWN)
526
    {
527
        $f = fopen($filename, 'rb');
528
        if ($f) {
529
            if ($data = fread($f, $this->record_size)) {
530
                $this->startChunk($data, $typestr, $id, $type);
531
            }
532
            while ($data = fread($f, $this->record_size)) {
533
                $this->doChunk($data, $typestr, $id, $type);
534
            }
535
            $this->endChunk();
536
            fclose($f);
537
        }
538
    }
539
 
540
    /**
541
     * Encodes data in DIME.
542
     *
543
     * @param string $data
544
     * @param string $typestr
545
     * @param string $id
546
     * @param integer $type     One of the NET_DIME_TYPE_* constants.
547
     */
548
    function encodeData($data, $typestr = '', $id = null,
549
                        $type = NET_DIME_TYPE_UNKNOWN)
550
    {
551
        $len = strlen($data);
552
        $resp = '';
553
 
554
        if ($len > $this->record_size) {
555
            $chunk = substr($data, 0, $this->record_size);
556
            $p = $this->record_size;
557
            $resp .= $this->startChunk($chunk, $typestr, $id, $type);
558
            while ($p < $len) {
559
                $chunk = substr($data, $p, $this->record_size);
560
                $p += $this->record_size;
561
                $resp .= $this->doChunk($chunk);
562
            }
563
            $resp .= $this->endChunk();
564
        } else {
565
            $resp .= $this->_makeRecord($data, $typestr, $id, $type);
566
        }
567
 
568
        return $resp;
569
    }
570
 
571
    /**
572
     * Reads a file, creates records and writes them to the stream provided in
573
     * the constructor.
574
     *
575
     */
576
    function encodeFile($filename, $typestr = '', $id = null,
577
                        $type = NET_DIME_TYPE_UNKNOWN)
578
    {
579
        $f = fopen($filename, 'rb');
580
        if ($f) {
581
            if ($data = fread($f, $this->record_size)) {
582
                $resp = $this->startChunk($data, $typestr, $id, $type);
583
            }
584
            while ($data = fread($f, $this->record_size)) {
585
                $resp = $this->doChunk($data, $typestr, $id, $type);
586
            }
587
            $resp = $this->endChunk();
588
            fclose($f);
589
        }
590
 
591
        return $resp;
592
    }
593
 
594
    /**
595
     * Creates Net_DIME_Records from provided data.
596
     */
597
    function _processData(&$data)
598
    {
599
        $leftover = null;
600
        if (!$this->_currentRecord) {
601
            $this->_currentRecord = new Net_DIME_Record($this->debug);
602
            $data = $this->_currentRecord->decode($data);
603
        } else {
604
            $data = $this->_currentRecord->addData($data);
605
        }
606
 
607
        if ($this->_currentRecord->_haveData) {
608
            if (count($this->parts) == 0 &&
609
                !$this->_currentRecord->isStart()) {
610
                return PEAR::raiseError('First Message is not a DIME begin record!');
611
            }
612
 
613
            if ($this->_currentRecord->isEnd() &&
614
                $this->_currentRecord->getDataLength() == 0) {
615
                return;
616
            }
617
 
618
            if ($this->currentPart < 0 && !$this->_currentRecord->isChunk()) {
619
                $this->parts[] = array();
620
                $this->currentPart = count($this->parts) - 1;
621
                $this->parts[$this->currentPart]['id']   = $this->_currentRecord->getID();
622
                $this->parts[$this->currentPart]['type'] = $this->_currentRecord->getType();
623
                $this->parts[$this->currentPart]['data'] = $this->_currentRecord->getData();
624
                $this->currentPart = -1;
625
            } else {
626
                if ($this->currentPart < 0) {
627
                    $this->parts[] = array();
628
                    $this->currentPart = count($this->parts) - 1;
629
                    $this->parts[$this->currentPart]['id']   = $this->_currentRecord->getID();
630
                    $this->parts[$this->currentPart]['type'] = $this->_currentRecord->getType();
631
                    $this->parts[$this->currentPart]['data'] = $this->_currentRecord->getData();
632
                } else {
633
                    $this->parts[$this->currentPart]['data'] .= $this->_currentRecord->getData();
634
                    if (!$this->_currentRecord->isChunk()) {
635
                        // We reached the end of the chunk.
636
                        $this->currentPart = -1;
637
                    }
638
                }
639
            }
640
            if (!$this->_currentRecord->isEnd()) {
641
                $this->_currentRecord = null;
642
            }
643
        }
644
 
645
        return;
646
    }
647
 
648
    /**
649
     * Decodes a DIME encode string of data.
650
     */
651
    function decodeData(&$data)
652
    {
653
        while (strlen($data) >= NET_DIME_RECORD_HEADER) {
654
            $err = $this->_processData($data);
655
            if (PEAR::isError($err)) {
656
                return $err;
657
            }
658
        }
659
    }
660
 
661
    /**
662
     * Reads the stream and creates an array of records.
663
     *
664
     * The method can accept the start of a previously read buffer. This is
665
     * useful in situations where you need to read headers before discovering
666
     * that the data is DIME encoded, such as in the case of reading an HTTP
667
     * response.
668
     */
669
    function read($buf = null)
670
    {
671
        while ($data = fread($this->stream, 8192)) {
672
            if ($buf) {
673
                $data = $buf . $data;
674
                $buf = null;
675
            }
676
            if ($this->debug) {
677
                echo 'read: ' . strlen($data) . " bytes\n";
678
            }
679
            $err = $this->decodeData($data);
680
            if (PEAR::isError($err)) {
681
                return $err;
682
            }
683
 
684
            // Store any leftover data to be used again.
685
            // Should be < NET_DIME_RECORD_HEADER bytes.
686
            $buf = $data;
687
        }
688
 
689
        if (!$this->_currentRecord || !$this->_currentRecord->isEnd()) {
690
            return PEAR::raiseError('reached stream end without end record');
691
        }
692
    }
693
}