1<?php
2/**
3 * Write data to a file and save as an ar
4 *
5 * PHP versions 4 and 5
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA
20 *
21 * @category   File Formats
22 * @package    File_Archive
23 * @author     Pablo Fischer <pablo@pablo.com.mx>
24 * @copyright  1997-2005 The PHP Group
25 * @license    http://www.gnu.org/copyleft/lesser.html  LGPL
26 * @version    CVS: $Id:
27 * @link       http://pear.php.net/package/File_Archive
28 */
29
30require_once "File/Archive/Writer/Archive.php";
31
32/**
33 * Write the files as an AR archive
34 */
35class File_Archive_Writer_Ar extends File_Archive_Writer_Archive
36{
37
38    /**
39     * @var    string   Current data of the file.
40     * @access private
41     */
42    var $_buffer = "";
43
44    /**
45     * @var    string   Filename of the current filename
46     * @access private
47     */
48    var $_currentFilename = null;
49
50    /**
51     * @var    boolean  Flag: use buffer or not.
52     * @access private
53     */
54    var $_useBuffer;
55
56    /**
57     * @var    array    Stats of the current filename
58     * @access private
59     */
60    var $_currentStat = array ();
61
62    /**
63     * @var    boolean  Flag: beginning of the archive or not
64     * @access private
65     */
66    var $_atStart = true;
67
68    /**
69     * Returns the header of the current file.
70     *
71     * More Info:
72     *  http://publibn.boulder.ibm.com/doc_link/en_US/a_doc_lib/files/aixfiles/ar_IA64.htm
73     *
74     * @access  private
75     * @param   string  $filename  Name of the current file
76     * @param   array   $stat      Stat array of the current file
77     * @return  string  The built header struct
78     */
79    function arHeader ($filename, $stat)
80    {
81        $mode = isset($stat[2]) ? $stat[2] : 0x8000;
82        $uid  = isset($stat[4]) ? $stat[4] : 0;
83        $gid  = isset($stat[5]) ? $stat[5] : 0;
84        $size = $stat[7];
85        $time = isset($stat[9]) ? $stat[9] : time();
86
87        $struct = "";
88        $currentSize = $size;
89        //if file length is > than 16..
90        if (strlen($filename) > 16) {
91            $currentSize += strlen($filename);
92            $struct .= sprintf("#1/%-13d", strlen($filename));
93            $struct .= sprintf("%-12d%-6d%-6d%-8s%-10d",
94                               $time, $uid, $gid, $mode, $currentSize);
95            $struct .=  "`\n".$filename;
96        } else {
97            $struct .= sprintf("%-16s", $filename);
98            $struct .= sprintf("%-12d%-6d%-6d%-8s%-10d`\n",
99                               $time, $uid, $gid, $mode, $size);
100        }
101        return $struct;
102    }
103
104    /**
105     * Returns the footer of the current file, the footer depends
106     * of the size of the file
107     *
108     * @access  private
109     * @param   string   $filename Name of the file, the footer depends on its length
110     * @param   int      $size     Size of the current file, here the size does matters!
111     * @return  string   The footer struct
112     */
113    function arFooter($filename, $size)
114    {
115        $size = (strlen ($filename) > 16) ? $size + strlen($filename) : $size;
116
117        return ($size % 2 == 1) ? "\n" : "";
118    }
119
120
121    /**
122     * Flush the memory we have in the ar.
123     *
124     * Build the buffer if its called at the end or initialize
125     * it if we are just creating it from the start.
126     */
127    function flush()
128    {
129        if ($this->_atStart) {
130            $this->innerWriter->writeData("!<arch>\n");
131            $this->_atStart = false;
132        }
133        if ($this->_currentFilename !== null) {
134            $this->_currentStat[7] = strlen($this->_buffer);
135            if ($this->_useBuffer) {
136                $this->innerWriter->writeData(
137                                              $this->arHeader($this->_currentFilename, $this->_currentStat)
138                                              );
139                $this->innerWriter->writeData($this->_buffer);
140            }
141            $this->innerWriter->writeData($this->arFooter($this->_currentFilename, $this->_currentStat[7]));
142        }
143        $this->_buffer = "";
144    }
145
146    /**
147     * @see File_Archive_Writer::newFile()
148     *
149     */
150    function newFile($filename, $stat = array (),
151                     $mime = "application/octet-stream")
152    {
153        $this->flush();
154        /*
155         * If the file is empty, there's no reason to have a buffer
156         * or use memory
157         */
158        $this->_useBuffer = !isset($stats[7]);
159        /*
160         * Becaue ar fileformats doesn't support files in directories,
161         * then we need to just save with the filename an ommit the
162         * directory
163         */
164        $this->_currentFilename = basename($filename);
165        $this->_currentStat = $stat;
166
167        if(!$this->_useBuffer) {
168            return $this->innerWriter->writeData($this->arHeader($filename, $stat));
169        }
170    }
171
172    /**
173     * @see File_Archive_Writer::close()
174     */
175    function close()
176    {
177        $this->flush();
178        parent::close();
179    }
180
181    /**
182     * @see File_Archive_Writer::writeData()
183     */
184    function writeData($data)
185    {
186        if ($this->_useBuffer) {
187            $this->_buffer .= $data;
188        } else {
189            $this->innerWriter->writeData($data);
190        }
191
192    }
193    /**
194     * @see File_Archive_Writer::writeFile()
195     */
196    function writeFile($filename)
197    {
198        if ($this->_useBuffer) {
199            $this->_buffer .= file_get_contents($filename);
200        } else {
201            $this->innerWriter->writeFile($filename);
202        }
203    }
204}