1<?php 2 3final class ArcanistWorkingCopyPath 4 extends Phobject { 5 6 private $path; 7 private $mode; 8 private $data; 9 private $binary; 10 private $dataAsLines; 11 private $charMap; 12 private $lineMap; 13 14 public function setPath($path) { 15 $this->path = $path; 16 return $this; 17 } 18 19 public function getPath() { 20 return $this->path; 21 } 22 23 public function setData($data) { 24 $this->data = $data; 25 return $this; 26 } 27 28 public function getData() { 29 if ($this->data === null) { 30 throw new Exception( 31 pht( 32 'No data provided for path "%s".', 33 $this->getDescription())); 34 } 35 36 return $this->data; 37 } 38 39 public function getDataAsLines() { 40 if ($this->dataAsLines === null) { 41 $lines = phutil_split_lines($this->getData()); 42 $this->dataAsLines = $lines; 43 } 44 45 return $this->dataAsLines; 46 } 47 48 public function setMode($mode) { 49 $this->mode = $mode; 50 return $this; 51 } 52 53 public function getMode() { 54 if ($this->mode === null) { 55 throw new Exception( 56 pht( 57 'No mode provided for path "%s".', 58 $this->getDescription())); 59 } 60 61 return $this->mode; 62 } 63 64 public function isExecutable() { 65 $mode = $this->getMode(); 66 return (bool)($mode & 0111); 67 } 68 69 public function isBinary() { 70 if ($this->binary === null) { 71 $data = $this->getData(); 72 $is_binary = ArcanistDiffUtils::isHeuristicBinaryFile($data); 73 $this->binary = $is_binary; 74 } 75 76 return $this->binary; 77 } 78 79 public function getMimeType() { 80 if ($this->mimeType === null) { 81 // TOOLSETS: This is not terribly efficient on real repositories since 82 // it re-writes files which are often already on disk, but is good for 83 // unit tests. 84 85 $tmp = new TempFile(); 86 Filesystem::writeFile($tmp, $this->getData()); 87 $mime = Filesystem::getMimeType($tmp); 88 89 $this->mimeType = $mime; 90 } 91 92 return $this->mimeType; 93 } 94 95 96 public function getBasename() { 97 return basename($this->getPath()); 98 } 99 100 public function getLineAndCharFromOffset($offset) { 101 if ($this->charMap === null) { 102 $char_map = array(); 103 $line_map = array(); 104 105 $lines = $this->getDataAsLines(); 106 107 $line_number = 0; 108 $line_start = 0; 109 foreach ($lines as $line) { 110 $len = strlen($line); 111 $line_map[] = $line_start; 112 $line_start += $len; 113 for ($ii = 0; $ii < $len; $ii++) { 114 $char_map[] = $line_number; 115 } 116 $line_number++; 117 } 118 119 $this->charMap = $char_map; 120 $this->lineMap = $line_map; 121 } 122 123 $line = $this->charMap[$offset]; 124 $char = $offset - $this->lineMap[$line]; 125 126 return array($line, $char); 127 } 128 129} 130