1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 package convwatch;
29 
30 import java.io.File;
31 import java.io.RandomAccessFile;
32 import java.util.ArrayList;
33 
34 /**
35    Helper class to give a simple API to read/write windows like ini files
36  */
37 /* public */ // is only need, if we need this class outside package convwatch
38 class IniFile
39 {
40     /**
41      * internal representation of the ini file content.
42      * Problem, if ini file changed why other write something difference, we don't realise this.
43      */
44     String m_sFilename;
45     ArrayList m_aList;
46     boolean m_bListContainUnsavedChanges = false;
47 
48     /**
49        open a ini file by it's name
50        @param _sFilename string a filename, if the file doesn't exist, a new empty ini file will create.
51        write back to disk only if there are really changes.
52      */
53     public IniFile(String _sFilename)
54         {
55             m_sFilename = _sFilename;
56             m_aList = loadLines();
57         }
58 
59     ArrayList loadLines()
60         {
61             File aFile = new File(m_sFilename);
62             ArrayList aLines = new ArrayList();
63             if (! aFile.exists())
64             {
65                 GlobalLogWriter.get().println("couldn't find file " + m_sFilename);
66                 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
67                 // m_bListContainUnsavedChanges = false;
68                 return aLines;
69             }
70             RandomAccessFile aReader = null;
71             try
72             {
73                 aReader = new RandomAccessFile(aFile,"r");
74                 String aLine = "";
75                 while (aLine != null)
76                 {
77                     aLine = aReader.readLine();
78                     if (aLine != null)
79                     {
80                         aLines.add(aLine);
81                         }
82                     }
83                 }
84             catch (java.io.FileNotFoundException fne)
85             {
86                 GlobalLogWriter.get().println("couldn't open file " + m_sFilename);
87                 GlobalLogWriter.get().println("Message: " + fne.getMessage());
88                 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
89             }
90             catch (java.io.IOException ie)
91             {
92                 GlobalLogWriter.get().println("Exception occurs while reading from file " + m_sFilename);
93                 GlobalLogWriter.get().println("Message: " + ie.getMessage());
94                 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
95             }
96             try
97             {
98                 aReader.close();
99             }
100             catch (java.io.IOException ie)
101             {
102                 GlobalLogWriter.get().println("Couldn't close file " + m_sFilename);
103                 GlobalLogWriter.get().println("Message: " + ie.getMessage());
104                 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
105             }
106             return aLines;
107         }
108 
109     /**
110      * @return true, if the ini file contain some readable data
111      */
112     public boolean is()
113         {
114             return m_aList.size() > 1 ? true : false;
115         }
116 
117     // -----------------------------------------------------------------------------
118 
119     boolean isRemark(String _sLine)
120         {
121             if ( ((_sLine.length() < 2) ) ||
122                  ( _sLine.startsWith("#")) ||
123                  ( _sLine.startsWith(";")) )
124             {
125                 return true;
126             }
127             return false;
128         }
129 
130     String getItem(int i)
131         {
132             return (String)m_aList.get(i);
133         }
134 
135     String buildSectionName(String _sSectionName)
136         {
137             String sFindSection = "[" + _sSectionName + "]";
138             return sFindSection;
139         }
140     String toLowerIfNeed(String _sName)
141         {
142             return _sName.toLowerCase();
143         }
144 
145     // return the number where this section starts
146     int findSection(String _sSection)
147         {
148             String sFindSection = toLowerIfNeed(buildSectionName(_sSection));
149             // ----------- find _sSection ---------------
150             int i;
151             for (i=0; i<m_aList.size();i++)
152             {
153                 String sLine = toLowerIfNeed(getItem(i).trim());
154                 if (isRemark(sLine))
155             {
156                     continue;
157                 }
158                 if (sFindSection.equals("[]"))
159                 {
160                     // special case, empty Section.
161                     return i - 1;
162                 }
163                 if (sLine.startsWith(sFindSection))
164                 {
165                     return i;
166                 }
167             }
168             return -1;
169         }
170 
171     // return the line number, where the key is found.
172     int findKey(String _sSection, String _sKey)
173         {
174             int i = findSection(_sSection);
175             if (i == -1)
176             {
177                 // Section not found, therefore the value can't exist
178                 return -1;
179             }
180             return findKeyFromKnownSection(i, _sKey);
181         }
182 
183     // i must be the index in the list, where the well known section starts
184     int findKeyFromKnownSection(int _nSectionIndex, String _sKey)
185         {
186             _sKey = toLowerIfNeed(_sKey);
187             for (int j=_nSectionIndex + 1; j<m_aList.size();j++)
188             {
189                 String sLine = getItem(j).trim();
190 
191                 if (isRemark(sLine))
192                 {
193                     continue;
194                 }
195 
196                 if (sLine.startsWith("[") /* && sLine.endsWith("]") */)
197                 {
198                     // found end.
199                     break;
200                 }
201 
202                 int nEqual = sLine.indexOf("=");
203                 if (nEqual >= 0)
204                 {
205                     String sKey = toLowerIfNeed(sLine.substring(0, nEqual).trim());
206                     if (sKey.equals(_sKey))
207                     {
208                         return j;
209                     }
210             }
211             }
212             return -1;
213         }
214 
215     // i must be the index in the list, where the well known section starts
216     int findLastKnownKeyIndex(int _nSectionIndex, String _sKey)
217         {
218             _sKey = toLowerIfNeed(_sKey);
219             int i = _nSectionIndex + 1;
220             for (int j=i; j<m_aList.size();j++)
221             {
222                 String sLine = getItem(j).trim();
223 
224                 if (isRemark(sLine))
225                 {
226                     continue;
227                 }
228 
229                 if (sLine.startsWith("[") /* && sLine.endsWith("]") */)
230                 {
231                     // found end.
232                     return j;
233                 }
234 
235                 int nEqual = sLine.indexOf("=");
236                 if (nEqual >= 0)
237                 {
238                     String sKey = toLowerIfNeed(sLine.substring(0, nEqual).trim());
239                     if (sKey.equals(_sKey))
240                     {
241                         return j;
242                     }
243                 }
244             }
245             return i;
246         }
247 
248     String getValue(int _nIndex)
249         {
250             String sLine = getItem(_nIndex).trim();
251             if (isRemark(sLine))
252             {
253                 return "";
254             }
255             int nEqual = sLine.indexOf("=");
256             if (nEqual >= 0)
257             {
258                 String sKey =   sLine.substring(0, nEqual).trim();
259                 String sValue = sLine.substring(nEqual + 1).trim();
260                 return sValue;
261                     }
262             return "";
263                 }
264 
265     /**
266        @param _sSection string
267        @param _sKey string
268        @return the value found in the inifile which is given by the section and key parameter
269     */
270     public String getValue(String _sSection, String _sKey)
271         {
272             String sValue = "";
273             int i = findKey(_sSection, _sKey);
274             if (i == -1)
275             {
276                 // Section not found, therefore the value can't exist
277                 return "";
278             }
279 
280             sValue = getValue(i);
281 
282             return sValue;
283         }
284 
285     /**
286        write back the ini file to the disk, only if there exist changes
287     */
288     public void store()
289         {
290             if (m_bListContainUnsavedChanges == false)
291             {
292                 // nothing has changed, so no need to store
293                 return;
294             }
295 
296             File aFile = new File(m_sFilename);
297             if (aFile.exists())
298             {
299                 // System.out.println("couldn't find file " + m_sFilename);
300                 aFile.delete();
301                 if (aFile.exists())
302                 {
303                     GlobalLogWriter.get().println("Couldn't delete the file " + m_sFilename);
304                     return;
305                     // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, "Couldn't delete the file " + m_sFilename);
306                 }
307             }
308             // if (! aFile.canWrite())
309             // {
310             //    System.out.println("Couldn't write to file " + m_sFilename);
311             //    DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, "");
312             // }
313             try
314             {
315                 RandomAccessFile aWriter = new RandomAccessFile(aFile, "rw");
316                 for (int i=0; i<m_aList.size();i++)
317                 {
318                     String sLine = getItem(i);
319                     aWriter.writeBytes(sLine);
320                     aWriter.writeByte((int)'\n');
321                 }
322                 aWriter.close();
323             }
324 
325             catch (java.io.FileNotFoundException fne)
326             {
327                 GlobalLogWriter.get().println("couldn't open file for writing " + m_sFilename);
328                 GlobalLogWriter.get().println("Message: " + fne.getMessage());
329                 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
330             }
331             catch(java.io.IOException ie)
332             {
333                 GlobalLogWriter.get().println("Exception occurs while writing to file " + m_sFilename);
334                 GlobalLogWriter.get().println("Message: " + ie.getMessage());
335                 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
336             }
337         }
338 
339 
340 
341     /**
342        insert a value
343        there are 3 cases
344        1. section doesn't exist, goto end and insert a new section, insert a new key value pair
345        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
346        3. section exist and key exist, remove the old key and insert the key value pair at the same position
347     */
348     public void insertValue(String _sSection, String _sKey, String _sValue)
349         {
350             int i = findSection(_sSection);
351             if (i == -1)
352             {
353                 // case 1: section doesn't exist
354                 String sFindSection = buildSectionName(_sSection);
355 
356                 m_aList.add(sFindSection);
357                 String sKeyValuePair = _sKey + "=" + _sValue;
358                 m_aList.add(sKeyValuePair);
359                 m_bListContainUnsavedChanges = true;
360                 return;
361             }
362             int j = findKeyFromKnownSection(i, _sKey);
363             if (j == -1)
364             {
365                 // case 2: section exist, but not the key
366                 j = findLastKnownKeyIndex(i, _sKey);
367                 String sKeyValuePair = _sKey + "=" + _sValue;
368                 m_aList.add(j, sKeyValuePair);
369                 m_bListContainUnsavedChanges = true;
370                 return;
371             }
372             else
373             {
374                 // case 3: section exist, and also the key
375                 String sKeyValuePair = _sKey + "=" + _sValue;
376                 m_aList.set(j, sKeyValuePair);
377                 m_bListContainUnsavedChanges = true;
378             }
379         }
380     // -----------------------------------------------------------------------------
381     // String replaceEvaluatedValue(String _sSection, String _sValue)
382     //     {
383     //         String sValue = _sValue;
384     //         int nIndex = 0;
385     //         while (( nIndex = sValue.indexOf("$(", nIndex)) >= 0)
386     //         {
387     //             int nNextIndex = sValue.indexOf(")", nIndex);
388     //             if (nNextIndex >= 0)
389     //             {
390     //                 String sKey = sValue.substring(nIndex + 2, nNextIndex);
391     //                 String sNewValue = getValue(_sSection, sKey);
392     //                 if (sNewValue != null && sNewValue.length() > 0)
393     //                 {
394     //                     String sRegexpKey = "\\$\\(" + sKey + "\\)";
395     //                     sValue = sValue.replaceAll(sRegexpKey, sNewValue);
396     //                 }
397     //                 nIndex = nNextIndex;
398     //             }
399     //             else
400     //             {
401     //                 nIndex += 2;
402     //             }
403     //         }
404     //         return sValue;
405     //     }
406     // -----------------------------------------------------------------------------
407 
408     // public String getLocalEvaluatedValue(String _sSection, String _sKey)
409     //     {
410     //         String sValue = getValue(_sSection, _sKey);
411     //         sValue = replaceEvaluatedValue(_sSection, sValue);
412     //         return sValue;
413     //     }
414 
415     // -----------------------------------------------------------------------------
416 
417     // this is a special behaviour.
418     // public String getGlobalLocalEvaluatedValue(String _sSection, String _sKey)
419     //     {
420     //         String sGlobalValue = getKey("global", _sKey);
421     //         String sLocalValue = getKey(_sSection, _sKey);
422     //         if (sLocalValue.length() == 0)
423     //         {
424     //             sGlobalValue = replaceEvaluatedKey(_sSection, sGlobalValue);
425     //             sGlobalValue = replaceEvaluatedKey("global", sGlobalValue);
426     //             return sGlobalValue;
427     //         }
428     //         sLocalValue = replaceEvaluatedKey(_sSection, sLocalValue);
429     //         sLocalValue = replaceEvaluatedKey("global", sLocalValue);
430     //
431     //         return sLocalValue;
432     //     }
433 
434 
435     /**
436      * some tests for this class
437      */
438 //    public static void main(String[] args)
439 //        {
440 //            IniFile aIniFile = new IniFile("/tmp/inifile");
441 //            String sValue = aIniFile.getValue("Section","Key");
442 //            // insert a new value to a already exist section
443 //            aIniFile.insertValue("Section","Key2","a new value in a existing section");
444 //            // replace a value
445 //            aIniFile.insertValue("Section","Key","replaced value");
446 //            // create a new value
447 //            aIniFile.insertValue("New Section", "Key", "a new key value pair");
448 //
449 //            String sValue2 = aIniFile.getValue("Section2","Key");
450 //            aIniFile.store();
451 //        }
452 }
453