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