1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
29 // import java.io.BufferedReader;
31 import java
.io
.RandomAccessFile
;
32 import java
.util
.ArrayList
;
33 import java
.util
.Enumeration
;
36 Helper class to give a simple API to read/write windows like ini files
38 /* public */ // is only need, if we need this class outside package convwatch
39 public class IniFile
implements Enumeration
43 * internal representation of the ini file content.
44 * Problem, if ini file changed why other write something difference, we don't realise this.
46 private String m_sFilename
;
47 private ArrayList
<String
> m_aList
;
48 boolean m_bListContainUnsavedChanges
= false;
49 private int m_aEnumerationPos
= 0;
52 open a ini file by it's name
53 @param _sFilename string a filename, if the file doesn't exist, a new empty ini file will create.
54 write back to disk only if there are really changes.
56 public IniFile(String _sFilename
)
58 m_sFilename
= _sFilename
;
59 m_aList
= loadLines();
60 m_aEnumerationPos
= findNextSection(0);
61 // if (_sFilename.endsWith(".odb.ps.ini"))
67 public void insertFirstComment(String
[] _aList
)
69 if (m_aList
.size() == 0)
71 // can only insert if there is nothing else already in the ini file
72 for (int i
= 0; i
< _aList
.length
; i
++)
74 m_aList
.add(_aList
[i
]);
79 private ArrayList
<String
> loadLines()
81 File aFile
= new File(m_sFilename
);
82 ArrayList
<String
> aLines
= new ArrayList
<String
>();
85 // GlobalLogWriter.println("couldn't find file '" + m_sFilename + "', will be created.");
86 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
87 // m_bListContainUnsavedChanges = false;
90 RandomAccessFile aReader
= null;
91 // BufferedReader aReader;
94 aReader
= new RandomAccessFile(aFile
, "r");
98 aLine
= aReader
.readLine();
99 if (aLine
!= null && aLine
.length() > 0)
105 catch (java
.io
.FileNotFoundException fne
)
107 GlobalLogWriter
.println("couldn't open file " + m_sFilename
);
108 GlobalLogWriter
.println("Message: " + fne
.getMessage());
109 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
111 catch (java
.io
.IOException ie
)
113 GlobalLogWriter
.println("Exception occurs while reading from file " + m_sFilename
);
114 GlobalLogWriter
.println("Message: " + ie
.getMessage());
115 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
121 catch (java
.io
.IOException ie
)
123 GlobalLogWriter
.println("Couldn't close file " + m_sFilename
);
124 GlobalLogWriter
.println("Message: " + ie
.getMessage());
125 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
131 * @return true, if the ini file contain some readable data
135 return m_aList
.size() > 1 ?
true : false;
139 * Check if a given Section and Key exists in the ini file
140 * @param _sSectionName
142 * @return true if the given Section, Key exists, now you can get the value
144 public boolean hasValue(String _sSectionName
, String _sKey
)
146 int n
= findKey(_sSectionName
, _sKey
);
153 // -----------------------------------------------------------------------------
155 private boolean isRemark(String _sLine
)
157 if (((_sLine
.length() < 2)) ||
158 (_sLine
.startsWith("#")) ||
159 (_sLine
.startsWith(";")))
166 private String
getItem(int i
)
168 return m_aList
.get(i
);
171 private String
buildSectionName(String _sSectionName
)
173 String sFindSection
= "[" + _sSectionName
+ "]";
177 private String
sectionToString(String _sSectionName
)
179 String sKeyName
= _sSectionName
;
180 if (sKeyName
.startsWith("[") &&
181 sKeyName
.endsWith("]"))
183 sKeyName
= sKeyName
.substring(1, sKeyName
.length() - 1);
188 private String
toLowerIfNeed(String _sName
)
190 return _sName
.toLowerCase();
193 // return the number where this section starts
194 private int findSection(String _sSection
)
196 String sFindSection
= toLowerIfNeed(buildSectionName(_sSection
));
197 // ----------- find _sSection ---------------
199 for (i
= 0; i
< m_aList
.size(); i
++)
201 String sLine
= toLowerIfNeed(getItem(i
).trim());
206 if (sFindSection
.equals("[]"))
208 // special case, empty Section.
211 if (sLine
.startsWith(sFindSection
))
220 * Checks if a given section exists in the ini file
222 * @return true if the given _sSection was found
224 public boolean hasSection(String _sSection
)
226 int i
= findSection(_sSection
);
234 // return the line number, where the key is found.
235 private int findKey(String _sSection
, String _sKey
)
237 int i
= findSection(_sSection
);
240 // Section not found, therefore the value can't exist
243 return findKeyFromKnownSection(i
, _sKey
);
246 // i must be the index in the list, where the well known section starts
247 private int findKeyFromKnownSection(int _nSectionIndex
, String _sKey
)
249 _sKey
= toLowerIfNeed(_sKey
);
250 for (int j
= _nSectionIndex
+ 1; j
< m_aList
.size(); j
++)
252 String sLine
= getItem(j
).trim();
258 if (sLine
.startsWith("[") /* && sLine.endsWith("]") */)
260 // TODO: due to the fact we would like to insert an empty line before new sections
261 // TODO: we should check if we are in an empty line and if, go back one line.
267 int nEqual
= sLine
.indexOf("=");
270 String sKey
= toLowerIfNeed(sLine
.substring(0, nEqual
).trim());
271 if (sKey
.equals(_sKey
))
280 // i must be the index in the list, where the well known section starts
281 private int findLastKnownKeyIndex(int _nSectionIndex
, String _sKey
)
283 _sKey
= toLowerIfNeed(_sKey
);
284 int i
= _nSectionIndex
+ 1;
285 for (int j
= i
; j
< m_aList
.size(); j
++)
287 String sLine
= getItem(j
).trim();
294 if (sLine
.startsWith("[") /* && sLine.endsWith("]") */)
300 int nEqual
= sLine
.indexOf("=");
303 String sKey
= toLowerIfNeed(sLine
.substring(0, nEqual
).trim());
304 if (sKey
.equals(_sKey
))
313 private String
getValue(int _nIndex
)
315 String sLine
= getItem(_nIndex
).trim();
320 int nEqual
= sLine
.indexOf("=");
323 String sKey
= sLine
.substring(0, nEqual
).trim();
324 String sValue
= sLine
.substring(nEqual
+ 1).trim();
331 @param _sSection string
333 @return the value found in the inifile which is given by the section and key parameter
335 // private int m_nCurrentPosition;
336 // private String m_sOldKey;
337 public String
getValue(String _sSection
, String _sKey
)
340 int m_nCurrentPosition
= findKey(_sSection
, _sKey
);
341 if (m_nCurrentPosition
== -1)
343 // Section not found, therefore the value can't exist
347 // m_sOldKey = _sKey;
348 sValue
= getValue(m_nCurrentPosition
);
353 // private String getNextValue()
355 // if (m_nCurrentPosition >= 0)
357 // ++m_nCurrentPosition;
358 // String sValue = getValue(m_nCurrentPosition);
364 * Returns the value at Section, Key converted to an integer
365 * Check with hasValue(Section, Key) to check before you get into trouble.
368 * @param _nDefault if there is a problem, key not found... this value will return
371 public int getIntValue(String _sSection
, String _sKey
, int _nDefault
)
373 String sValue
= getValue(_sSection
, _sKey
);
374 int nValue
= _nDefault
;
375 if (sValue
.length() > 0)
379 nValue
= Integer
.valueOf(sValue
).intValue();
381 catch (java
.lang
.NumberFormatException e
)
383 GlobalLogWriter
.println("IniFile.getIntValue(): Caught a number format exception, return the default value.");
395 write back the ini file to the disk, only if there exist changes
396 * @deprecated use close() instead!
399 // TODO: make private
402 if (m_bListContainUnsavedChanges
== false)
404 // nothing has changed, so no need to store
408 File aFile
= new File(m_sFilename
);
411 // System.out.println("couldn't find file " + m_sFilename);
412 // TODO: little bit unsafe here, first rename, after write is complete, delete the old.
416 GlobalLogWriter
.println("Couldn't delete the file " + m_sFilename
);
418 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, "Couldn't delete the file " + m_sFilename);
421 // if (! aFile.canWrite())
423 // System.out.println("Couldn't write to file " + m_sFilename);
424 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, "");
428 RandomAccessFile aWriter
= new RandomAccessFile(aFile
, "rw");
429 for (int i
= 0; i
< m_aList
.size(); i
++)
431 String sLine
= getItem(i
);
432 if (sLine
.startsWith("["))
434 // write an extra empty line before next section.
435 aWriter
.writeByte((int) '\n');
437 aWriter
.writeBytes(sLine
);
438 aWriter
.writeByte((int) '\n');
442 catch (java
.io
.FileNotFoundException fne
)
444 GlobalLogWriter
.println("couldn't open file for writing " + m_sFilename
);
445 GlobalLogWriter
.println("Message: " + fne
.getMessage());
446 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
448 catch (java
.io
.IOException ie
)
450 GlobalLogWriter
.println("Exception occurs while writing to file " + m_sFilename
);
451 GlobalLogWriter
.println("Message: " + ie
.getMessage());
452 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
456 public void insertValue(String _sSection
, String _sKey
, int _nValue
)
458 insertValue(_sSection
, _sKey
, String
.valueOf(_nValue
));
461 public void insertValue(String _sSection
, String _sKey
, long _nValue
)
463 insertValue(_sSection
, _sKey
, String
.valueOf(_nValue
));
469 1. section doesn't exist, goto end and insert a new section, insert a new key value pair
470 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
471 3. section exist and key exist, remove the old key and insert the key value pair at the same position
476 public void insertValue(String _sSection
, String _sKey
, String _sValue
)
478 int i
= findSection(_sSection
);
481 // case 1: section doesn't exist
482 String sFindSection
= buildSectionName(_sSection
);
484 // TODO: before create a new Section, insert a empty line
485 m_aList
.add(sFindSection
);
486 if (_sKey
.length() > 0)
488 String sKeyValuePair
= _sKey
+ "=" + _sValue
;
489 m_aList
.add(sKeyValuePair
);
491 m_bListContainUnsavedChanges
= true;
494 int j
= findKeyFromKnownSection(i
, _sKey
);
497 // case 2: section exist, but not the key
498 j
= findLastKnownKeyIndex(i
, _sKey
);
499 if (_sKey
.length() > 0)
501 String sKeyValuePair
= _sKey
+ "=" + _sValue
;
502 m_aList
.add(j
, sKeyValuePair
);
503 m_bListContainUnsavedChanges
= true;
509 // case 3: section exist, and also the key
510 String sKeyValuePair
= _sKey
+ "=" + _sValue
;
511 m_aList
.set(j
, sKeyValuePair
);
512 m_bListContainUnsavedChanges
= true;
515 // -----------------------------------------------------------------------------
516 // String replaceEvaluatedValue(String _sSection, String _sValue)
518 // String sValue = _sValue;
520 // while (( nIndex = sValue.indexOf("$(", nIndex)) >= 0)
522 // int nNextIndex = sValue.indexOf(")", nIndex);
523 // if (nNextIndex >= 0)
525 // String sKey = sValue.substring(nIndex + 2, nNextIndex);
526 // String sNewValue = getValue(_sSection, sKey);
527 // if (sNewValue != null && sNewValue.length() > 0)
529 // String sRegexpKey = "\\$\\(" + sKey + "\\)";
530 // sValue = sValue.replaceAll(sRegexpKey, sNewValue);
532 // nIndex = nNextIndex;
541 // -----------------------------------------------------------------------------
543 // public String getLocalEvaluatedValue(String _sSection, String _sKey)
545 // String sValue = getValue(_sSection, _sKey);
546 // sValue = replaceEvaluatedValue(_sSection, sValue);
550 // -----------------------------------------------------------------------------
552 // this is a special behaviour.
553 // public String getGlobalLocalEvaluatedValue(String _sSection, String _sKey)
555 // String sGlobalValue = getKey("global", _sKey);
556 // String sLocalValue = getKey(_sSection, _sKey);
557 // if (sLocalValue.length() == 0)
559 // sGlobalValue = replaceEvaluatedKey(_sSection, sGlobalValue);
560 // sGlobalValue = replaceEvaluatedKey("global", sGlobalValue);
561 // return sGlobalValue;
563 // sLocalValue = replaceEvaluatedKey(_sSection, sLocalValue);
564 // sLocalValue = replaceEvaluatedKey("global", sLocalValue);
566 // return sLocalValue;
568 public void removeSection(String _sSectionToRemove
)
570 // first, search for the name
571 int i
= findSection(_sSectionToRemove
);
574 // Section to remove not found, do nothing.
577 // second, find the next section
578 int j
= findNextSection(i
+ 1);
581 // if we are at the end, use size() as second section
584 // remove all between first and second section
585 for (int k
= i
; k
< j
; k
++)
589 // mark the list as changed
590 m_bListContainUnsavedChanges
= true;
594 * some tests for this class
596 // public static void main(String[] args)
598 // String sTempFile = System.getProperty("java.io.tmpdir");
599 // sTempFile += "inifile";
602 // IniFile aIniFile = new IniFile(sTempFile);
603 // String sValue = aIniFile.getValue("Section", "Key");
604 // // insert a new value to a already exist section
605 // aIniFile.insertValue("Section", "Key2", "a new value in a existing section");
606 // // replace a value
607 // aIniFile.insertValue("Section", "Key", "replaced value");
608 // // create a new value
609 // aIniFile.insertValue("New Section", "Key", "a new key value pair");
610 // aIniFile.insertValue("New Section", "Key2", "a new second key value pair");
612 // String sValue2 = aIniFile.getValue("Section2", "Key");
614 // aIniFile.removeSection("Section");
615 // aIniFile.removeSection("New Section");
621 * Enumeration Interface
622 * @return true, if there are more Key values
624 public boolean hasMoreElements()
626 if (m_aEnumerationPos
>= 0 &&
627 m_aEnumerationPos
< m_aList
.size())
635 * Find the next line, which starts with '['
636 * @param i start position
637 * @return the line where '[' found or -1
639 private int findNextSection(int i
)
643 while (i
< m_aList
.size())
645 String sLine
= m_aList
.get(i
);
646 if (sLine
.startsWith("["))
657 * Enumeration Interface
658 * @return a key without the enveloped '[' ']'
660 public Object
nextElement()
662 int nLineWithSection
= findNextSection(m_aEnumerationPos
);
663 if (nLineWithSection
!= -1)
665 String sSection
= m_aList
.get(nLineWithSection
);
666 m_aEnumerationPos
= findNextSection(nLineWithSection
+ 1);
667 sSection
= sectionToString(sSection
);
672 m_aEnumerationPos
= m_aList
.size();
678 * Helper to count the occurrence of Sections
679 * @return returns the count of '^['.*']$' Elements
681 public int getElementCount()
685 while ((nPosition
= findNextSection(nPosition
)) != -1)