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: FileHelper.java,v $
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 ************************************************************************/
31 package com
.sun
.star
.filter
.config
.tools
.utils
;
33 // __________ Imports __________
40 // __________ Implementation __________
43 * It collects some static helper functons to handle file system specific problems.
44 * Sometimes it's neccessary to convert URL from/to system pathes;
45 * or from string notation to structural versions (e.g. com.sun.star.util.URL).
46 * And sometimes java had another notation then the office it has.
47 * Further it provides functionality to work easiear with the java.io.File class of java.
51 public class FileHelper
53 // ____________________
56 * Because the office need URLs for loading/saving documents
57 * we must convert used system pathes.
58 * And java use another notation for file URLs ... correct it.
61 * represent the file in system notation
64 * a file url which represent the given system path
66 public static java
.lang
.String
getFileURLFromSystemPath(java
.io
.File aSystemPath
)
68 System
.out
.println("TODO: must be adapted to java 1.3 :-(");
73 sFileURL = aSystemPath.toURI().toURL().toString();
75 catch( MalformedURLException exWrong )
80 java
.lang
.String sFileURL
= null;
82 // problem of java: file URL's are coded with 1 slash instead of 2 or 3 ones!
83 // => correct this problem first, otherwise office can't use these URL's
85 (sFileURL
!= null ) &&
86 (sFileURL
.startsWith("file:/") == true ) &&
87 (sFileURL
.startsWith("file://") == false)
90 java
.lang
.StringBuffer sWorkBuffer
= new java
.lang
.StringBuffer(sFileURL
);
91 sWorkBuffer
.insert(6,"//");
92 sFileURL
= sWorkBuffer
.toString();
98 // ____________________
101 * The same as getFileURLFromSystemPath() before but uses string parameter instead
102 * of a java.io.File type. It exist to supress converting of neccessary parameters in the
103 * outside code. But of course getFileURLFromSystemPath(File) will be a little bit faster
104 * then this method ...
107 * represent the file in system notation
110 * a file url which represent the given system path
112 public static java
.lang
.String
getFileURLFromSystemPath(java
.lang
.String sSystemPath
)
114 return getFileURLFromSystemPath(new java
.io
.File(sSystemPath
));
117 // ____________________
120 * Does the same as getFileURLFromSystemPath() before ... but uses
121 * the given protocol string (e.g."http://") insted of "file:///".
124 * represent the file in system notation
127 * define the base path of the aSystemPath value,
128 * which must be replaced with the value of "sServerPath".
131 * Will be used to replace sBasePath.
134 * System Path = "d:\test\file.txt"
135 * Base Path = "d:\test"
136 * Server Path = "http://alaska:8000"
137 * => "http://alaska:8000/file.txt"
140 * an url which represent the given system path
141 * and uses the given protocol
143 public static java
.lang
.String
getURLWithProtocolFromSystemPath(java
.io
.File aSystemPath
,
144 java
.io
.File aBasePath
,
145 java
.lang
.String sServerURL
)
147 System
.out
.println("TODO: must be adapted to java 1.3 :-(");
150 java
.lang
.String sFileURL
= FileHelper
.getFileURLFromSystemPath(aSystemPath
);
151 java
.lang
.String sBaseURL
= FileHelper
.getFileURLFromSystemPath(aBasePath
);
154 if (sBaseURL
.lastIndexOf('/')==(sBaseURL
.length()-1))
155 sBaseURL
= sBaseURL
.substring(0,sBaseURL
.length()-1);
158 if (sServerURL
.lastIndexOf('/')==(sServerURL
.length()-1))
159 sServerURL
= sServerURL
.substring(0,sServerURL
.length()-1);
161 //TODO_JAVA java.lang.String sURL = sFileURL.replaceFirst(sBaseURL,sServerURL);
162 java
.lang
.String sURL
= null;
166 // ____________________
169 * The same as getURLWithProtocolFromSystemPath() before but uses string parameter instead
170 * of a java.io.File types. It exist to supress converting of neccessary parameters in the
171 * outside code. But of course getURLWithProtocolFromSystemPath(File,File,String) will be
172 * a little bit faster then this method ...
175 * represent the file in system notation
178 * define the base path of the aSystemPath value,
179 * which must be replaced with the value of "sServerPath".
182 * Will be used to replace sBasePath.
185 * System Path = "d:\test\file.txt"
186 * Base Path = "d:\test"
187 * Server Path = "http://alaska:8000"
188 * => "http://alaska:8000/file.txt"
191 * an url which represent the given system path
192 * and uses the given protocol
194 public static java
.lang
.String
getURLWithProtocolFromSystemPath(java
.lang
.String sSystemPath
,
195 java
.lang
.String sBasePath
,
196 java
.lang
.String sServerPath
)
198 return getURLWithProtocolFromSystemPath(new java
.io
.File(sSystemPath
), new java
.io
.File(sBasePath
), sServerPath
);
201 //_________________________________
204 * Return a list of all available files of a directory.
205 * We filter sub directories. All other files
206 * are returned. So they can be used for further purposes.
207 * One parameter define the start directory,
208 * another one enable/disable recursive search into sub directories.
211 * the start directory, which should be analyzed.
214 * enable/disable search in sub directories.
217 * a filtered list of java java.io.File objects of all available files
218 * of the start dir (and may of its sub directories).
220 public static java
.util
.Vector
getSystemFilesFromDir(java
.io
.File aRoot
,
223 java
.io
.File
[] lAllFiles
= aRoot
.listFiles();
224 if (lAllFiles
== null)
227 int c
= lAllFiles
.length
;
228 java
.util
.Vector lFilteredFiles
= new java
.util
.Vector(c
);
229 for (int i
=0; i
<c
; ++i
)
232 if (lAllFiles
[i
].isFile())
233 lFilteredFiles
.add(lAllFiles
[i
]);
236 if (bRecursive
&& lAllFiles
[i
].isDirectory())
238 java
.util
.Vector lSubFiles
= FileHelper
.getSystemFilesFromDir(lAllFiles
[i
],bRecursive
);
239 if (lSubFiles
!= null)
241 java
.util
.Enumeration aSnapshot
= lSubFiles
.elements();
242 while (aSnapshot
.hasMoreElements())
243 lFilteredFiles
.add(aSnapshot
.nextElement());
248 return lFilteredFiles
;
251 //_________________________________
252 /** it converts the given name (e.g. an internal type name) to
253 * an usable system file name.
255 * Do so some special characters (e.g. "/") must be replaced with other ones.
258 * the name, which should be analyzed and converted.
260 * @return A valid system file name, which should be similar to the
261 * given name, but does not contain special characters any longer.
263 public static java
.lang
.String
convertName2FileName(String sName
)
266 int nLength
= sName
.length();
267 char[] lBuffer
= sName
.toCharArray();
269 java
.lang
.StringBuffer sNewName
= new java
.lang
.StringBuffer(nLength
);
270 for (i
=0; i
<nLength
; ++i
)
274 c
>=48 && c
<=57 // 0-9
276 c
>=97 && c
<=122 // a-z
278 c
>=65 && c
<=90 // A-Z
285 sNewName
.append("_");
289 return sNewName
.toString();
292 //___________________________________________
294 /** it removes all child nodes of a file system directory.
297 * points to the directory, which should be made empty.
300 * force deletion of files only. If its set to TRUE,
301 * no subdirectory will be removed.
303 * @throw [java.io.IOException]
304 * if some of the child nodes couldn't be removed.
306 public static void makeDirectoryEmpty(java
.io
.File aDirectory
,
308 throws java
.io
.IOException
310 if (!aDirectory
.isDirectory())
311 throw new java
.io
.FileNotFoundException("\""+aDirectory
.toString()+"\" is not a directory.");
313 java
.io
.File
[] lChilds
= aDirectory
.listFiles();
314 for (int f
=0; f
<lChilds
.length
; ++f
)
316 if (lChilds
[f
].isDirectory())
318 FileHelper
.makeDirectoryEmpty(lChilds
[f
], bFilesOnly
);
321 if (!lChilds
[f
].delete())
322 throw new java
.io
.IOException("\""+lChilds
[f
].toString()+"\" could not be deleted.");
327 if (!lChilds
[f
].delete())
328 throw new java
.io
.IOException("\""+lChilds
[f
].toString()+"\" could not be deleted.");
333 //___________________________________________
335 /** it try to generate a new file with a unique ID
336 * inside given directory.
338 * Call this method with a directory and a base name for
339 * a file. It will be used to generate a new files inside
340 * the directory. Existing files will be checked and new file
341 * name will be tested till a non existing file name would be found.
344 * must be a system path
348 * must be a system file name without extensions.
352 * the whished extension.
355 * @return A valid file object, if an unique file could be created -
357 * e.g.: "c:\temp\myfile_1.dat"
359 public static java
.io
.File
createUniqueFile(java
.io
.File aBaseDir
,
360 java
.lang
.String sBaseName
,
361 java
.lang
.String sExtension
)
363 java
.io
.File aBaseFile
= new java
.io
.File(aBaseDir
, sBaseName
);
364 java
.io
.File aFile
= null;
366 while (aFile
== null && nr
< java
.lang
.Long
.MAX_VALUE
)
368 java
.lang
.String sFileName
= aBaseFile
.getPath() + java
.lang
.String
.valueOf(nr
) + "." + sExtension
;
369 aFile
= new java
.io
.File(sFileName
);
377 //___________________________________________
379 /** reads the complete file, using the right encoding,
380 * into the given string buffer.
383 * must point to a system file, which must exist.
384 * e.g.: "c:\temp\test.txt"
388 * will be used to encode the string content
393 * used to return the file content.
395 * @throw [IOException]
396 * - if the file couldnt be opened
397 * - if the file does not use the right encoding
399 public static void readEncodedBufferFromFile(java
.io
.File aFile
,
400 java
.lang
.String sEncoding
,
401 java
.lang
.StringBuffer sBuffer
)
402 throws java
.io
.IOException
404 if (sEncoding
.equals("UTF-8Special"))
406 FileHelper
.readAndCheckUTF8File(aFile
,sBuffer
);
410 java
.io
.FileInputStream aByteStream
= new java
.io
.FileInputStream(aFile
.getAbsolutePath());
411 java
.io
.InputStreamReader aEncodedReader
= new java
.io
.InputStreamReader(aByteStream
, sEncoding
);
412 char[] aEncodedBuffer
= new char[4096];
415 while((nReadCount
=aEncodedReader
.read(aEncodedBuffer
))>0)
416 sBuffer
.append(aEncodedBuffer
, 0, nReadCount
);
418 aEncodedReader
.close();
421 //___________________________________________
422 private static void logEncodingData(java
.lang
.StringBuffer sLog
,
434 sLog
.append("["+nEncodingType
+"]\t");
435 sLog
.append((int)nUTF8
+"\t=");
436 sLog
.append("\t"+nByteOrg1
+"/"+nByte1
);
437 sLog
.append("\t"+nByteOrg2
+"/"+nByte2
);
438 sLog
.append("\t"+nByteOrg3
+"/"+nByte3
);
439 sLog
.append("\t"+nByteOrg4
+"/"+nByte4
);
443 //___________________________________________
444 private static char impl_convertBytesToChar(int nByte1
, int nByte2
, int nByte3
, int nByte4
)
446 return (char)((nByte1
*0x40000)+(nByte2
*0x1000)+(nByte3
*0x40)+nByte4
);
449 //___________________________________________
450 private static int impl_readAndCheckNextByte(byte[] aBuffer
,
455 throws java
.lang
.Exception
457 if (nBufPos
>=nBufLength
)
458 throw new java
.lang
.Exception("impl_readAndCheckNextByte()\nEnd of buffer reached.");
460 int nByte
= aBuffer
[nBufPos
] & 0xFF;
462 (nByte
< nMinRange
) ||
466 throw new java
.lang
.Exception("impl_readAndCheckNextByte()\nByte does not fit the specified range.");
472 //___________________________________________
473 public static void readAndCheckUTF8File(java
.io
.File aFile
,
474 java
.lang
.StringBuffer sBuffer
)
475 throws java
.io
.IOException
477 java
.io
.FileInputStream aByteStream
= new java
.io
.FileInputStream(aFile
.getAbsolutePath());
478 byte[] aBuffer
= new byte[4096];
490 int nEncodingType
= 0;
491 java
.lang
.StringBuffer sLog
= new java
.lang
.StringBuffer();
496 while((nReadCount
=aByteStream
.read(aBuffer
))>0)
512 nByteOrg_1
= aBuffer
[i
++] & 0xFF;
513 nByte_1
= nByteOrg_1
;
515 Table 3-6. Well-Formed UTF-8 Byte Sequences
517 ============================================================================
518 Nr. Code Points 1st Byte 2nd Byte 3rd Byte 4th Byte
519 ============================================================================
520 01 U+ 0..U+ 7F 00..7F
521 02 U+ 80..U+ 7FF C2..DF 80..BF
522 03 U+ 800..U+ FFF E0 A0..BF 80..BF
523 04 U+ 1000..U+ CFFF E1..EC 80..BF 80..BF
524 05 U+ D000..U+ D7FF ED 80..9F 80..BF
525 06 U+ E000..U+ FFFF EE..EF 80..BF 80..BF
526 07 U+ 10000..U+ 3FFFF F0 90..BF 80..BF 80..BF
527 08 U+ 40000..U+ FFFFF F1..F3 80..BF 80..BF 80..BF
528 09 U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
530 // ------------------------------------------------------------
533 // ------------------------------------------------------------
535 (nByteOrg_1
>= 0x00) &&
540 nUTF8
= (char)nByte_1
;
542 // ------------------------------------------------------------
546 // ------------------------------------------------------------
549 (nByteOrg_1
>= 0xC2) &&
554 nByteOrg_2
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
555 nByte_1
= nByteOrg_1
-0xC2;
556 nByte_2
= nByteOrg_2
-0x80;
557 nUTF8
= FileHelper
.impl_convertBytesToChar(0,0,nByte_1
, nByte_2
);
559 // ------------------------------------------------------------
564 // ------------------------------------------------------------
566 if (nByteOrg_1
== 0xE0)
569 nByteOrg_2
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0xA0, 0xBF);
570 nByteOrg_3
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
571 nByte_2
= nByteOrg_2
-0xA0;
572 nByte_3
= nByteOrg_3
-0x80;
573 nUTF8
= FileHelper
.impl_convertBytesToChar(0,0,nByte_2
, nByte_3
);
575 // ------------------------------------------------------------
580 // ------------------------------------------------------------
583 (nByteOrg_1
>= 0xE1) &&
588 nByteOrg_2
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
589 nByteOrg_3
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
590 nByte_1
= nByteOrg_1
-0xE1;
591 nByte_2
= nByteOrg_2
-0x80;
592 nByte_3
= nByteOrg_3
-0x80;
593 nUTF8
= FileHelper
.impl_convertBytesToChar(0,nByte_1
, nByte_2
, nByte_3
);
595 // ------------------------------------------------------------
600 // ------------------------------------------------------------
602 if (nByteOrg_1
== 0xED)
605 nByteOrg_2
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0x9F);
606 nByteOrg_3
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
607 nByte_2
= nByteOrg_2
-0x80;
608 nByte_3
= nByteOrg_3
-0x80;
609 nUTF8
= FileHelper
.impl_convertBytesToChar(0,0, nByte_2
, nByte_3
);
611 // ------------------------------------------------------------
616 // ------------------------------------------------------------
619 (nByteOrg_1
>= 0xEE) &&
624 nByteOrg_2
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
625 nByteOrg_3
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
626 nByte_1
= nByteOrg_1
-0xEE;
627 nByte_2
= nByteOrg_2
-0x80;
628 nByte_3
= nByteOrg_3
-0x80;
629 nUTF8
= FileHelper
.impl_convertBytesToChar(0,nByte_1
, nByte_2
, nByte_3
);
631 // ------------------------------------------------------------
637 // ------------------------------------------------------------
639 if (nByteOrg_1
== 0xF0)
642 nByteOrg_2
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x90, 0xBF);
643 nByteOrg_3
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
644 nByteOrg_4
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
645 nByte_2
= nByteOrg_2
-0x90;
646 nByte_3
= nByteOrg_3
-0x80;
647 nByte_4
= nByteOrg_4
-0x80;
648 nUTF8
= FileHelper
.impl_convertBytesToChar(0, nByte_2
, nByte_3
, nByte_4
);
650 // ------------------------------------------------------------
656 // ------------------------------------------------------------
659 (nByteOrg_1
>= 0xF1) &&
664 nByteOrg_2
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
665 nByteOrg_3
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
666 nByteOrg_4
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
667 nByte_1
= nByteOrg_1
-0xF1;
668 nByte_2
= nByteOrg_2
-0x80;
669 nByte_3
= nByteOrg_3
-0x80;
670 nByte_4
= nByteOrg_4
-0x80;
671 nUTF8
= FileHelper
.impl_convertBytesToChar(nByte_1
, nByte_2
, nByte_3
, nByte_4
);
673 // ------------------------------------------------------------
679 // ------------------------------------------------------------
681 if (nByteOrg_1
== 0xF0)
684 nByteOrg_2
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
685 nByteOrg_3
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
686 nByteOrg_4
= FileHelper
.impl_readAndCheckNextByte(aBuffer
, i
++, nReadCount
, 0x80, 0xBF);
687 nByte_2
= nByteOrg_2
-0x80;
688 nByte_3
= nByteOrg_3
-0x80;
689 nByte_4
= nByteOrg_4
-0x80;
690 nUTF8
= FileHelper
.impl_convertBytesToChar(0, nByte_2
, nByte_3
, nByte_4
);
695 throw new java
.lang
.Exception("Non well formed UTF-8 encoding.");
698 sBuffer
.append(nUTF8
);
700 FileHelper
.logEncodingData(sLog
, nUTF8
, nByteOrg_1
, nByteOrg_2
, nByteOrg_3
, nByteOrg_4
, nByte_1
, nByte_2
, nByte_3
, nByte_4
, nEncodingType
);
706 catch(java
.lang
.Throwable ex
)
709 FileHelper
.logEncodingData(sLog
, nUTF8
, nByteOrg_1
, nByteOrg_2
, nByteOrg_3
, nByteOrg_4
, nByte_1
, nByte_2
, nByte_3
, nByte_4
, nEncodingType
);
711 java
.io
.File aDir
= new java
.io
.File(aFile
.getParent());
712 java
.lang
.String sDump
= aFile
.getName();
713 java
.io
.File aDump
= FileHelper
.createUniqueFile(aDir
, sDump
, "dump");
714 FileHelper
.writeEncodedBufferToFile(aDump
, "UTF-8", false, sLog
);
717 java
.lang
.String sMsg
= "File '"+aFile
.getPath()+"' is not encoded right as UTF-8.";
718 throw new java
.io
.IOException(sMsg
);
724 //___________________________________________
726 /** writes the given string buffer into the specified file
727 * using the specified encoding.
729 * Further it can be set, if the file should be expanded
730 * or replaced by this new string buffer.
733 * must point to a system file. It can already exist!
734 * e.g.: "c:\temp\test.txt"
738 * will be used to encode the string content inside the file.
742 * specify if an already existing file will be
743 * expanded or replaced.
746 * the new string content for this file.
748 public static void writeEncodedBufferToFile(java
.io
.File aFile
,
749 java
.lang
.String sEncoding
,
751 java
.lang
.StringBuffer sBuffer
)
752 throws java
.io
.IOException
754 java
.io
.FileOutputStream aByteStream
= new java
.io
.FileOutputStream(aFile
.getAbsolutePath(), bAppend
);
755 java
.io
.OutputStreamWriter aEncodedWriter
= new java
.io
.OutputStreamWriter(aByteStream
, sEncoding
);
757 java
.lang
.String sTemp
= sBuffer
.toString();
758 aEncodedWriter
.write(sTemp
, 0, sTemp
.length());
760 aEncodedWriter
.flush();
761 aEncodedWriter
.close();
764 throw new java
.io
.IOException("File \""+aFile
.getAbsolutePath()+"\" not written correctly.");