home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / phing / system / io / Win32FileSystem.php < prev    next >
Encoding:
PHP Script  |  2007-10-25  |  15.2 KB  |  478 lines

  1. <?php
  2. /*
  3.  *  $Id: Win32FileSystem.php 267 2007-10-25 01:49:31Z hans $
  4.  *
  5.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  6.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  7.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  8.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  9.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  10.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  11.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  14.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  15.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16.  *
  17.  * This software consists of voluntary contributions made by many individuals
  18.  * and is licensed under the LGPL. For more information please see
  19.  * <http://phing.info>. 
  20.  */
  21.  
  22. include_once 'phing/system/io/FileSystem.php';
  23.  
  24. /**
  25.  *  @package   phing.system.io
  26.  */
  27. class Win32FileSystem extends FileSystem {
  28.  
  29.     protected $slash;
  30.     protected $altSlash;
  31.     protected $semicolon;
  32.  
  33.     private static $driveDirCache = array();
  34.  
  35.     function __construct() {
  36.         $this->slash = self::getSeparator();
  37.         $this->semicolon = self::getPathSeparator();
  38.         $this->altSlash = ($this->slash === '\\') ? '/' : '\\';
  39.     }
  40.  
  41.     function isSlash($c) {
  42.         return ($c == '\\') || ($c == '/');
  43.     }
  44.  
  45.     function isLetter($c) {
  46.         return ((ord($c) >= ord('a')) && (ord($c) <= ord('z')))
  47.                || ((ord($c) >= ord('A')) && (ord($c) <= ord('Z')));
  48.     }
  49.  
  50.     function slashify($p) {
  51.         if ((strlen($p) > 0) && ($p{0} != $this->slash)) {
  52.             return $this->slash.$p;
  53.         }
  54.         else {
  55.             return $p;
  56.         }
  57.     }
  58.  
  59.     /* -- Normalization and construction -- */
  60.  
  61.     function getSeparator() {
  62.         // the ascii value of is the \
  63.         return chr(92);
  64.     }
  65.  
  66.     function getPathSeparator() {
  67.         return ';';
  68.     }
  69.  
  70.     /**
  71.      * A normal Win32 pathname contains no duplicate slashes, except possibly
  72.      * for a UNC prefix, and does not end with a slash.  It may be the empty
  73.      * string.  Normalized Win32 pathnames have the convenient property that
  74.      * the length of the prefix almost uniquely identifies the type of the path
  75.      * and whether it is absolute or relative:
  76.      *
  77.      *    0  relative to both drive and directory
  78.      *    1  drive-relative (begins with '\\')
  79.      *    2  absolute UNC (if first char is '\\'), else directory-relative (has form "z:foo")
  80.      *    3  absolute local pathname (begins with "z:\\")
  81.      */
  82.     function normalizePrefix($strPath, $len, &$sb) {
  83.         $src = 0;
  84.         while (($src < $len) && $this->isSlash($strPath{$src})) {
  85.             $src++;
  86.         }
  87.         $c = "";
  88.         if (($len - $src >= 2)
  89.                 && $this->isLetter($c = $strPath{$src})
  90.                 && $strPath{$src + 1} === ':') {
  91.             /* Remove leading slashes if followed by drive specifier.
  92.              * This hack is necessary to support file URLs containing drive
  93.              * specifiers (e.g., "file://c:/path").  As a side effect,
  94.              * "/c:/path" can be used as an alternative to "c:/path". */
  95.             $sb .= $c;
  96.             $sb .= ':';
  97.             $src += 2;
  98.         }
  99.         else {
  100.             $src = 0;
  101.             if (($len >= 2)
  102.                     && $this->isSlash($strPath{0})
  103.                     && $this->isSlash($strPath{1})) {
  104.                 /* UNC pathname: Retain first slash; leave src pointed at
  105.                  * second slash so that further slashes will be collapsed
  106.                  * into the second slash.  The result will be a pathname
  107.                  * beginning with "\\\\" followed (most likely) by a host
  108.                  * name. */
  109.                 $src = 1;
  110.                 $sb.=$this->slash;
  111.             }
  112.         }
  113.         return $src;
  114.     }
  115.  
  116.     /** Normalize the given pathname, whose length is len, starting at the given
  117.        offset; everything before this offset is already normal. */
  118.     protected function normalizer($strPath, $len, $offset) {
  119.         if ($len == 0) {
  120.             return $strPath;
  121.         }
  122.         if ($offset < 3) {
  123.             $offset = 0;    //Avoid fencepost cases with UNC pathnames
  124.         }
  125.         $src = 0;
  126.         $slash = $this->slash;
  127.         $sb = "";
  128.  
  129.         if ($offset == 0) {
  130.             // Complete normalization, including prefix
  131.             $src = $this->normalizePrefix($strPath, $len, $sb);
  132.         } else {
  133.             // Partial normalization
  134.             $src = $offset;
  135.             $sb .= substr($strPath, 0, $offset);
  136.         }
  137.  
  138.         // Remove redundant slashes from the remainder of the path, forcing all
  139.         // slashes into the preferred slash
  140.         while ($src < $len) {
  141.             $c = $strPath{$src++};
  142.             if ($this->isSlash($c)) {
  143.                 while (($src < $len) && $this->isSlash($strPath{$src})) {
  144.                     $src++;
  145.                 }
  146.                 if ($src === $len) {
  147.                     /* Check for trailing separator */
  148.                     $sn = (int) strlen($sb);
  149.                     if (($sn == 2) && ($sb{1} === ':')) {
  150.                         // "z:\\"
  151.                         $sb .= $slash;
  152.                         break;
  153.                     }
  154.                     if ($sn === 0) {
  155.                         // "\\"
  156.                         $sb .= $slash;
  157.                         break;
  158.                     }
  159.                     if (($sn === 1) && ($this->isSlash($sb{0}))) {
  160.                         /* "\\\\" is not collapsed to "\\" because "\\\\" marks
  161.                         the beginning of a UNC pathname.  Even though it is
  162.                         not, by itself, a valid UNC pathname, we leave it as
  163.                         is in order to be consistent with the win32 APIs,
  164.                         which treat this case as an invalid UNC pathname
  165.                         rather than as an alias for the root directory of
  166.                         the current drive. */
  167.                         $sb .= $slash;
  168.                         break;
  169.                     }
  170.                     // Path does not denote a root directory, so do not append
  171.                     // trailing slash
  172.                     break;
  173.                 } else {
  174.                     $sb .= $slash;
  175.                 }
  176.             } else {
  177.                 $sb.=$c;
  178.             }
  179.         }
  180.         $rv = (string) $sb;
  181.         return $rv;
  182.     }
  183.  
  184.     /**
  185.      * Check that the given pathname is normal.  If not, invoke the real
  186.      * normalizer on the part of the pathname that requires normalization.
  187.      * This way we iterate through the whole pathname string only once.
  188.      * @param string $strPath
  189.      * @return string
  190.      */
  191.     function normalize($strPath) {
  192.         $n = strlen($strPath);
  193.         $slash    = $this->slash;
  194.         $altSlash = $this->altSlash;
  195.         $prev = 0;
  196.         for ($i = 0; $i < $n; $i++) {
  197.             $c = $strPath{$i};
  198.             if ($c === $altSlash) {
  199.                 return $this->normalizer($strPath, $n, ($prev === $slash) ? $i - 1 : $i);
  200.             }
  201.             if (($c === $slash) && ($prev === $slash) && ($i > 1)) {
  202.                 return $this->normalizer($strPath, $n, $i - 1);
  203.             }
  204.             if (($c === ':') && ($i > 1)) {
  205.                 return $this->normalizer($strPath, $n, 0);
  206.             }
  207.             $prev = $c;
  208.         }
  209.         if ($prev === $slash) {
  210.             return $this->normalizer($strPath, $n, $n - 1);
  211.         }
  212.         return $strPath;
  213.     }
  214.  
  215.     function prefixLength($strPath) {
  216.         $path  = (string) $strPath;
  217.         $slash = (string) $this->slash;
  218.         $n = (int) strlen($path);
  219.         if ($n === 0) {
  220.             return 0;
  221.         }
  222.         $c0 = $path{0};
  223.         $c1 = ($n > 1) ? $path{1} :
  224.               0;
  225.         if ($c0 === $slash) {
  226.             if ($c1 === $slash) {
  227.                 return 2;            // absolute UNC pathname "\\\\foo"
  228.             }
  229.             return 1;                // drive-relative "\\foo"
  230.         }
  231.  
  232.         if ($this->isLetter($c0) && ($c1 === ':')) {
  233.             if (($n > 2) && ($path{2}) === $slash) {
  234.                 return 3;            // Absolute local pathname "z:\\foo" */
  235.             }
  236.             return 2;                // Directory-relative "z:foo"
  237.         }
  238.         return 0;                    // Completely relative
  239.     }
  240.  
  241.     function resolve($parent, $child) {
  242.         $parent = (string) $parent;
  243.         $child  = (string) $child;
  244.         $slash  = (string) $this->slash;
  245.  
  246.         $pn = (int) strlen($parent);
  247.         if ($pn === 0) {
  248.             return $child;
  249.         }
  250.         $cn = (int) strlen($child);
  251.         if ($cn === 0) {
  252.             return $parent;
  253.         }
  254.  
  255.         $c = $child;
  256.         if (($cn > 1) && ($c{0} === $slash)) {
  257.             if ($c{1} === $slash) {
  258.                 // drop prefix when child is a UNC pathname
  259.                 $c = substr($c, 2);
  260.             }
  261.             else {
  262.                 //Drop prefix when child is drive-relative */
  263.                 $c = substr($c, 1);
  264.             }
  265.         }
  266.  
  267.         $p = $parent;
  268.         if ($p{$pn - 1} === $slash) {
  269.             $p = substr($p, 0, $pn - 1);
  270.         }
  271.         return $p.$this->slashify($c);
  272.     }
  273.  
  274.     function getDefaultParent() {
  275.         return (string) ("".$this->slash);
  276.     }
  277.  
  278.     function fromURIPath($strPath) {
  279.         $p = (string) $strPath;
  280.         if ((strlen($p) > 2) && ($p{2} === ':')) {
  281.  
  282.             // "/c:/foo" --> "c:/foo"
  283.             $p = substr($p,1);
  284.  
  285.             // "c:/foo/" --> "c:/foo", but "c:/" --> "c:/"
  286.             if ((strlen($p) > 3) && StringHelper::endsWith('/', $p)) {
  287.                 $p = substr($p, 0, strlen($p) - 1);
  288.             }
  289.         } elseif ((strlen($p) > 1) && StringHelper::endsWith('/', $p)) {
  290.             // "/foo/" --> "/foo"
  291.             $p = substr($p, 0, strlen($p) - 1);
  292.         }
  293.         return (string) $p;
  294.     }
  295.  
  296.  
  297.     /* -- Path operations -- */
  298.  
  299.     function isAbsolute(PhingFile $f) {
  300.         $pl = (int) $f->getPrefixLength();
  301.         $p  = (string) $f->getPath();
  302.         return ((($pl === 2) && ($p{0} === $this->slash)) || ($pl === 3) || ($pl === 1 && $p{0} === $this->slash));
  303.     }
  304.  
  305.     /** private */
  306.     function _driveIndex($d) {
  307.         $d = (string) $d{0};
  308.         if ((ord($d) >= ord('a')) && (ord($d) <= ord('z'))) {
  309.             return ord($d) - ord('a');
  310.         }
  311.         if ((ord($d) >= ord('A')) && (ord($d) <= ord('Z'))) {
  312.             return ord($d) - ord('A');
  313.         }
  314.         return -1;
  315.     }
  316.  
  317.     /** private */
  318.     function _getDriveDirectory($drive) {
  319.         $drive = (string) $drive{0};
  320.         $i = (int) $this->_driveIndex($drive);
  321.         if ($i < 0) {
  322.             return null;
  323.         }
  324.  
  325.         $s = (isset(self::$driveDirCache[$i]) ? self::$driveDirCache[$i] : null);
  326.  
  327.         if ($s !== null) {
  328.             return $s;
  329.         }
  330.  
  331.         $s = $this->_getDriveDirectory($i + 1);
  332.         self::$driveDirCache[$i] = $s;
  333.         return $s;
  334.     }
  335.  
  336.     function _getUserPath() {
  337.         //For both compatibility and security, we must look this up every time
  338.         return (string) $this->normalize(Phing::getProperty("user.dir"));
  339.     }
  340.  
  341.     function _getDrive($path) {
  342.         $path = (string) $path;
  343.         $pl   = $this->prefixLength($path);
  344.         return ($pl === 3) ? substr($path, 0, 2) : null;
  345.     }
  346.  
  347.     function resolveFile(PhingFile $f) {
  348.         $path = $f->getPath();
  349.         $pl   = (int) $f->getPrefixLength();
  350.  
  351.         if (($pl === 2) && ($path{0} === $this->slash)) {
  352.             return $path;            // UNC
  353.         }
  354.  
  355.         if ($pl === 3) {
  356.             return $path;            // Absolute local
  357.         }
  358.  
  359.         if ($pl === 0) {
  360.             return (string) ($this->_getUserPath().$this->slashify($path)); //Completely relative
  361.         }
  362.  
  363.         if ($pl === 1) {            // Drive-relative
  364.             $up = (string) $this->_getUserPath();
  365.             $ud = (string) $this->_getDrive($up);
  366.             if ($ud !== null) {
  367.                 return (string) $ud.$path;
  368.             }
  369.             return (string) $up.$path;            //User dir is a UNC path
  370.         }
  371.  
  372.         if ($pl === 2) {                // Directory-relative
  373.             $up = (string) $this->_getUserPath();
  374.             $ud = (string) $this->_getDrive($up);
  375.             if (($ud !== null) && StringHelper::startsWith($ud, $path)) {
  376.                 return (string) ($up . $this->slashify(substr($path,2)));
  377.             }
  378.             $drive = (string) $path{0};
  379.             $dir   = (string) $this->_getDriveDirectory($drive);
  380.  
  381.             $np = (string) "";
  382.             if ($dir !== null) {
  383.                 /* When resolving a directory-relative path that refers to a
  384.                 drive other than the current drive, insist that the caller
  385.                 have read permission on the result */
  386.                 $p = (string) $drive . (':'.$dir.$this->slashify(substr($path,2)));
  387.  
  388.                 if (!$this->checkAccess($p, false)) {
  389.                     // FIXME
  390.                     // throw security error
  391.                     die("Can't resolve path $p");
  392.                 }
  393.                 return $p;
  394.             }
  395.             return (string) $drive.':'.$this->slashify(substr($path,2)); //fake it
  396.         }
  397.         
  398.         throw new Exception("Unresolvable path: " . $path);
  399.     }
  400.  
  401.     /* -- most of the following is mapped to the functions mapped th php natives in FileSystem */
  402.  
  403.     /* -- Attribute accessors -- */
  404.  
  405.     function setReadOnly($f) {
  406.         // dunno how to do this on win
  407.         throw new Exception("WIN32FileSystem doesn't support read-only yet.");
  408.     }
  409.  
  410.     /* -- Filesystem interface -- */
  411.  
  412.     protected function _access($path) {
  413.         if (!$this->checkAccess($path, false)) {
  414.             throw new Exception("Can't resolve path $p");
  415.         }
  416.         return true;
  417.     }
  418.  
  419.     function _nativeListRoots() {
  420.         // FIXME
  421.     }
  422.  
  423.     function listRoots() {
  424.         $ds = _nativeListRoots();
  425.         $n = 0;
  426.         for ($i = 0; $i < 26; $i++) {
  427.             if ((($ds >> $i) & 1) !== 0) {
  428.                 if (!$this->access((string)( chr(ord('A') + $i) . ':' . $this->slash))) {
  429.                     $ds &= ~(1 << $i);
  430.                 } else {
  431.                     $n++;
  432.                 }
  433.             }
  434.         }
  435.         $fs = array();
  436.         $j = (int) 0;
  437.         $slash = (string) $this->slash;
  438.         for ($i = 0; $i < 26; $i++) {
  439.             if ((($ds >> $i) & 1) !== 0) {
  440.                 $fs[$j++] = new PhingFile(chr(ord('A') + $i) . ':' . $this->slash);
  441.             }
  442.         }
  443.         return $fs;
  444.     }
  445.  
  446.     /* -- Basic infrastructure -- */
  447.  
  448.     /** compares file paths lexicographically */
  449.     function compare(PhingFile $f1, PhingFile $f2) {
  450.         $f1Path = $f1->getPath();
  451.         $f2Path = $f2->getPath();
  452.         return (boolean) strcasecmp((string) $f1Path, (string) $f2Path);        
  453.     }
  454.  
  455.  
  456.     /**
  457.      * returns the contents of a directory in an array
  458.      */
  459.     function lister($f) {
  460.         $dir = @opendir($f->getAbsolutePath());
  461.         if (!$dir) {
  462.             throw new Exception("Can't open directory " . $f->__toString());
  463.         }
  464.         $vv = array();
  465.         while (($file = @readdir($dir)) !== false) {
  466.             if ($file == "." || $file == "..") {
  467.                 continue;
  468.             }
  469.             $vv[] = (string) $file;
  470.         }
  471.         @closedir($dir);
  472.         return $vv;
  473.     }
  474.     
  475. }
  476.  
  477. ?>
  478.