1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 package graphical;
24 
25 // import java.io.BufferedReader;
26 import java.io.File;
27 import java.io.RandomAccessFile;
28 import java.util.ArrayList;
29 import java.util.Enumeration;
30 
31 /**
32    Helper class to give a simple API to read/write windows like ini files
33 */
34 /* public */ // is only need, if we need this class outside package convwatch
35 public class IniFile implements Enumeration
36 {
37 
38     /**
39      * internal representation of the ini file content.
40      * Problem, if ini file changed why other write something difference, we don't realise this.
41      */
42     private String m_sFilename;
43     private ArrayList<String> m_aList;
44     boolean m_bListContainUnsavedChanges = false;
45     private int m_aEnumerationPos = 0;
46 
47     /**
48        open a ini file by it's name
49        @param _sFilename string a filename, if the file doesn't exist, a new empty ini file will create.
50        write back to disk only if there are really changes.
51     */
IniFile(String _sFilename)52     public IniFile(String _sFilename)
53         {
54             m_sFilename = _sFilename;
55             m_aList = loadLines();
56             m_aEnumerationPos = findNextSection(0);
57 //            if (_sFilename.endsWith(".odb.ps.ini"))
58 //            {
59 //                int dummy = 0;
60 //            }
61         }
62 
insertFirstComment(String[] _aList)63     public void insertFirstComment(String[] _aList)
64         {
65             if (m_aList.size() == 0)
66             {
67                 // can only insert if there is nothing else already in the ini file
68                 for (int i = 0; i < _aList.length; i++)
69                 {
70                     m_aList.add(_aList[i]);
71                 }
72             }
73         }
74 
loadLines()75     private ArrayList<String> loadLines()
76         {
77             File aFile = new File(m_sFilename);
78             ArrayList<String> aLines = new ArrayList<String>();
79             if (!aFile.exists())
80             {
81                 // GlobalLogWriter.println("couldn't find file '" + m_sFilename + "', will be created.");
82                 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
83                 // m_bListContainUnsavedChanges = false;
84                 return aLines;
85             }
86             RandomAccessFile aReader = null;
87             // BufferedReader aReader;
88             try
89             {
90                 aReader = new RandomAccessFile(aFile, "r");
91                 String aLine = "";
92                 while (aLine != null)
93                 {
94                     aLine = aReader.readLine();
95                     if (aLine != null && aLine.length() > 0)
96                     {
97                         aLines.add(aLine);
98                     }
99                 }
100             }
101             catch (java.io.FileNotFoundException fne)
102             {
103                 GlobalLogWriter.println("couldn't open file " + m_sFilename);
104                 GlobalLogWriter.println("Message: " + fne.getMessage());
105                 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
106             }
107             catch (java.io.IOException ie)
108             {
109                 GlobalLogWriter.println("Exception occurs while reading from file " + m_sFilename);
110                 GlobalLogWriter.println("Message: " + ie.getMessage());
111                 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
112             }
113             try
114             {
115                 aReader.close();
116             }
117             catch (java.io.IOException ie)
118             {
119                 GlobalLogWriter.println("Couldn't close file " + m_sFilename);
120                 GlobalLogWriter.println("Message: " + ie.getMessage());
121                 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
122             }
123             return aLines;
124         }
125 
126     /**
127      * @return true, if the ini file contain some readable data
128      */
is()129     public boolean is()
130         {
131             return m_aList.size() > 1 ? true : false;
132         }
133 
134     /**
135      * Check if a given Section and Key exists in the ini file
136      * @param _sSectionName
137      * @param _sKey
138      * @return true if the given Section, Key exists, now you can get the value
139      */
hasValue(String _sSectionName, String _sKey)140     public boolean hasValue(String _sSectionName, String _sKey)
141         {
142             int n = findKey(_sSectionName, _sKey);
143             if (n > 0)
144             {
145                 return true;
146             }
147             return false;
148         }
149     // -----------------------------------------------------------------------------
150 
isRemark(String _sLine)151     private boolean isRemark(String _sLine)
152         {
153             if (((_sLine.length() < 2)) ||
154                 (_sLine.startsWith("#")) ||
155                 (_sLine.startsWith(";")))
156             {
157                 return true;
158             }
159             return false;
160         }
161 
getItem(int i)162     private String getItem(int i)
163         {
164             return m_aList.get(i);
165         }
166 
buildSectionName(String _sSectionName)167     private String buildSectionName(String _sSectionName)
168         {
169             String sFindSection = "[" + _sSectionName + "]";
170             return sFindSection;
171         }
172 
sectionToString(String _sSectionName)173     private String sectionToString(String _sSectionName)
174         {
175             String sKeyName = _sSectionName;
176             if (sKeyName.startsWith("[") &&
177                 sKeyName.endsWith("]"))
178             {
179                 sKeyName = sKeyName.substring(1, sKeyName.length() - 1);
180             }
181             return sKeyName;
182         }
183 
toLowerIfNeed(String _sName)184     private String toLowerIfNeed(String _sName)
185         {
186             return _sName.toLowerCase();
187         }
188 
189     // return the number where this section starts
findSection(String _sSection)190     private int findSection(String _sSection)
191         {
192             String sFindSection = toLowerIfNeed(buildSectionName(_sSection));
193             // ----------- find _sSection ---------------
194             int i;
195             for (i = 0; i < m_aList.size(); i++)
196             {
197                 String sLine = toLowerIfNeed(getItem(i).trim());
198                 if (isRemark(sLine))
199                 {
200                     continue;
201                 }
202                 if (sFindSection.equals("[]"))
203                 {
204                     // special case, empty Section.
205                     return i - 1;
206                 }
207                 if (sLine.startsWith(sFindSection))
208                 {
209                     return i;
210                 }
211             }
212             return -1;
213         }
214 
215     /**
216      * Checks if a given section exists in the ini file
217      * @param _sSection
218      * @return true if the given _sSection was found
219      */
hasSection(String _sSection)220     public boolean hasSection(String _sSection)
221         {
222             int i = findSection(_sSection);
223             if (i == -1)
224             {
225                 return false;
226             }
227             return true;
228         }
229 
230     // return the line number, where the key is found.
findKey(String _sSection, String _sKey)231     private int findKey(String _sSection, String _sKey)
232         {
233             int i = findSection(_sSection);
234             if (i == -1)
235             {
236                 // Section not found, therefore the value can't exist
237                 return -1;
238             }
239             return findKeyFromKnownSection(i, _sKey);
240         }
241 
242     // i must be the index in the list, where the well known section starts
findKeyFromKnownSection(int _nSectionIndex, String _sKey)243     private int findKeyFromKnownSection(int _nSectionIndex, String _sKey)
244         {
245             _sKey = toLowerIfNeed(_sKey);
246             for (int j = _nSectionIndex + 1; j < m_aList.size(); j++)
247             {
248                 String sLine = getItem(j).trim();
249 
250                 if (isRemark(sLine))
251                 {
252                     continue;
253                 }
254                 if (sLine.startsWith("[") /* && sLine.endsWith("]") */)
255                 {
256                     // TODO: due to the fact we would like to insert an empty line before new sections
257                     // TODO: we should check if we are in an empty line and if, go back one line.
258 
259                     // found end.
260                     break;
261                 }
262 
263                 int nEqual = sLine.indexOf("=");
264                 if (nEqual >= 0)
265                 {
266                     String sKey = toLowerIfNeed(sLine.substring(0, nEqual).trim());
267                     if (sKey.equals(_sKey))
268                     {
269                         return j;
270                     }
271                 }
272             }
273             return -1;
274         }
275 
276     // i must be the index in the list, where the well known section starts
findLastKnownKeyIndex(int _nSectionIndex, String _sKey)277     private int findLastKnownKeyIndex(int _nSectionIndex, String _sKey)
278         {
279             _sKey = toLowerIfNeed(_sKey);
280             int i = _nSectionIndex + 1;
281             for (int j = i; j < m_aList.size(); j++)
282             {
283                 String sLine = getItem(j).trim();
284 
285                 if (isRemark(sLine))
286                 {
287                     continue;
288                 }
289 
290                 if (sLine.startsWith("[") /* && sLine.endsWith("]") */)
291                 {
292                     // found end.
293                     return j;
294                 }
295 
296                 int nEqual = sLine.indexOf("=");
297                 if (nEqual >= 0)
298                 {
299                     String sKey = toLowerIfNeed(sLine.substring(0, nEqual).trim());
300                     if (sKey.equals(_sKey))
301                     {
302                         return j;
303                     }
304                 }
305             }
306             return i;
307         }
308 
getValue(int _nIndex)309     private String getValue(int _nIndex)
310         {
311             String sLine = getItem(_nIndex).trim();
312             if (isRemark(sLine))
313             {
314                 return "";
315             }
316             int nEqual = sLine.indexOf("=");
317             if (nEqual >= 0)
318             {
319                 String sKey = sLine.substring(0, nEqual).trim();
320                 String sValue = sLine.substring(nEqual + 1).trim();
321                 return sValue;
322             }
323             return "";
324         }
325 
326     /**
327        @param _sSection string
328        @param _sKey string
329        @return the value found in the inifile which is given by the section and key parameter
330     */
331     // private int m_nCurrentPosition;
332     // private String m_sOldKey;
getValue(String _sSection, String _sKey)333     public String getValue(String _sSection, String _sKey)
334         {
335             String sValue = "";
336             int m_nCurrentPosition = findKey(_sSection, _sKey);
337             if (m_nCurrentPosition == -1)
338             {
339                 // Section not found, therefore the value can't exist
340                 return "";
341             }
342 
343             // m_sOldKey = _sKey;
344             sValue = getValue(m_nCurrentPosition);
345 
346             return sValue;
347         }
348 
349 //    private String getNextValue()
350 //    {
351 //        if (m_nCurrentPosition >= 0)
352 //        {
353 //            ++m_nCurrentPosition;
354 //            String sValue = getValue(m_nCurrentPosition);
355 //            return sValue;
356 //        }
357 //        return "";
358 //    }
359     /**
360      * Returns the value at Section, Key converted to an integer
361      * Check with hasValue(Section, Key) to check before you get into trouble.
362      * @param _sSection
363      * @param _sKey
364      * @param _nDefault if there is a problem, key not found... this value will return
365      * @return
366      */
getIntValue(String _sSection, String _sKey, int _nDefault)367     public int getIntValue(String _sSection, String _sKey, int _nDefault)
368         {
369             String sValue = getValue(_sSection, _sKey);
370             int nValue = _nDefault;
371             if (sValue.length() > 0)
372             {
373                 try
374                 {
375                     nValue = Integer.valueOf(sValue).intValue();
376                 }
377                 catch (java.lang.NumberFormatException e)
378                 {
379                     GlobalLogWriter.println("IniFile.getIntValue(): Caught a number format exception, return the default value.");
380                 }
381             }
382             return nValue;
383         }
384 
close()385     public void close()
386         {
387             store();
388         }
389 
390     /**
391        write back the ini file to the disk, only if there exist changes
392        * @deprecated use close() instead!
393        */
394 
395     // TODO: make private
store()396     public void store()
397         {
398             if (m_bListContainUnsavedChanges == false)
399             {
400                 // nothing has changed, so no need to store
401                 return;
402             }
403 
404             File aFile = new File(m_sFilename);
405             if (aFile.exists())
406             {
407                 // System.out.println("couldn't find file " + m_sFilename);
408                 // TODO: little bit unsafe here, first rename, after write is complete, delete the old.
409                 aFile.delete();
410                 if (aFile.exists())
411                 {
412                     GlobalLogWriter.println("Couldn't delete the file " + m_sFilename);
413                     return;
414                     // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, "Couldn't delete the file " + m_sFilename);
415                 }
416             }
417             // if (! aFile.canWrite())
418             // {
419             //    System.out.println("Couldn't write to file " + m_sFilename);
420             //    DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, "");
421             // }
422             try
423             {
424                 RandomAccessFile aWriter = new RandomAccessFile(aFile, "rw");
425                 for (int i = 0; i < m_aList.size(); i++)
426                 {
427                     String sLine = getItem(i);
428                     if (sLine.startsWith("["))
429                     {
430                         // write an extra empty line before next section.
431                         aWriter.writeByte((int) '\n');
432                     }
433                     aWriter.writeBytes(sLine);
434                     aWriter.writeByte((int) '\n');
435                 }
436                 aWriter.close();
437             }
438             catch (java.io.FileNotFoundException fne)
439             {
440                 GlobalLogWriter.println("couldn't open file for writing " + m_sFilename);
441                 GlobalLogWriter.println("Message: " + fne.getMessage());
442                 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
443             }
444             catch (java.io.IOException ie)
445             {
446                 GlobalLogWriter.println("Exception occurs while writing to file " + m_sFilename);
447                 GlobalLogWriter.println("Message: " + ie.getMessage());
448                 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
449             }
450         }
451 
insertValue(String _sSection, String _sKey, int _nValue)452     public void insertValue(String _sSection, String _sKey, int _nValue)
453         {
454             insertValue(_sSection, _sKey, String.valueOf(_nValue));
455         }
456 
insertValue(String _sSection, String _sKey, long _nValue)457     public void insertValue(String _sSection, String _sKey, long _nValue)
458         {
459             insertValue(_sSection, _sKey, String.valueOf(_nValue));
460         }
461 
462     /**
463        insert a value
464        there are 3 cases
465        1. section doesn't exist, goto end and insert a new section, insert a new key value pair
466        2. section exist but key not, search section, search key, if key is -1 get last known key position and insert new key value pair there
467        3. section exist and key exist, remove the old key and insert the key value pair at the same position
468      * @param _sSection
469      * @param _sKey
470      * @param _sValue
471      */
insertValue(String _sSection, String _sKey, String _sValue)472     public void insertValue(String _sSection, String _sKey, String _sValue)
473         {
474             int i = findSection(_sSection);
475             if (i == -1)
476             {
477                 // case 1: section doesn't exist
478                 String sFindSection = buildSectionName(_sSection);
479 
480                 // TODO: before create a new Section, insert a empty line
481                 m_aList.add(sFindSection);
482                 if (_sKey.length() > 0)
483                 {
484                     String sKeyValuePair = _sKey + "=" + _sValue;
485                     m_aList.add(sKeyValuePair);
486                 }
487                 m_bListContainUnsavedChanges = true;
488                 return;
489             }
490             int j = findKeyFromKnownSection(i, _sKey);
491             if (j == -1)
492             {
493                 // case 2: section exist, but not the key
494                 j = findLastKnownKeyIndex(i, _sKey);
495                 if (_sKey.length() > 0)
496                 {
497                     String sKeyValuePair = _sKey + "=" + _sValue;
498                     m_aList.add(j, sKeyValuePair);
499                     m_bListContainUnsavedChanges = true;
500                 }
501                 return;
502             }
503             else
504             {
505                 // case 3: section exist, and also the key
506                 String sKeyValuePair = _sKey + "=" + _sValue;
507                 m_aList.set(j, sKeyValuePair);
508                 m_bListContainUnsavedChanges = true;
509             }
510         }
511     // -----------------------------------------------------------------------------
512     // String replaceEvaluatedValue(String _sSection, String _sValue)
513     //     {
514     //         String sValue = _sValue;
515     //         int nIndex = 0;
516     //         while (( nIndex = sValue.indexOf("$(", nIndex)) >= 0)
517     //         {
518     //             int nNextIndex = sValue.indexOf(")", nIndex);
519     //             if (nNextIndex >= 0)
520     //             {
521     //                 String sKey = sValue.substring(nIndex + 2, nNextIndex);
522     //                 String sNewValue = getValue(_sSection, sKey);
523     //                 if (sNewValue != null && sNewValue.length() > 0)
524     //                 {
525     //                     String sRegexpKey = "\\$\\(" + sKey + "\\)";
526     //                     sValue = sValue.replaceAll(sRegexpKey, sNewValue);
527     //                 }
528     //                 nIndex = nNextIndex;
529     //             }
530     //             else
531     //             {
532     //                 nIndex += 2;
533     //             }
534     //         }
535     //         return sValue;
536     //     }
537     // -----------------------------------------------------------------------------
538 
539     // public String getLocalEvaluatedValue(String _sSection, String _sKey)
540     //     {
541     //         String sValue = getValue(_sSection, _sKey);
542     //         sValue = replaceEvaluatedValue(_sSection, sValue);
543     //         return sValue;
544     //     }
545 
546     // -----------------------------------------------------------------------------
547 
548     // this is a special behaviour.
549     // public String getGlobalLocalEvaluatedValue(String _sSection, String _sKey)
550     //     {
551     //         String sGlobalValue = getKey("global", _sKey);
552     //         String sLocalValue = getKey(_sSection, _sKey);
553     //         if (sLocalValue.length() == 0)
554     //         {
555     //             sGlobalValue = replaceEvaluatedKey(_sSection, sGlobalValue);
556     //             sGlobalValue = replaceEvaluatedKey("global", sGlobalValue);
557     //             return sGlobalValue;
558     //         }
559     //         sLocalValue = replaceEvaluatedKey(_sSection, sLocalValue);
560     //         sLocalValue = replaceEvaluatedKey("global", sLocalValue);
561     //
562     //         return sLocalValue;
563     //     }
removeSection(String _sSectionToRemove)564     public void removeSection(String _sSectionToRemove)
565         {
566             // first, search for the name
567             int i = findSection(_sSectionToRemove);
568             if (i == -1)
569             {
570                 // Section to remove not found, do nothing.
571                 return;
572             }
573             // second, find the next section
574             int j = findNextSection(i + 1);
575             if (j == -1)
576             {
577                 // if we are at the end, use size() as second section
578                 j = m_aList.size();
579             }
580             // remove all between first and second section
581             for (int k = i; k < j; k++)
582             {
583                 m_aList.remove(i);
584             }
585             // mark the list as changed
586             m_bListContainUnsavedChanges = true;
587         }
588 
589     /**
590      * some tests for this class
591      */
592 //    public static void main(String[] args)
593 //        {
594 //            String sTempFile = System.getProperty("java.io.tmpdir");
595 //            sTempFile += "inifile";
596 //
597 //
598 //            IniFile aIniFile = new IniFile(sTempFile);
599 //            String sValue = aIniFile.getValue("Section", "Key");
600 //            // insert a new value to a already exist section
601 //            aIniFile.insertValue("Section", "Key2", "a new value in a existing section");
602 //            // replace a value
603 //            aIniFile.insertValue("Section", "Key", "replaced value");
604 //            // create a new value
605 //            aIniFile.insertValue("New Section", "Key", "a new key value pair");
606 //            aIniFile.insertValue("New Section", "Key2", "a new second key value pair");
607 //
608 //            String sValue2 = aIniFile.getValue("Section2", "Key");
609 //
610 //            aIniFile.removeSection("Section");
611 //            aIniFile.removeSection("New Section");
612 //
613 //            aIniFile.close();
614 //        }
615 
616     /**
617      * Enumeration Interface
618      * @return true, if there are more Key values
619      */
hasMoreElements()620     public boolean hasMoreElements()
621         {
622             if (m_aEnumerationPos >= 0 &&
623                 m_aEnumerationPos < m_aList.size())
624             {
625                 return true;
626             }
627             return false;
628         }
629 
630     /**
631      * Find the next line, which starts with '['
632      * @param i start position
633      * @return the line where '[' found or -1
634      */
findNextSection(int i)635     private int findNextSection(int i)
636         {
637             if (i >= 0)
638             {
639                 while (i < m_aList.size())
640                 {
641                     String sLine =  m_aList.get(i);
642                     if (sLine.startsWith("["))
643                     {
644                         return i;
645                     }
646                     i++;
647                 }
648             }
649             return -1;
650         }
651 
652     /**
653      * Enumeration Interface
654      * @return a key without the enveloped '[' ']'
655      */
nextElement()656     public Object nextElement()
657         {
658             int nLineWithSection = findNextSection(m_aEnumerationPos);
659             if (nLineWithSection != -1)
660             {
661                 String sSection =  m_aList.get(nLineWithSection);
662                 m_aEnumerationPos = findNextSection(nLineWithSection + 1);
663                 sSection = sectionToString(sSection);
664                 return sSection;
665             }
666             else
667             {
668                 m_aEnumerationPos = m_aList.size();
669             }
670             return null;
671         }
672 
673     /**
674      * Helper to count the occurence of Sections
675      * @return returns the count of '^['.*']$' Elements
676      */
getElementCount()677     public int getElementCount()
678         {
679             int nCount = 0;
680             int nPosition = 0;
681             while ((nPosition = findNextSection(nPosition)) != -1)
682             {
683                 nCount++;
684                 nPosition++;
685             }
686             return nCount;
687         }
688 }
689 
690