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