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