1 <?php
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
22
23 interface phpMorphy_Fsa_Interface {
24 25 26 27
28 function getRootTrans();
29
30 31 32 33
34 function getRootState();
35
36 37 38 39
40 function getAlphabet();
41
42 43 44 45 46 47
48 function getAnnot($trans);
49
50 51 52 53 54 55 56 57
58 function walk($trans, $word, $readAnnot = true);
59
60 61 62 63 64 65 66 67 68 69 70
71 function collect($startNode, $callback, $readAnnot = true, $path = '');
72
73 74 75 76 77 78
79 function readState($index);
80
81 82 83 84 85 86
87 function unpackTranses($rawTranses);
88 }
89
90 abstract class phpMorphy_Fsa implements phpMorphy_Fsa_Interface {
91 const = 128;
92
93 protected
94 $resource,
95 $header,
96 $fsa_start,
97 $root_trans,
98 $alphabet;
99
100 protected function phpMorphy_Fsa($resource, $header) {
101 $this->resource = $resource;
102 $this->header = $header;
103 $this->fsa_start = $header['fsa_offset'];
104 $this->root_trans = $this->readRootTrans();
105 }
106
107
108 static function create(phpMorphy_Storage $storage, $lazy) {
109 if($lazy) {
110 return new phpMorphy_Fsa_Proxy($storage);
111 }
112
113 $header = phpMorphy_Fsa::readHeader(
114 $storage->read(0, self::HEADER_SIZE, true)
115 );
116
117 if(!phpMorphy_Fsa::validateHeader($header)) {
118 throw new phpMorphy_Exception('Invalid fsa format');
119 }
120
121 if($header['flags']['is_sparse']) {
122 $type = 'sparse';
123 } else if($header['flags']['is_tree']) {
124 $type = 'tree';
125 } else {
126 throw new phpMorphy_Exception('Only sparse or tree fsa`s supported');
127 }
128
129 $storage_type = $storage->getTypeAsString();
130 $file_path = dirname(__FILE__) . "/access/fsa_{$type}_{$storage_type}.php";
131 $clazz = 'phpMorphy_Fsa_' . ucfirst($type) . '_' . ucfirst($storage_type);
132
133 require_once($file_path);
134 return new $clazz(
135 $storage->getResource(),
136 $header
137 );
138 }
139
140 function getRootTrans() { return $this->root_trans; }
141
142 function getRootState() {
143 return $this->createState($this->getRootStateIndex());
144 }
145
146 function getAlphabet() {
147 if(!isset($this->alphabet)) {
148 $this->alphabet = str_split($this->readAlphabet());
149 }
150
151 return $this->alphabet;
152 }
153
154 protected function createState($index) {
155 require_once(PHPMORPHY_DIR . '/fsa/fsa_state.php');
156 return new phpMorphy_State($this, $index);
157 }
158
159 static protected function ($headerRaw) {
160 if($GLOBALS['__phpmorphy_strlen']($headerRaw) != self::HEADER_SIZE) {
161 throw new phpMorphy_Exception('Invalid header string given');
162 }
163
164 $header = unpack(
165 'a4fourcc/Vver/Vflags/Valphabet_offset/Vfsa_offset/Vannot_offset/Valphabet_size/Vtranses_count/Vannot_length_size/' .
166 'Vannot_chunk_size/Vannot_chunks_count/Vchar_size/Vpadding_size/Vdest_size/Vhash_size',
167 $headerRaw
168 );
169
170 if(false === $header) {
171 throw new phpMorphy_Exception('Can`t unpack header');
172 }
173
174 $flags = array();
175 $raw_flags = $header['flags'];
176 $flags['is_tree'] = $raw_flags & 0x01 ? true : false;
177 $flags['is_hash'] = $raw_flags & 0x02 ? true : false;
178 $flags['is_sparse'] = $raw_flags & 0x04 ? true : false;
179 $flags['is_be'] = $raw_flags & 0x08 ? true : false;
180
181 $header['flags'] = $flags;
182
183 $header['trans_size'] = $header['char_size'] + $header['padding_size'] + $header['dest_size'] + $header['hash_size'];
184
185 return $header;
186 }
187
188
189 static protected function ($header) {
190 if(
191 'meal' != $header['fourcc'] ||
192 3 != $header['ver'] ||
193 $header['char_size'] != 1 ||
194 $header['padding_size'] > 0 ||
195 $header['dest_size'] != 3 ||
196 $header['hash_size'] != 0 ||
197 $header['annot_length_size'] != 1 ||
198 $header['annot_chunk_size'] != 1 ||
199 $header['flags']['is_be'] ||
200 $header['flags']['is_hash'] ||
201 1 == 0
202 ) {
203 return false;
204 }
205
206 return true;
207 }
208
209 protected function getRootStateIndex() { return 0; }
210
211 abstract protected function readRootTrans();
212 abstract protected function readAlphabet();
213 };
214
215 class phpMorphy_Fsa_WordsCollector {
216 protected
217 $items = array(),
218 $limit;
219
220 function phpMorphy_Fsa_WordsCollector($collectLimit) {
221 $this->limit = $collectLimit;
222 }
223
224 function collect($word, $annot) {
225 if(count($this->items) < $this->limit) {
226 $this->items[$word] = $annot;
227 return true;
228 } else {
229 return false;
230 }
231 }
232
233 function getItems() { return $this->items; }
234 function clear() { $this->items = array(); }
235 function getCallback() { return array($this, 'collect'); }
236 };
237
238 class phpMorphy_Fsa_Decorator implements phpMorphy_Fsa_Interface {
239 protected $fsa;
240
241 function phpMorphy_Fsa_Decorator(phpMorphy_Fsa_Interface $fsa) {
242 $this->fsa = $fsa;
243 }
244
245 function getRootTrans() { return $this->fsa->getRootTrans(); }
246 function getRootState() { return $this->fsa->getRootState(); }
247 function getAlphabet() { return $this->fsa->getAlphabet(); }
248 function getAnnot($trans) { return $this->fsa->getAnnot($trans); }
249 function walk($start, $word, $readAnnot = true) { return $this->fsa->walk($start, $word, $readAnnot); }
250 function collect($start, $callback, $readAnnot = true, $path = '') { return $this->fsa->collect($start, $callback, $readAnnot, $path); }
251 function readState($index) { return $this->fsa->readState($index); }
252 function unpackTranses($transes) { return $this->fsa->unpackTranses($transes); }
253 };
254
255 class phpMorphy_Fsa_Proxy extends phpMorphy_Fsa_Decorator {
256 protected $storage;
257
258 function __construct(phpMorphy_Storage $storage) {
259 $this->storage = $storage;
260 unset($this->fsa);
261 }
262
263 function __get($propName) {
264 if($propName == 'fsa') {
265 $this->fsa = phpMorphy_Fsa::create($this->storage, false);
266
267 unset($this->storage);
268 return $this->fsa;
269 }
270
271 throw new phpMorphy_Exception("Unknown prop name '$propName'");
272 }
273 }
274
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the
Silverstripe Forums to ask development related questions.
-