PageRenderTime 52ms CodeModel.GetById 2ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 1ms

/tags/stable-1.0.3/Client/Config/PHPIniFile.cs

#
C# | 648 lines | 553 code | 72 blank | 23 comment | 57 complexity | b61e3900a4e755b5b7b54a3e342fa43c MD5 | raw file
  1//-----------------------------------------------------------------------
  2// <copyright>
  3// Copyright (C) Ruslan Yakushev for the PHP Manager for IIS project.
  4//
  5// This file is subject to the terms and conditions of the Microsoft Public License (MS-PL).
  6// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL for more details.
  7// </copyright>
  8//----------------------------------------------------------------------- 
  9
 10using System;
 11using System.Collections;
 12using System.Collections.Generic;
 13using System.Globalization;
 14using System.IO;
 15using System.Text;
 16
 17namespace Web.Management.PHP.Config
 18{
 19
 20    internal sealed class PHPIniFile : IRemoteObject
 21    {
 22        private object[] _data;
 23        private const int IndexSettings = 0;
 24        private const int IndexExtensions = 1;
 25        private const int Size = 2;
 26
 27        private RemoteObjectCollection<PHPIniSetting> _settings;
 28        private RemoteObjectCollection<PHPIniExtension> _extensions;
 29
 30        private List<PHPIniBase> _rawEntries;
 31        private string _filename;
 32
 33        public PHPIniFile()
 34        {
 35            _data = new object[Size];
 36        }
 37
 38        public PHPIniFile(string filename)
 39            : this()
 40        {
 41            _filename = filename;
 42        }
 43
 44        public RemoteObjectCollection<PHPIniExtension> Extensions
 45        {
 46            get
 47            {
 48                if (_extensions == null)
 49                {
 50                    _extensions = new RemoteObjectCollection<PHPIniExtension>((ArrayList)_data[IndexExtensions]);
 51                }
 52
 53                return _extensions;
 54            }
 55        }
 56
 57        public string FileName
 58        {
 59            get
 60            {
 61                return _filename;
 62            }
 63        }
 64
 65        private IList<PHPIniBase> RawEntries
 66        {
 67            get
 68            {
 69                if (_rawEntries == null)
 70                {
 71                    _rawEntries = new List<PHPIniBase>();
 72                }
 73
 74                return _rawEntries;
 75            }
 76        }
 77
 78        public RemoteObjectCollection<PHPIniSetting> Settings
 79        {
 80            get
 81            {
 82                if (_settings == null)
 83                {
 84                    _settings = new RemoteObjectCollection<PHPIniSetting>((ArrayList)_data[IndexSettings]);
 85                }
 86
 87                return _settings;
 88            }
 89        }
 90
 91        private void AddAllAvailableExtensions(string extensionDir)
 92        {
 93            DirectoryInfo di = new DirectoryInfo(extensionDir);
 94            FileInfo[] files = di.GetFiles("php*.dll");
 95
 96            int extensionCount = Extensions.Count;
 97            foreach (FileInfo file in files)
 98            {
 99                bool found = false;
100                for (int i = 0; i < extensionCount; i++)
101                {
102                    if (String.Equals(Extensions[i].Name, file.Name, StringComparison.OrdinalIgnoreCase))
103                    {
104                        found = true;
105                        break;
106                    }
107                }
108
109                if (!found)
110                {
111                    Extensions.Add(new PHPIniExtension(file.Name, false));
112                }
113            }
114        }
115
116        internal void AddOrUpdateSettings(IEnumerable<PHPIniSetting> settings)
117        {
118            foreach (PHPIniSetting setting in settings)
119            {
120                bool settingFound = false;
121                int index = -1;
122                int lastIndex = -1;
123
124                for (int i = 0; i < RawEntries.Count; i++)
125                {
126                    PHPIniBase b = RawEntries[i];
127
128                    PHPIniSetting existing = b as PHPIniSetting;
129                    if (existing != null)
130                    {
131                        lastIndex = i;
132
133                        if (String.Equals(existing.Name, setting.Name, StringComparison.OrdinalIgnoreCase))
134                        {
135                            existing.Value = setting.Value;
136                            existing.UpdateText();
137                            settingFound = true;
138
139                            break;
140                        }
141
142                        if (String.Equals(existing.Section, setting.Section, StringComparison.OrdinalIgnoreCase))
143                        {
144                            index = i;
145                        }
146                    }
147                }
148
149                if (!settingFound)
150                {
151                    setting.UpdateText();
152
153                    if (index == -1)
154                    {
155                        lastIndex++;
156                        RawEntries.Insert(lastIndex, new PHPIniString(""));
157                        lastIndex++;
158                        RawEntries.Insert(lastIndex, new PHPIniString('[' + setting.Section + ']'));
159                        lastIndex++;
160                        RawEntries.Insert(lastIndex, setting);
161                    }
162                    else
163                    {
164                        RawEntries.Insert(index + 1, setting);
165                    }
166                }
167            }
168        }
169
170        public object GetData()
171        {
172            if (_settings != null)
173            {
174                _data[IndexSettings] = _settings.GetData();
175            }
176            if (_extensions != null)
177            {
178                _data[IndexExtensions] = _extensions.GetData();
179            }
180
181            return _data;
182        }
183
184        internal int GetEnabledExtensionsCount()
185        {
186            int result = 0;
187
188            foreach (PHPIniExtension extension in Extensions)
189            {
190                if (extension.Enabled)
191                {
192                    result++;
193                }
194            }
195
196            return result;
197        }
198
199        private static string GetExtensionSection(string extensionName)
200        {
201            string sectionName = Path.GetFileNameWithoutExtension(extensionName).ToUpper(CultureInfo.InvariantCulture);
202            return '[' + sectionName + ']';
203        }
204
205        internal PHPIniSetting GetSetting(string name)
206        {
207            foreach (PHPIniSetting setting in Settings)
208            {
209                if (String.Equals(setting.Name, name, StringComparison.OrdinalIgnoreCase))
210                {
211                    return setting;
212                }
213            }
214
215            return null;
216        }
217
218        internal void Parse()
219        {
220            if (String.IsNullOrEmpty(FileName))
221            {
222                throw new InvalidOperationException();
223            }
224
225            string extensionDir = String.Empty;
226
227            using (StreamReader reader = new StreamReader(FileName))
228            {
229                foreach (object o in PHPIniFile.ParseIniFile(reader))
230                {
231                    PHPIniSetting directive = o as PHPIniSetting;
232                    if (directive != null)
233                    {
234                        Settings.Add(directive);
235                        RawEntries.Add(directive);
236
237                        // Get the path to the extension directory - this will be used later
238                        if (String.Equals(directive.Name, "extension_dir", StringComparison.OrdinalIgnoreCase))
239                        {
240                            extensionDir = directive.TrimmedValue;
241                        }
242                    }
243                    else
244                    {
245                        PHPIniExtension extension = o as PHPIniExtension;
246                        if (extension != null)
247                        {
248                            Extensions.Add(extension);
249                            RawEntries.Add(extension);
250                        }
251                        else
252                        {
253                            PHPIniBase entry = o as PHPIniBase;
254                            if (entry != null)
255                            {
256                                RawEntries.Add(entry);
257                            }
258                        }
259                    }
260                }
261            }
262
263            if (String.IsNullOrEmpty(extensionDir) ||
264                !Path.IsPathRooted(extensionDir))
265            {
266                extensionDir = Path.Combine(Path.GetDirectoryName(FileName), "ext");
267            }
268
269            if (Directory.Exists(extensionDir))
270            {
271                AddAllAvailableExtensions(extensionDir);
272            }
273        }
274
275        private static IEnumerable<PHPIniBase> ParseIniFile(TextReader reader)
276        {
277            string section = String.Empty;
278
279            string line = reader.ReadLine();
280            while (line != null)
281            {
282                string tmp = line.Trim();
283
284                // Process comments
285                if (tmp.StartsWith(";", StringComparison.OrdinalIgnoreCase))
286                {
287                    yield return new PHPIniString(line);
288                }
289                // Process section
290                else if (tmp.StartsWith("[", StringComparison.OrdinalIgnoreCase))
291                {
292                    int startindex = tmp.IndexOf('[');
293                    int endindex = tmp.IndexOf(']');
294                    if ((startindex >= 0) && (endindex > startindex))
295                    {
296                        string name = tmp.Substring(startindex + 1, endindex - startindex - 1);
297                        section = name;
298                        yield return new PHPIniSection(line);
299                    }
300                }
301                // Process an extension
302                else if (tmp.StartsWith("extension=", StringComparison.OrdinalIgnoreCase))
303                {
304                    // Take care of the inline comment
305                    tmp = RemoveInlineComment(tmp);
306
307                    string[] split = tmp.Split(new Char[] { '=' });
308                    if (split.Length == 2)
309                    {
310                        string fileName = split[1].Trim();
311                        yield return new PHPIniExtension(fileName, true, line);
312                    }
313                    else
314                    {
315                        // If extension file is not specified then treat the line as unusable
316                        yield return new PHPIniString(line);
317                    }
318                }
319                // Process a directive
320                else if (!String.IsNullOrEmpty(tmp))
321                {
322                    // Take care of the inline comment
323                    tmp = RemoveInlineComment(tmp);
324
325                    string[] split = tmp.Split(new Char[] { '=' });
326                    if (split.Length > 1)
327                    {
328                        yield return new PHPIniSetting(split[0].Trim(), split[1].Trim(), section, line);
329                    }
330                    else
331                    {
332                        yield return new PHPIniSetting(split[0].Trim(), String.Empty, section, line);
333                    }
334                }
335                else
336                {
337                    // Return empty comment by default
338                    yield return new PHPIniString(line);
339                }
340
341                line = reader.ReadLine();
342            }
343        }
344
345        internal bool Remove(PHPIniBase entry)
346        {
347            return RawEntries.Remove(entry);
348        }
349
350        private static string RemoveInlineComment(string line)
351        {
352            int commentIndex = line.IndexOf(';');
353            if (commentIndex > 0)
354            {
355                return line.Substring(0, commentIndex);
356            }
357            return line;
358        }
359
360        internal void Save(string filename)
361        {
362            if (String.IsNullOrEmpty(filename))
363            {
364                throw new ArgumentNullException("filename");
365            }
366
367            using (StreamWriter writer = new StreamWriter(filename))
368            {
369                foreach (PHPIniBase entry in RawEntries)
370                {
371                    writer.WriteLine(entry.Text);
372                }
373            }
374        }
375
376        public void SetData(object o)
377        {
378            _data = (object[])o;
379        }
380
381        internal void UpdateExtensions(IEnumerable<PHPIniExtension> extensions)
382        {
383            foreach (PHPIniExtension extension in extensions)
384            {
385                int foundIndex = -1;
386
387                for (int i = 0; i < RawEntries.Count; i++)
388                {
389                    PHPIniBase b = RawEntries[i];
390
391                    PHPIniExtension existing = b as PHPIniExtension;
392                    if (existing != null)
393                    {
394                        if (String.Equals(existing.Name, extension.Name, StringComparison.OrdinalIgnoreCase))
395                        {
396                            foundIndex = i;
397                            break;
398                        }
399                    }
400                }
401
402                // If extension is found...
403                if (foundIndex >= 0)
404                {
405                    // ... and is disabled then...
406                    if (!extension.Enabled)
407                    {
408                        PHPIniBase extensionLine = RawEntries[foundIndex];
409                        // ... remove the extension section name if it exists
410                        if (foundIndex > 0 &&
411                            String.Equals(RawEntries[foundIndex - 1].Text, GetExtensionSection(extension.Name), StringComparison.OrdinalIgnoreCase))
412                        {
413                            RawEntries.Remove(RawEntries[foundIndex - 1]);
414                        }
415
416                        // remove the exension
417                        RawEntries.Remove(extensionLine);
418                    }
419                }
420                else
421                {
422                    // Extension is not found
423                    if (extension.Enabled)
424                    {
425                        extension.UpdateText();
426
427                        // Add it at the end of the file along with the extension section name
428                        int lastIndex = RawEntries.Count - 1;
429                        lastIndex++;
430                        RawEntries.Insert(lastIndex, new PHPIniString(GetExtensionSection(extension.Name)));
431                        lastIndex++;
432                        RawEntries.Insert(lastIndex, extension);
433                    }
434                }
435            }
436        }
437
438    }
439
440    internal abstract class PHPIniBase
441    {
442        private string _text;
443
444        protected PHPIniBase() { }
445
446        protected PHPIniBase(string text)
447        {
448            _text = text;
449        }
450
451        public string Text
452        {
453            get
454            {
455                return _text;
456            }
457            set
458            {
459                _text = value;
460            }
461        }
462    }
463
464    internal class PHPIniString : PHPIniBase
465    {
466
467        public PHPIniString() { }
468
469        public PHPIniString(string rawText) : base(rawText) { }
470    }
471
472    internal class PHPIniSetting : PHPIniBase, IRemoteObject
473    {
474        private object[] _data;
475        private const int Size = 3;
476        private const int IndexName = 0;
477        private const int IndexValue = 1;
478        private const int IndexSection = 2;
479
480        public PHPIniSetting()
481        {
482            _data = new object[Size];
483        }
484
485        public PHPIniSetting(string name, string value, string section) : this(name, value, section, String.Empty) { }
486
487        public PHPIniSetting(string name, string value, string section, string rawText)
488            : base(rawText)
489        {
490            _data = new object[Size];
491            Name = name;
492            Value = value;
493            Section = section;
494        }
495
496        public string Name
497        {
498            get
499            {
500                return (string)_data[IndexName];
501            }
502            set
503            {
504                _data[IndexName] = value;
505            }
506        }
507
508        public string Section
509        {
510            get
511            {
512                return (string)_data[IndexSection];
513            }
514            set
515            {
516                _data[IndexSection] = value;
517            }
518        }
519
520        public string Value
521        {
522            get
523            {
524                return (string)_data[IndexValue];
525            }
526            set
527            {
528                _data[IndexValue] = value;
529            }
530        }
531
532        public string TrimmedValue
533        {
534            get
535            {
536                string result = (string)_data[IndexValue];
537                return result.Trim(new char[] {' ', '"' });
538            }
539        }
540
541        public override bool Equals(object obj)
542        {
543            PHPIniSetting setting = obj as PHPIniSetting;
544            if (setting == null)
545            {
546                return false;
547            }
548
549            return (String.Equals(setting.Name, Name, StringComparison.OrdinalIgnoreCase) &&
550                    String.Equals(setting.Value, Value, StringComparison.OrdinalIgnoreCase) &&
551                    String.Equals(setting.Section, Section, StringComparison.OrdinalIgnoreCase));
552        }
553
554        public object GetData()
555        {
556            return _data;
557        }
558
559        public override int GetHashCode()
560        {
561            return Name.GetHashCode() ^ Value.GetHashCode() ^ Section.GetHashCode();
562        }
563
564        #region IRemoteObject Members
565
566        public void SetData(object o)
567        {
568            _data = (object[])o;
569        }
570
571        #endregion
572
573        internal void UpdateText()
574        {
575            Text = Name + " = " + Value;
576        }
577    }
578
579    internal class PHPIniExtension : PHPIniBase, IRemoteObject
580    {
581        private object[] _data;
582        private const int Size = 2;
583        private const int IndexName = 0;
584        private const int IndexEnabled = 1;
585
586        public PHPIniExtension()
587        {
588            _data = new object[Size];
589            Enabled = false;
590        }
591
592        public PHPIniExtension(string filename, bool enabled): this(filename, enabled, String.Empty) {  }
593
594        public PHPIniExtension(string filename, bool enabled, string rawText): base(rawText)
595        {
596            _data = new object[Size];
597            Name = filename;
598            Enabled = enabled;
599        }
600
601        public bool Enabled
602        {
603            get
604            {
605                return (bool)_data[IndexEnabled];
606            }
607            set
608            {
609                _data[IndexEnabled] = value;
610            }
611        }
612
613        public string Name
614        {
615            get
616            {
617                return (string)_data[IndexName];
618            }
619            set
620            {
621                _data[IndexName] = value;
622            }
623        }
624
625        public object GetData()
626        {
627            return _data;
628        }
629
630        public void SetData(object o)
631        {
632            _data = (object[])o;
633        }
634
635        internal void UpdateText()
636        {
637            Text = "extension=" + Name;
638        }
639
640    }
641
642    internal class PHPIniSection : PHPIniBase
643    {
644        public PHPIniSection() { }
645
646        public PHPIniSection(string rawText) : base(rawText) { }
647    }
648}