2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 // import java.io.BufferedReader;
22 import java
.io
.RandomAccessFile
;
23 import java
.util
.ArrayList
;
24 import java
.util
.Enumeration
;
27 Helper class to give a simple API to read/write windows like ini files
29 /* public */ // is only need, if we need this class outside package convwatch
30 public class IniFile
implements Enumeration
<String
>
34 * internal representation of the ini file content.
35 * Problem, if ini file changed why other write something difference, we don't realise this.
37 private String m_sFilename
;
38 private ArrayList
<String
> m_aList
;
39 boolean m_bListContainUnsavedChanges
= false;
40 private int m_aEnumerationPos
= 0;
43 open a ini file by it's name
44 @param _sFilename string a filename, if the file doesn't exist, a new empty ini file will create.
45 write back to disk only if there are really changes.
47 public IniFile(String _sFilename
)
49 m_sFilename
= _sFilename
;
50 m_aList
= loadLines();
51 m_aEnumerationPos
= findNextSection(0);
52 // if (_sFilename.endsWith(".odb.ps.ini"))
58 public void insertFirstComment(String
[] _aList
)
60 if (m_aList
.size() == 0)
62 // can only insert if there is nothing else already in the ini file
63 for (int i
= 0; i
< _aList
.length
; i
++)
65 m_aList
.add(_aList
[i
]);
70 private ArrayList
<String
> loadLines()
72 File aFile
= new File(m_sFilename
);
73 ArrayList
<String
> aLines
= new ArrayList
<String
>();
76 // GlobalLogWriter.println("couldn't find file '" + m_sFilename + "', will be created.");
77 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
78 // m_bListContainUnsavedChanges = false;
81 RandomAccessFile aReader
= null;
82 // BufferedReader aReader;
85 aReader
= new RandomAccessFile(aFile
, "r");
89 aLine
= aReader
.readLine();
90 if (aLine
!= null && aLine
.length() > 0)
96 catch (java
.io
.FileNotFoundException fne
)
98 GlobalLogWriter
.println("couldn't open file " + m_sFilename
);
99 GlobalLogWriter
.println("Message: " + fne
.getMessage());
100 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
102 catch (java
.io
.IOException ie
)
104 GlobalLogWriter
.println("Exception occurs while reading from file " + m_sFilename
);
105 GlobalLogWriter
.println("Message: " + ie
.getMessage());
106 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
112 catch (java
.io
.IOException ie
)
114 GlobalLogWriter
.println("Couldn't close file " + m_sFilename
);
115 GlobalLogWriter
.println("Message: " + ie
.getMessage());
116 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
122 * @return true, if the ini file contain some readable data
126 return m_aList
.size() > 1 ?
true : false;
130 * Check if a given Section and Key exists in the ini file
131 * @param _sSectionName
133 * @return true if the given Section, Key exists, now you can get the value
135 public boolean hasValue(String _sSectionName
, String _sKey
)
137 int n
= findKey(_sSectionName
, _sKey
);
144 // -----------------------------------------------------------------------------
146 private boolean isRemark(String _sLine
)
148 if (((_sLine
.length() < 2)) ||
149 (_sLine
.startsWith("#")) ||
150 (_sLine
.startsWith(";")))
157 private String
getItem(int i
)
159 return m_aList
.get(i
);
162 private String
buildSectionName(String _sSectionName
)
164 String sFindSection
= "[" + _sSectionName
+ "]";
168 private String
sectionToString(String _sSectionName
)
170 String sKeyName
= _sSectionName
;
171 if (sKeyName
.startsWith("[") &&
172 sKeyName
.endsWith("]"))
174 sKeyName
= sKeyName
.substring(1, sKeyName
.length() - 1);
179 private String
toLowerIfNeed(String _sName
)
181 return _sName
.toLowerCase();
184 // return the number where this section starts
185 private int findSection(String _sSection
)
187 String sFindSection
= toLowerIfNeed(buildSectionName(_sSection
));
188 // ----------- find _sSection ---------------
190 for (i
= 0; i
< m_aList
.size(); i
++)
192 String sLine
= toLowerIfNeed(getItem(i
).trim());
197 if (sFindSection
.equals("[]"))
199 // special case, empty Section.
202 if (sLine
.startsWith(sFindSection
))
211 * Checks if a given section exists in the ini file
213 * @return true if the given _sSection was found
215 public boolean hasSection(String _sSection
)
217 int i
= findSection(_sSection
);
225 // return the line number, where the key is found.
226 private int findKey(String _sSection
, String _sKey
)
228 int i
= findSection(_sSection
);
231 // Section not found, therefore the value can't exist
234 return findKeyFromKnownSection(i
, _sKey
);
237 // i must be the index in the list, where the well known section starts
238 private int findKeyFromKnownSection(int _nSectionIndex
, String _sKey
)
240 _sKey
= toLowerIfNeed(_sKey
);
241 for (int j
= _nSectionIndex
+ 1; j
< m_aList
.size(); j
++)
243 String sLine
= getItem(j
).trim();
249 if (sLine
.startsWith("[") /* && sLine.endsWith("]") */)
251 // TODO: due to the fact we would like to insert an empty line before new sections
252 // TODO: we should check if we are in an empty line and if, go back one line.
258 int nEqual
= sLine
.indexOf("=");
261 String sKey
= toLowerIfNeed(sLine
.substring(0, nEqual
).trim());
262 if (sKey
.equals(_sKey
))
271 // i must be the index in the list, where the well known section starts
272 private int findLastKnownKeyIndex(int _nSectionIndex
, String _sKey
)
274 _sKey
= toLowerIfNeed(_sKey
);
275 int i
= _nSectionIndex
+ 1;
276 for (int j
= i
; j
< m_aList
.size(); j
++)
278 String sLine
= getItem(j
).trim();
285 if (sLine
.startsWith("[") /* && sLine.endsWith("]") */)
291 int nEqual
= sLine
.indexOf("=");
294 String sKey
= toLowerIfNeed(sLine
.substring(0, nEqual
).trim());
295 if (sKey
.equals(_sKey
))
304 private String
getValue(int _nIndex
)
306 String sLine
= getItem(_nIndex
).trim();
311 int nEqual
= sLine
.indexOf("=");
314 sLine
.substring(0, nEqual
).trim();
315 String sValue
= sLine
.substring(nEqual
+ 1).trim();
322 @param _sSection string
324 @return the value found in the inifile which is given by the section and key parameter
326 // private int m_nCurrentPosition;
327 // private String m_sOldKey;
328 public String
getValue(String _sSection
, String _sKey
)
331 int m_nCurrentPosition
= findKey(_sSection
, _sKey
);
332 if (m_nCurrentPosition
== -1)
334 // Section not found, therefore the value can't exist
338 // m_sOldKey = _sKey;
339 sValue
= getValue(m_nCurrentPosition
);
344 // private String getNextValue()
346 // if (m_nCurrentPosition >= 0)
348 // ++m_nCurrentPosition;
349 // String sValue = getValue(m_nCurrentPosition);
355 * Returns the value at Section, Key converted to an integer
356 * Check with hasValue(Section, Key) to check before you get into trouble.
359 * @param _nDefault if there is a problem, key not found... this value will return
362 public int getIntValue(String _sSection
, String _sKey
, int _nDefault
)
364 String sValue
= getValue(_sSection
, _sKey
);
365 int nValue
= _nDefault
;
366 if (sValue
.length() > 0)
370 nValue
= Integer
.valueOf(sValue
).intValue();
372 catch (java
.lang
.NumberFormatException e
)
374 GlobalLogWriter
.println("IniFile.getIntValue(): Caught a number format exception, return the default value.");
386 write back the ini file to the disk, only if there exist changes
387 * @deprecated use close() instead!
390 // TODO: make private
393 if (m_bListContainUnsavedChanges
== false)
395 // nothing has changed, so no need to store
399 File aFile
= new File(m_sFilename
);
402 // System.out.println("couldn't find file " + m_sFilename);
403 // TODO: little bit unsafe here, first rename, after write is complete, delete the old.
407 GlobalLogWriter
.println("Couldn't delete the file " + m_sFilename
);
409 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, "Couldn't delete the file " + m_sFilename);
412 // if (! aFile.canWrite())
414 // System.out.println("Couldn't write to file " + m_sFilename);
415 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, "");
419 RandomAccessFile aWriter
= new RandomAccessFile(aFile
, "rw");
420 for (int i
= 0; i
< m_aList
.size(); i
++)
422 String sLine
= getItem(i
);
423 if (sLine
.startsWith("["))
425 // write an extra empty line before next section.
426 aWriter
.writeByte('\n');
428 aWriter
.writeBytes(sLine
);
429 aWriter
.writeByte('\n');
433 catch (java
.io
.FileNotFoundException fne
)
435 GlobalLogWriter
.println("couldn't open file for writing " + m_sFilename
);
436 GlobalLogWriter
.println("Message: " + fne
.getMessage());
437 // DebugHelper.exception(BasicErrorCode.SbERR_FILE_NOT_FOUND, "");
439 catch (java
.io
.IOException ie
)
441 GlobalLogWriter
.println("Exception occurs while writing to file " + m_sFilename
);
442 GlobalLogWriter
.println("Message: " + ie
.getMessage());
443 // DebugHelper.exception(BasicErrorCode.SbERR_INTERNAL_ERROR, ie.getMessage());
447 public void insertValue(String _sSection
, String _sKey
, int _nValue
)
449 insertValue(_sSection
, _sKey
, String
.valueOf(_nValue
));
452 public void insertValue(String _sSection
, String _sKey
, long _nValue
)
454 insertValue(_sSection
, _sKey
, String
.valueOf(_nValue
));
460 1. section doesn't exist, goto end and insert a new section, insert a new key value pair
461 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
462 3. section exist and key exist, remove the old key and insert the key value pair at the same position
467 public void insertValue(String _sSection
, String _sKey
, String _sValue
)
469 int i
= findSection(_sSection
);
472 // case 1: section doesn't exist
473 String sFindSection
= buildSectionName(_sSection
);
475 // TODO: before create a new Section, insert a empty line
476 m_aList
.add(sFindSection
);
477 if (_sKey
.length() > 0)
479 String sKeyValuePair
= _sKey
+ "=" + _sValue
;
480 m_aList
.add(sKeyValuePair
);
482 m_bListContainUnsavedChanges
= true;
485 int j
= findKeyFromKnownSection(i
, _sKey
);
488 // case 2: section exist, but not the key
489 j
= findLastKnownKeyIndex(i
, _sKey
);
490 if (_sKey
.length() > 0)
492 String sKeyValuePair
= _sKey
+ "=" + _sValue
;
493 m_aList
.add(j
, sKeyValuePair
);
494 m_bListContainUnsavedChanges
= true;
500 // case 3: section exist, and also the key
501 String sKeyValuePair
= _sKey
+ "=" + _sValue
;
502 m_aList
.set(j
, sKeyValuePair
);
503 m_bListContainUnsavedChanges
= true;
506 // -----------------------------------------------------------------------------
507 // String replaceEvaluatedValue(String _sSection, String _sValue)
509 // String sValue = _sValue;
511 // while (( nIndex = sValue.indexOf("$(", nIndex)) >= 0)
513 // int nNextIndex = sValue.indexOf(")", nIndex);
514 // if (nNextIndex >= 0)
516 // String sKey = sValue.substring(nIndex + 2, nNextIndex);
517 // String sNewValue = getValue(_sSection, sKey);
518 // if (sNewValue != null && sNewValue.length() > 0)
520 // String sRegexpKey = "\\$\\(" + sKey + "\\)";
521 // sValue = sValue.replaceAll(sRegexpKey, sNewValue);
523 // nIndex = nNextIndex;
532 // -----------------------------------------------------------------------------
534 // public String getLocalEvaluatedValue(String _sSection, String _sKey)
536 // String sValue = getValue(_sSection, _sKey);
537 // sValue = replaceEvaluatedValue(_sSection, sValue);
541 // -----------------------------------------------------------------------------
543 // this is a special behaviour.
544 // public String getGlobalLocalEvaluatedValue(String _sSection, String _sKey)
546 // String sGlobalValue = getKey("global", _sKey);
547 // String sLocalValue = getKey(_sSection, _sKey);
548 // if (sLocalValue.length() == 0)
550 // sGlobalValue = replaceEvaluatedKey(_sSection, sGlobalValue);
551 // sGlobalValue = replaceEvaluatedKey("global", sGlobalValue);
552 // return sGlobalValue;
554 // sLocalValue = replaceEvaluatedKey(_sSection, sLocalValue);
555 // sLocalValue = replaceEvaluatedKey("global", sLocalValue);
557 // return sLocalValue;
559 public void removeSection(String _sSectionToRemove
)
561 // first, search for the name
562 int i
= findSection(_sSectionToRemove
);
565 // Section to remove not found, do nothing.
568 // second, find the next section
569 int j
= findNextSection(i
+ 1);
572 // if we are at the end, use size() as second section
575 // remove all between first and second section
576 for (int k
= i
; k
< j
; k
++)
580 // mark the list as changed
581 m_bListContainUnsavedChanges
= true;
585 * some tests for this class
587 // public static void main(String[] args)
589 // String sTempFile = System.getProperty("java.io.tmpdir");
590 // sTempFile += "inifile";
593 // IniFile aIniFile = new IniFile(sTempFile);
594 // String sValue = aIniFile.getValue("Section", "Key");
595 // // insert a new value to a already exist section
596 // aIniFile.insertValue("Section", "Key2", "a new value in a existing section");
597 // // replace a value
598 // aIniFile.insertValue("Section", "Key", "replaced value");
599 // // create a new value
600 // aIniFile.insertValue("New Section", "Key", "a new key value pair");
601 // aIniFile.insertValue("New Section", "Key2", "a new second key value pair");
603 // String sValue2 = aIniFile.getValue("Section2", "Key");
605 // aIniFile.removeSection("Section");
606 // aIniFile.removeSection("New Section");
612 * Enumeration Interface
613 * @return true, if there are more Key values
615 public boolean hasMoreElements()
617 if (m_aEnumerationPos
>= 0 &&
618 m_aEnumerationPos
< m_aList
.size())
626 * Find the next line, which starts with '['
627 * @param i start position
628 * @return the line where '[' found or -1
630 private int findNextSection(int i
)
634 while (i
< m_aList
.size())
636 String sLine
= m_aList
.get(i
);
637 if (sLine
.startsWith("["))
648 * Enumeration Interface
649 * @return a key without the enveloped '[' ']'
651 public String
nextElement()
653 int nLineWithSection
= findNextSection(m_aEnumerationPos
);
654 if (nLineWithSection
!= -1)
656 String sSection
= m_aList
.get(nLineWithSection
);
657 m_aEnumerationPos
= findNextSection(nLineWithSection
+ 1);
658 sSection
= sectionToString(sSection
);
663 m_aEnumerationPos
= m_aList
.size();
669 * Helper to count the occurrence of Sections
670 * @return returns the count of '^['.*']$' Elements
672 public int getElementCount()
676 while ((nPosition
= findNextSection(nPosition
)) != -1)