1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: IniFile.java,v $
10 * $Revision: 1.1.2.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
32 import java
.io
.BufferedReader
;
34 import java
.io
.RandomAccessFile
;
35 import java
.util
.ArrayList
;
36 import java
.util
.Enumeration
;
39 Helper class to give a simple API to read/write windows like ini files
41 /* public */ // is only need, if we need this class outside package convwatch
42 public class IniFile
implements Enumeration
46 * internal representation of the ini file content.
47 * Problem, if ini file changed why other write something difference, we don't realise this.
49 private String m_sFilename
;
50 private ArrayList m_aList
;
51 boolean m_bListContainUnsavedChanges
= false;
52 private int m_aEnumerationPos
= 0;
55 open a ini file by it's name
56 @param _sFilename string a filename, if the file doesn't exist, a new empty ini file will create.
57 write back to disk only if there are really changes.
59 public IniFile(String _sFilename
)
61 m_sFilename
= _sFilename
;
62 m_aList
= loadLines();
63 m_aEnumerationPos
= findNextSection(0);
64 // if (_sFilename.endsWith(".odb.ps.ini"))
70 public void insertFirstComment(String
[] _aList
)
72 if (m_aList
.size() == 0)
74 // can only insert if there is nothing else already in the ini file
75 for (int i
= 0; i
< _aList
.length
; i
++)
77 m_aList
.add(_aList
[i
]);
82 private ArrayList
loadLines()
84 File aFile
= new File(m_sFilename
);
85 ArrayList aLines
= new ArrayList();
88 GlobalLogWriter
.get().println("couldn't find file '" + m_sFilename
+ "', will be created.");
89 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
90 // m_bListContainUnsavedChanges = false;
93 RandomAccessFile aReader
= null;
94 // BufferedReader aReader;
97 aReader
= new RandomAccessFile(aFile
, "r");
101 aLine
= aReader
.readLine();
102 if (aLine
!= null && aLine
.length() > 0)
108 catch (java
.io
.FileNotFoundException fne
)
110 GlobalLogWriter
.get().println("couldn't open file " + m_sFilename
);
111 GlobalLogWriter
.get().println("Message: " + fne
.getMessage());
112 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
114 catch (java
.io
.IOException ie
)
116 GlobalLogWriter
.get().println("Exception occurs while reading from file " + m_sFilename
);
117 GlobalLogWriter
.get().println("Message: " + ie
.getMessage());
118 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
124 catch (java
.io
.IOException ie
)
126 GlobalLogWriter
.get().println("Couldn't close file " + m_sFilename
);
127 GlobalLogWriter
.get().println("Message: " + ie
.getMessage());
128 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
134 * @return true, if the ini file contain some readable data
138 return m_aList
.size() > 1 ?
true : false;
142 * Check if a given Section and Key exists in the ini file
143 * @param _sSectionName
145 * @return true if the given Section, Key exists, now you can get the value
147 public boolean hasValue(String _sSectionName
, String _sKey
)
149 int n
= findKey(_sSectionName
, _sKey
);
156 // -----------------------------------------------------------------------------
158 private boolean isRemark(String _sLine
)
160 if (((_sLine
.length() < 2)) ||
161 (_sLine
.startsWith("#")) ||
162 (_sLine
.startsWith(";")))
169 private String
getItem(int i
)
171 return (String
) m_aList
.get(i
);
174 private String
buildSectionName(String _sSectionName
)
176 String sFindSection
= "[" + _sSectionName
+ "]";
180 private String
sectionToString(String _sSectionName
)
182 String sKeyName
= _sSectionName
;
183 if (sKeyName
.startsWith("[") &&
184 sKeyName
.endsWith("]"))
186 sKeyName
= sKeyName
.substring(1, sKeyName
.length() - 1);
191 private String
toLowerIfNeed(String _sName
)
193 return _sName
.toLowerCase();
196 // return the number where this section starts
197 private int findSection(String _sSection
)
199 String sFindSection
= toLowerIfNeed(buildSectionName(_sSection
));
200 // ----------- find _sSection ---------------
202 for (i
= 0; i
< m_aList
.size(); i
++)
204 String sLine
= toLowerIfNeed(getItem(i
).trim());
209 if (sFindSection
.equals("[]"))
211 // special case, empty Section.
214 if (sLine
.startsWith(sFindSection
))
223 * Checks if a given section exists in the ini file
225 * @return true if the given _sSection was found
227 public boolean hasSection(String _sSection
)
229 int i
= findSection(_sSection
);
237 // return the line number, where the key is found.
238 private int findKey(String _sSection
, String _sKey
)
240 int i
= findSection(_sSection
);
243 // Section not found, therefore the value can't exist
246 return findKeyFromKnownSection(i
, _sKey
);
249 // i must be the index in the list, where the well known section starts
250 private int findKeyFromKnownSection(int _nSectionIndex
, String _sKey
)
252 _sKey
= toLowerIfNeed(_sKey
);
253 for (int j
= _nSectionIndex
+ 1; j
< m_aList
.size(); j
++)
255 String sLine
= getItem(j
).trim();
261 if (sLine
.startsWith("[") /* && sLine.endsWith("]") */)
263 // TODO: due to the fact we would like to insert an empty line before new sections
264 // TODO: we should check if we are in an empty line and if, go back one line.
270 int nEqual
= sLine
.indexOf("=");
273 String sKey
= toLowerIfNeed(sLine
.substring(0, nEqual
).trim());
274 if (sKey
.equals(_sKey
))
283 // i must be the index in the list, where the well known section starts
284 private int findLastKnownKeyIndex(int _nSectionIndex
, String _sKey
)
286 _sKey
= toLowerIfNeed(_sKey
);
287 int i
= _nSectionIndex
+ 1;
288 for (int j
= i
; j
< m_aList
.size(); j
++)
290 String sLine
= getItem(j
).trim();
297 if (sLine
.startsWith("[") /* && sLine.endsWith("]") */)
303 int nEqual
= sLine
.indexOf("=");
306 String sKey
= toLowerIfNeed(sLine
.substring(0, nEqual
).trim());
307 if (sKey
.equals(_sKey
))
316 private String
getValue(int _nIndex
)
318 String sLine
= getItem(_nIndex
).trim();
323 int nEqual
= sLine
.indexOf("=");
326 String sKey
= sLine
.substring(0, nEqual
).trim();
327 String sValue
= sLine
.substring(nEqual
+ 1).trim();
334 @param _sSection string
336 @return the value found in the inifile which is given by the section and key parameter
338 // private int m_nCurrentPosition;
339 // private String m_sOldKey;
340 public String
getValue(String _sSection
, String _sKey
)
343 int m_nCurrentPosition
= findKey(_sSection
, _sKey
);
344 if (m_nCurrentPosition
== -1)
346 // Section not found, therefore the value can't exist
350 // m_sOldKey = _sKey;
351 sValue
= getValue(m_nCurrentPosition
);
356 // private String getNextValue()
358 // if (m_nCurrentPosition >= 0)
360 // ++m_nCurrentPosition;
361 // String sValue = getValue(m_nCurrentPosition);
367 * Returns the value at Section, Key converted to an integer
368 * Check with hasValue(Section, Key) to check before you get into trouble.
371 * @param _nDefault if there is a problem, key not found... this value will return
374 public int getIntValue(String _sSection
, String _sKey
, int _nDefault
)
376 String sValue
= getValue(_sSection
, _sKey
);
377 int nValue
= _nDefault
;
378 if (sValue
.length() > 0)
382 nValue
= Integer
.valueOf(sValue
).intValue();
384 catch (java
.lang
.NumberFormatException e
)
386 GlobalLogWriter
.get().println("IniFile.getIntValue(): Caught a number format exception, return the default value.");
398 write back the ini file to the disk, only if there exist changes
399 * @deprecated use close() instead!
403 if (m_bListContainUnsavedChanges
== false)
405 // nothing has changed, so no need to store
409 File aFile
= new File(m_sFilename
);
412 // System.out.println("couldn't find file " + m_sFilename);
413 // TODO: little bit unsafe here, first rename, after write is complete, delete the old.
417 GlobalLogWriter
.get().println("Couldn't delete the file " + m_sFilename
);
419 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, "Couldn't delete the file " + m_sFilename);
422 // if (! aFile.canWrite())
424 // System.out.println("Couldn't write to file " + m_sFilename);
425 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, "");
429 RandomAccessFile aWriter
= new RandomAccessFile(aFile
, "rw");
430 for (int i
= 0; i
< m_aList
.size(); i
++)
432 String sLine
= getItem(i
);
433 if (sLine
.startsWith("["))
435 // write an extra empty line before next section.
436 aWriter
.writeByte((int) '\n');
438 aWriter
.writeBytes(sLine
);
439 aWriter
.writeByte((int) '\n');
443 catch (java
.io
.FileNotFoundException fne
)
445 GlobalLogWriter
.get().println("couldn't open file for writing " + m_sFilename
);
446 GlobalLogWriter
.get().println("Message: " + fne
.getMessage());
447 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
449 catch (java
.io
.IOException ie
)
451 GlobalLogWriter
.get().println("Exception occurs while writing to file " + m_sFilename
);
452 GlobalLogWriter
.get().println("Message: " + ie
.getMessage());
453 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
457 public void insertValue(String _sSection
, String _sKey
, int _nValue
)
459 insertValue(_sSection
, _sKey
, String
.valueOf(_nValue
));
462 public void insertValue(String _sSection
, String _sKey
, long _nValue
)
464 insertValue(_sSection
, _sKey
, String
.valueOf(_nValue
));
470 1. section doesn't exist, goto end and insert a new section, insert a new key value pair
471 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
472 3. section exist and key exist, remove the old key and insert the key value pair at the same position
474 public void insertValue(String _sSection
, String _sKey
, String _sValue
)
476 int i
= findSection(_sSection
);
479 // case 1: section doesn't exist
480 String sFindSection
= buildSectionName(_sSection
);
482 // TODO: before create a new Section, insert a empty line
483 m_aList
.add(sFindSection
);
484 if (_sKey
.length() > 0)
486 String sKeyValuePair
= _sKey
+ "=" + _sValue
;
487 m_aList
.add(sKeyValuePair
);
489 m_bListContainUnsavedChanges
= true;
492 int j
= findKeyFromKnownSection(i
, _sKey
);
495 // case 2: section exist, but not the key
496 j
= findLastKnownKeyIndex(i
, _sKey
);
497 if (_sKey
.length() > 0)
499 String sKeyValuePair
= _sKey
+ "=" + _sValue
;
500 m_aList
.add(j
, sKeyValuePair
);
501 m_bListContainUnsavedChanges
= true;
507 // case 3: section exist, and also the key
508 String sKeyValuePair
= _sKey
+ "=" + _sValue
;
509 m_aList
.set(j
, sKeyValuePair
);
510 m_bListContainUnsavedChanges
= true;
513 // -----------------------------------------------------------------------------
514 // String replaceEvaluatedValue(String _sSection, String _sValue)
516 // String sValue = _sValue;
518 // while (( nIndex = sValue.indexOf("$(", nIndex)) >= 0)
520 // int nNextIndex = sValue.indexOf(")", nIndex);
521 // if (nNextIndex >= 0)
523 // String sKey = sValue.substring(nIndex + 2, nNextIndex);
524 // String sNewValue = getValue(_sSection, sKey);
525 // if (sNewValue != null && sNewValue.length() > 0)
527 // String sRegexpKey = "\\$\\(" + sKey + "\\)";
528 // sValue = sValue.replaceAll(sRegexpKey, sNewValue);
530 // nIndex = nNextIndex;
539 // -----------------------------------------------------------------------------
541 // public String getLocalEvaluatedValue(String _sSection, String _sKey)
543 // String sValue = getValue(_sSection, _sKey);
544 // sValue = replaceEvaluatedValue(_sSection, sValue);
548 // -----------------------------------------------------------------------------
550 // this is a special behaviour.
551 // public String getGlobalLocalEvaluatedValue(String _sSection, String _sKey)
553 // String sGlobalValue = getKey("global", _sKey);
554 // String sLocalValue = getKey(_sSection, _sKey);
555 // if (sLocalValue.length() == 0)
557 // sGlobalValue = replaceEvaluatedKey(_sSection, sGlobalValue);
558 // sGlobalValue = replaceEvaluatedKey("global", sGlobalValue);
559 // return sGlobalValue;
561 // sLocalValue = replaceEvaluatedKey(_sSection, sLocalValue);
562 // sLocalValue = replaceEvaluatedKey("global", sLocalValue);
564 // return sLocalValue;
566 public void removeSection(String _sSectionToRemove
)
568 // first, search for the name
569 int i
= findSection(_sSectionToRemove
);
572 // Section to remove not found, do nothing.
575 // second, find the next section
576 int j
= findNextSection(i
+ 1);
579 // if we are at the end, use size() as second section
582 // remove all between first and second section
583 for (int k
= i
; k
< j
; k
++)
587 // mark the list as changed
588 m_bListContainUnsavedChanges
= true;
592 * some tests for this class
594 public static void main(String
[] args
)
596 String sTempFile
= System
.getProperty("java.io.tmpdir");
597 sTempFile
+= "inifile";
600 IniFile aIniFile
= new IniFile(sTempFile
);
601 String sValue
= aIniFile
.getValue("Section", "Key");
602 // insert a new value to a already exist section
603 aIniFile
.insertValue("Section", "Key2", "a new value in a existing section");
605 aIniFile
.insertValue("Section", "Key", "replaced value");
606 // create a new value
607 aIniFile
.insertValue("New Section", "Key", "a new key value pair");
608 aIniFile
.insertValue("New Section", "Key2", "a new second key value pair");
610 String sValue2
= aIniFile
.getValue("Section2", "Key");
612 aIniFile
.removeSection("Section");
613 aIniFile
.removeSection("New Section");
619 * Enumeration Interface
620 * @return true, if there are more Key values
622 public boolean hasMoreElements()
624 if (m_aEnumerationPos
>= 0 &&
625 m_aEnumerationPos
< m_aList
.size())
633 * Find the next line, which starts with '['
634 * @param i start position
635 * @return the line where '[' found or -1
637 private int findNextSection(int i
)
641 while (i
< m_aList
.size())
643 String sLine
= (String
) m_aList
.get(i
);
644 if (sLine
.startsWith("["))
655 * Enumeration Interface
656 * @return a key without the enveloped '[' ']'
658 public Object
nextElement()
660 int nLineWithSection
= findNextSection(m_aEnumerationPos
);
661 if (nLineWithSection
!= -1)
663 String sSection
= (String
) m_aList
.get(nLineWithSection
);
664 m_aEnumerationPos
= findNextSection(nLineWithSection
+ 1);
665 sSection
= sectionToString(sSection
);
670 m_aEnumerationPos
= m_aList
.size();
676 * Helper to count the occurence of Sections
677 * @return returns the count of '^['.*']$' Elements
679 public int getElementCount()
683 while ((nPosition
= findNextSection(nPosition
)) != -1)