001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.util;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
018    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
019    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.nio.charset.CharsetEncoderUtil;
023    import com.liferay.portal.kernel.process.ClassPathUtil;
024    import com.liferay.portal.kernel.process.ProcessCallable;
025    import com.liferay.portal.kernel.process.ProcessChannel;
026    import com.liferay.portal.kernel.process.ProcessException;
027    import com.liferay.portal.kernel.process.ProcessExecutorUtil;
028    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
029    import com.liferay.portal.kernel.util.ArrayUtil;
030    import com.liferay.portal.kernel.util.CharPool;
031    import com.liferay.portal.kernel.util.ClassLoaderUtil;
032    import com.liferay.portal.kernel.util.Digester;
033    import com.liferay.portal.kernel.util.DigesterUtil;
034    import com.liferay.portal.kernel.util.FileComparator;
035    import com.liferay.portal.kernel.util.PwdGenerator;
036    import com.liferay.portal.kernel.util.ReflectionUtil;
037    import com.liferay.portal.kernel.util.StreamUtil;
038    import com.liferay.portal.kernel.util.StringBundler;
039    import com.liferay.portal.kernel.util.StringPool;
040    import com.liferay.portal.kernel.util.StringUtil;
041    import com.liferay.portal.kernel.util.SystemProperties;
042    import com.liferay.portal.kernel.util.Time;
043    import com.liferay.portal.kernel.util.Validator;
044    import com.liferay.util.ant.ExpandTask;
045    
046    import java.io.File;
047    import java.io.FileInputStream;
048    import java.io.FileOutputStream;
049    import java.io.FileReader;
050    import java.io.IOException;
051    import java.io.InputStream;
052    import java.io.OutputStreamWriter;
053    import java.io.RandomAccessFile;
054    import java.io.Reader;
055    import java.io.Writer;
056    
057    import java.nio.ByteBuffer;
058    import java.nio.channels.FileChannel;
059    
060    import java.util.ArrayList;
061    import java.util.Arrays;
062    import java.util.List;
063    import java.util.Properties;
064    import java.util.concurrent.Future;
065    
066    import org.apache.commons.compress.archivers.zip.UnsupportedZipFeatureException;
067    import org.apache.commons.io.FileUtils;
068    import org.apache.commons.lang.exception.ExceptionUtils;
069    import org.apache.pdfbox.exceptions.CryptographyException;
070    import org.apache.poi.EncryptedDocumentException;
071    import org.apache.tika.Tika;
072    import org.apache.tika.exception.TikaException;
073    import org.apache.tools.ant.DirectoryScanner;
074    
075    import org.mozilla.intl.chardet.nsDetector;
076    import org.mozilla.intl.chardet.nsPSMDetector;
077    
078    /**
079     * @author Brian Wing Shun Chan
080     * @author Alexander Chow
081     */
082    @DoPrivileged
083    public class FileImpl implements com.liferay.portal.kernel.util.File {
084    
085            public static FileImpl getInstance() {
086                    return _instance;
087            }
088    
089            @Override
090            public void copyDirectory(File source, File destination)
091                    throws IOException {
092    
093                    if (!source.exists() || !source.isDirectory()) {
094                            return;
095                    }
096    
097                    mkdirs(destination);
098    
099                    File[] fileArray = source.listFiles();
100    
101                    for (int i = 0; i < fileArray.length; i++) {
102                            if (fileArray[i].isDirectory()) {
103                                    copyDirectory(
104                                            fileArray[i],
105                                            new File(
106                                                    destination.getPath() + File.separator +
107                                                            fileArray[i].getName()));
108                            }
109                            else {
110                                    copyFile(
111                                            fileArray[i],
112                                            new File(
113                                                    destination.getPath() + File.separator +
114                                                            fileArray[i].getName()));
115                            }
116                    }
117            }
118    
119            @Override
120            public void copyDirectory(String sourceDirName, String destinationDirName)
121                    throws IOException {
122    
123                    copyDirectory(new File(sourceDirName), new File(destinationDirName));
124            }
125    
126            @Override
127            public void copyFile(File source, File destination) throws IOException {
128                    copyFile(source, destination, false);
129            }
130    
131            @Override
132            public void copyFile(File source, File destination, boolean lazy)
133                    throws IOException {
134    
135                    if (!source.exists()) {
136                            return;
137                    }
138    
139                    if (lazy) {
140                            String oldContent = null;
141    
142                            try {
143                                    oldContent = read(source);
144                            }
145                            catch (Exception e) {
146                                    return;
147                            }
148    
149                            String newContent = null;
150    
151                            try {
152                                    newContent = read(destination);
153                            }
154                            catch (Exception e) {
155                            }
156    
157                            if ((oldContent == null) || !oldContent.equals(newContent)) {
158                                    copyFile(source, destination, false);
159                            }
160                    }
161                    else {
162                            mkdirsParentFile(destination);
163    
164                            StreamUtil.transfer(
165                                    new FileInputStream(source), new FileOutputStream(destination));
166                    }
167            }
168    
169            @Override
170            public void copyFile(String source, String destination) throws IOException {
171                    copyFile(source, destination, false);
172            }
173    
174            @Override
175            public void copyFile(String source, String destination, boolean lazy)
176                    throws IOException {
177    
178                    copyFile(new File(source), new File(destination), lazy);
179            }
180    
181            @Override
182            public File createTempFile() {
183                    return createTempFile(StringPool.BLANK);
184            }
185    
186            @Override
187            public File createTempFile(byte[] bytes) throws IOException {
188                    File file = createTempFile(StringPool.BLANK);
189    
190                    write(file, bytes, false);
191    
192                    return file;
193            }
194    
195            @Override
196            public File createTempFile(InputStream is) throws IOException {
197                    File file = createTempFile(StringPool.BLANK);
198    
199                    write(file, is);
200    
201                    return file;
202            }
203    
204            @Override
205            public File createTempFile(String extension) {
206                    return new File(createTempFileName(extension));
207            }
208    
209            @Override
210            public File createTempFile(String prefix, String extension) {
211                    return new File(createTempFileName(prefix, extension));
212            }
213    
214            @Override
215            public String createTempFileName() {
216                    return createTempFileName(null, null);
217            }
218    
219            @Override
220            public String createTempFileName(String extension) {
221                    return createTempFileName(null, extension);
222            }
223    
224            @Override
225            public String createTempFileName(String prefix, String extension) {
226                    StringBundler sb = new StringBundler(7);
227    
228                    sb.append(SystemProperties.get(SystemProperties.TMP_DIR));
229                    sb.append(StringPool.SLASH);
230    
231                    if (Validator.isNotNull(prefix)) {
232                            sb.append(prefix);
233                    }
234    
235                    sb.append(Time.getTimestamp());
236                    sb.append(PwdGenerator.getPassword(8, PwdGenerator.KEY2));
237    
238                    if (Validator.isFileExtension(extension)) {
239                            sb.append(StringPool.PERIOD);
240                            sb.append(extension);
241                    }
242    
243                    return sb.toString();
244            }
245    
246            @Override
247            public File createTempFolder() throws IOException {
248                    File file = new File(createTempFileName());
249    
250                    mkdirs(file);
251    
252                    return file;
253            }
254    
255            @Override
256            public String decodeSafeFileName(String fileName) {
257                    return StringUtil.replace(
258                            fileName, _SAFE_FILE_NAME_2, _SAFE_FILE_NAME_1);
259            }
260    
261            @Override
262            public boolean delete(File file) {
263                    if (file != null) {
264                            boolean exists = true;
265    
266                            try {
267                                    exists = file.exists();
268                            }
269                            catch (SecurityException se) {
270    
271                                    // We may have the permission to delete a specific file without
272                                    // having the permission to check if the file exists
273    
274                            }
275    
276                            if (exists) {
277                                    return file.delete();
278                            }
279                    }
280    
281                    return false;
282            }
283    
284            @Override
285            public boolean delete(String file) {
286                    return delete(new File(file));
287            }
288    
289            @Override
290            public void deltree(File directory) {
291                    if (directory.exists() && directory.isDirectory()) {
292                            File[] fileArray = directory.listFiles();
293    
294                            for (int i = 0; i < fileArray.length; i++) {
295                                    if (fileArray[i].isDirectory()) {
296                                            deltree(fileArray[i]);
297                                    }
298                                    else {
299                                            fileArray[i].delete();
300                                    }
301                            }
302    
303                            directory.delete();
304                    }
305            }
306    
307            @Override
308            public void deltree(String directory) {
309                    deltree(new File(directory));
310            }
311    
312            @Override
313            public String encodeSafeFileName(String fileName) {
314                    if (fileName == null) {
315                            return StringPool.BLANK;
316                    }
317    
318                    return StringUtil.replace(
319                            fileName, _SAFE_FILE_NAME_1, _SAFE_FILE_NAME_2);
320            }
321    
322            @Override
323            public boolean exists(File file) {
324                    return file.exists();
325            }
326    
327            @Override
328            public boolean exists(String fileName) {
329                    return exists(new File(fileName));
330            }
331    
332            @Override
333            public String extractText(InputStream is, String fileName) {
334                    return extractText(is, fileName, -1);
335            }
336    
337            @Override
338            public String extractText(
339                    InputStream is, String fileName, int maxStringLength) {
340    
341                    if (maxStringLength == 0) {
342                            return StringPool.BLANK;
343                    }
344    
345                    String text = null;
346    
347                    ClassLoader portalClassLoader = ClassLoaderUtil.getPortalClassLoader();
348    
349                    ClassLoader contextClassLoader =
350                            ClassLoaderUtil.getContextClassLoader();
351    
352                    try {
353                            if (contextClassLoader != portalClassLoader) {
354                                    ClassLoaderUtil.setContextClassLoader(portalClassLoader);
355                            }
356    
357                            Tika tika = new Tika();
358    
359                            tika.setMaxStringLength(maxStringLength);
360    
361                            boolean forkProcess = false;
362    
363                            if (PropsValues.TEXT_EXTRACTION_FORK_PROCESS_ENABLED) {
364                                    String mimeType = tika.detect(is);
365    
366                                    if (ArrayUtil.contains(
367                                                    PropsValues.TEXT_EXTRACTION_FORK_PROCESS_MIME_TYPES,
368                                                    mimeType)) {
369    
370                                            forkProcess = true;
371                                    }
372                            }
373    
374                            if (forkProcess) {
375                                    ProcessChannel<String> processChannel =
376                                            ProcessExecutorUtil.execute(
377                                                    ClassPathUtil.getPortalProcessConfig(),
378                                                    new ExtractTextProcessCallable(getBytes(is)));
379    
380                                    Future<String> future =
381                                            processChannel.getProcessNoticeableFuture();
382    
383                                    text = future.get();
384                            }
385                            else {
386                                    text = tika.parseToString(is);
387                            }
388                    }
389                    catch (Exception e) {
390                            Throwable throwable = ExceptionUtils.getRootCause(e);
391    
392                            if ((throwable instanceof CryptographyException) ||
393                                    (throwable instanceof EncryptedDocumentException) ||
394                                    (throwable instanceof UnsupportedZipFeatureException)) {
395    
396                                    if (_log.isWarnEnabled()) {
397                                            _log.warn(
398                                                    "Unable to extract text from an encrypted file " +
399                                                            fileName);
400                                    }
401                            }
402                            else if (e instanceof TikaException) {
403                                    if (_log.isWarnEnabled()) {
404                                            _log.warn("Unable to extract text from " + fileName);
405                                    }
406                            }
407                            else {
408                                    _log.error(e, e);
409                            }
410                    }
411                    finally {
412                            if (contextClassLoader != portalClassLoader) {
413                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
414                            }
415                    }
416    
417                    if (_log.isInfoEnabled()) {
418                            if (text == null) {
419                                    _log.info("Text extraction failed for " + fileName);
420                            }
421                            else {
422                                    _log.info("Text was extracted for " + fileName);
423                            }
424                    }
425    
426                    if (_log.isDebugEnabled()) {
427                            _log.debug("Extractor returned text:\n\n" + text);
428                    }
429    
430                    if (text == null) {
431                            text = StringPool.BLANK;
432                    }
433    
434                    return text;
435            }
436    
437            @Override
438            public String[] find(String directory, String includes, String excludes) {
439                    if (directory.length() > 0) {
440                            directory = replaceSeparator(directory);
441    
442                            if (directory.charAt(directory.length() - 1) == CharPool.SLASH) {
443                                    directory = directory.substring(0, directory.length() - 1);
444                            }
445                    }
446    
447                    if (!exists(directory)) {
448                            if (_log.isWarnEnabled()) {
449                                    _log.warn("Directory " + directory + " does not exist");
450                            }
451    
452                            return new String[0];
453                    }
454    
455                    DirectoryScanner directoryScanner = new DirectoryScanner();
456    
457                    directoryScanner.setBasedir(directory);
458                    directoryScanner.setExcludes(StringUtil.split(excludes));
459                    directoryScanner.setIncludes(StringUtil.split(includes));
460    
461                    directoryScanner.scan();
462    
463                    String[] includedFiles = directoryScanner.getIncludedFiles();
464    
465                    for (int i = 0; i < includedFiles.length; i++) {
466                            includedFiles[i] = directory.concat(
467                                    StringPool.SLASH).concat(replaceSeparator(includedFiles[i]));
468                    }
469    
470                    return includedFiles;
471            }
472    
473            @Override
474            public String getAbsolutePath(File file) {
475                    return StringUtil.replace(
476                            file.getAbsolutePath(), CharPool.BACK_SLASH, CharPool.SLASH);
477            }
478    
479            @Override
480            public byte[] getBytes(Class<?> clazz, String fileName) throws IOException {
481                    return getBytes(clazz.getResourceAsStream(fileName));
482            }
483    
484            @Override
485            public byte[] getBytes(File file) throws IOException {
486                    if ((file == null) || !file.exists()) {
487                            return null;
488                    }
489    
490                    try (RandomAccessFile randomAccessFile = new RandomAccessFile(
491                                    file, "r")) {
492    
493                            byte[] bytes = new byte[(int)randomAccessFile.length()];
494    
495                            randomAccessFile.readFully(bytes);
496    
497                            return bytes;
498                    }
499            }
500    
501            @Override
502            public byte[] getBytes(InputStream is) throws IOException {
503                    return getBytes(is, -1);
504            }
505    
506            @Override
507            public byte[] getBytes(InputStream inputStream, int bufferSize)
508                    throws IOException {
509    
510                    return getBytes(inputStream, bufferSize, true);
511            }
512    
513            @Override
514            public byte[] getBytes(
515                            InputStream inputStream, int bufferSize, boolean cleanUpStream)
516                    throws IOException {
517    
518                    if (inputStream == null) {
519                            return null;
520                    }
521    
522                    UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
523                            new UnsyncByteArrayOutputStream();
524    
525                    StreamUtil.transfer(
526                            inputStream, unsyncByteArrayOutputStream, bufferSize,
527                            cleanUpStream);
528    
529                    return unsyncByteArrayOutputStream.toByteArray();
530            }
531    
532            @Override
533            public String getExtension(String fileName) {
534                    if (fileName == null) {
535                            return null;
536                    }
537    
538                    int pos = fileName.lastIndexOf(CharPool.PERIOD);
539    
540                    if (pos > 0) {
541                            return StringUtil.toLowerCase(
542                                    fileName.substring(pos + 1, fileName.length()));
543                    }
544                    else {
545                            return StringPool.BLANK;
546                    }
547            }
548    
549            @Override
550            public String getMD5Checksum(File file) throws IOException {
551                    FileInputStream fileInputStream = null;
552    
553                    try {
554                            fileInputStream = new FileInputStream(file);
555    
556                            return DigesterUtil.digestHex(Digester.MD5, fileInputStream);
557                    }
558                    finally {
559                            StreamUtil.cleanUp(fileInputStream);
560                    }
561            }
562    
563            @Override
564            public String getPath(String fullFileName) {
565                    int x = fullFileName.lastIndexOf(CharPool.SLASH);
566                    int y = fullFileName.lastIndexOf(CharPool.BACK_SLASH);
567    
568                    if ((x == -1) && (y == -1)) {
569                            return StringPool.SLASH;
570                    }
571    
572                    String shortFileName = fullFileName.substring(0, Math.max(x, y));
573    
574                    return shortFileName;
575            }
576    
577            @Override
578            public String getShortFileName(String fullFileName) {
579                    int x = fullFileName.lastIndexOf(CharPool.SLASH);
580                    int y = fullFileName.lastIndexOf(CharPool.BACK_SLASH);
581    
582                    String shortFileName = fullFileName.substring(Math.max(x, y) + 1);
583    
584                    return shortFileName;
585            }
586    
587            @Override
588            public boolean isAscii(File file) throws IOException {
589                    boolean ascii = true;
590    
591                    nsDetector detector = new nsDetector(nsPSMDetector.ALL);
592    
593                    try (InputStream inputStream = new FileInputStream(file)) {
594                            byte[] buffer = new byte[1024];
595    
596                            int len = 0;
597    
598                            while ((len = inputStream.read(buffer, 0, buffer.length)) != -1) {
599                                    if (ascii) {
600                                            ascii = detector.isAscii(buffer, len);
601    
602                                            if (!ascii) {
603                                                    break;
604                                            }
605                                    }
606                            }
607    
608                            detector.DataEnd();
609                    }
610    
611                    return ascii;
612            }
613    
614            @Override
615            public boolean isSameContent(File file, byte[] bytes, int length) {
616                    FileChannel fileChannel = null;
617    
618                    try {
619                            FileInputStream fileInputStream = new FileInputStream(file);
620    
621                            fileChannel = fileInputStream.getChannel();
622    
623                            if (fileChannel.size() != length) {
624                                    return false;
625                            }
626    
627                            byte[] buffer = new byte[1024];
628    
629                            ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
630    
631                            int bufferIndex = 0;
632                            int bufferLength = -1;
633    
634                            while (((bufferLength = fileChannel.read(byteBuffer)) > 0) &&
635                                       (bufferIndex < length)) {
636    
637                                    for (int i = 0; i < bufferLength; i++) {
638                                            if (buffer[i] != bytes[bufferIndex++]) {
639                                                    return false;
640                                            }
641                                    }
642    
643                                    byteBuffer.clear();
644                            }
645    
646                            if ((bufferIndex != length) || (bufferLength != -1)) {
647                                    return false;
648                            }
649                            else {
650                                    return true;
651                            }
652                    }
653                    catch (Exception e) {
654                            return false;
655                    }
656                    finally {
657                            if (fileChannel != null) {
658                                    try {
659                                            fileChannel.close();
660                                    }
661                                    catch (IOException ioe) {
662                                    }
663                            }
664                    }
665            }
666    
667            @Override
668            public boolean isSameContent(File file, String s) {
669                    ByteBuffer byteBuffer = CharsetEncoderUtil.encode(StringPool.UTF8, s);
670    
671                    return isSameContent(file, byteBuffer.array(), byteBuffer.limit());
672            }
673    
674            @Override
675            public String[] listDirs(File file) {
676                    List<String> dirs = new ArrayList<>();
677    
678                    File[] fileArray = file.listFiles();
679    
680                    for (int i = 0; (fileArray != null) && (i < fileArray.length); i++) {
681                            if (fileArray[i].isDirectory()) {
682                                    dirs.add(fileArray[i].getName());
683                            }
684                    }
685    
686                    return dirs.toArray(new String[dirs.size()]);
687            }
688    
689            @Override
690            public String[] listDirs(String fileName) {
691                    return listDirs(new File(fileName));
692            }
693    
694            @Override
695            public String[] listFiles(File file) {
696                    List<String> files = new ArrayList<>();
697    
698                    File[] fileArray = file.listFiles();
699    
700                    for (int i = 0; (fileArray != null) && (i < fileArray.length); i++) {
701                            if (fileArray[i].isFile()) {
702                                    files.add(fileArray[i].getName());
703                            }
704                    }
705    
706                    return files.toArray(new String[files.size()]);
707            }
708    
709            @Override
710            public String[] listFiles(String fileName) {
711                    if (Validator.isNull(fileName)) {
712                            return new String[0];
713                    }
714    
715                    return listFiles(new File(fileName));
716            }
717    
718            @Override
719            public void mkdirs(File file) throws IOException {
720                    FileUtils.forceMkdir(file);
721            }
722    
723            @Override
724            public void mkdirs(String pathName) {
725                    File file = new File(pathName);
726    
727                    if (file.exists() && file.isDirectory()) {
728                            if (_log.isDebugEnabled()) {
729                                    _log.debug("Directory " + pathName + " already exists");
730                            }
731    
732                            return;
733                    }
734    
735                    try {
736                            mkdirs(file);
737                    }
738                    catch (IOException ioe) {
739                            ReflectionUtil.throwException(ioe);
740                    }
741            }
742    
743            @Override
744            public boolean move(File source, File destination) {
745                    if (!source.exists()) {
746                            return false;
747                    }
748    
749                    destination.delete();
750    
751                    try {
752                            if (source.isDirectory()) {
753                                    FileUtils.moveDirectory(source, destination);
754                            }
755                            else {
756                                    FileUtils.moveFile(source, destination);
757                            }
758                    }
759                    catch (IOException ioe) {
760                            return false;
761                    }
762    
763                    return true;
764            }
765    
766            @Override
767            public boolean move(String sourceFileName, String destinationFileName) {
768                    return move(new File(sourceFileName), new File(destinationFileName));
769            }
770    
771            @Override
772            public String read(File file) throws IOException {
773                    return read(file, false);
774            }
775    
776            @Override
777            public String read(File file, boolean raw) throws IOException {
778                    byte[] bytes = getBytes(file);
779    
780                    if (bytes == null) {
781                            return null;
782                    }
783    
784                    String s = new String(bytes, StringPool.UTF8);
785    
786                    if (raw) {
787                            return s;
788                    }
789                    else {
790                            return StringUtil.replace(
791                                    s, StringPool.RETURN_NEW_LINE, StringPool.NEW_LINE);
792                    }
793            }
794    
795            @Override
796            public String read(String fileName) throws IOException {
797                    return read(new File(fileName));
798            }
799    
800            @Override
801            public String replaceSeparator(String fileName) {
802                    return StringUtil.replace(
803                            fileName, CharPool.BACK_SLASH, CharPool.SLASH);
804            }
805    
806            @Override
807            public File[] sortFiles(File[] files) {
808                    if (files == null) {
809                            return null;
810                    }
811    
812                    Arrays.sort(files, new FileComparator());
813    
814                    List<File> directoryList = new ArrayList<>();
815                    List<File> fileList = new ArrayList<>();
816    
817                    for (int i = 0; i < files.length; i++) {
818                            if (files[i].isDirectory()) {
819                                    directoryList.add(files[i]);
820                            }
821                            else {
822                                    fileList.add(files[i]);
823                            }
824                    }
825    
826                    directoryList.addAll(fileList);
827    
828                    return directoryList.toArray(new File[directoryList.size()]);
829            }
830    
831            @Override
832            public String stripExtension(String fileName) {
833                    if (fileName == null) {
834                            return null;
835                    }
836    
837                    String ext = getExtension(fileName);
838    
839                    if (ext.length() > 0) {
840                            return fileName.substring(0, fileName.length() - ext.length() - 1);
841                    }
842                    else {
843                            return fileName;
844                    }
845            }
846    
847            @Override
848            public List<String> toList(Reader reader) {
849                    List<String> list = new ArrayList<>();
850    
851                    try (UnsyncBufferedReader unsyncBufferedReader =
852                                    new UnsyncBufferedReader(reader)) {
853    
854                            String line = null;
855    
856                            while ((line = unsyncBufferedReader.readLine()) != null) {
857                                    list.add(line);
858                            }
859                    }
860                    catch (IOException ioe) {
861                    }
862    
863                    return list;
864            }
865    
866            @Override
867            public List<String> toList(String fileName) {
868                    try {
869                            return toList(new FileReader(fileName));
870                    }
871                    catch (IOException ioe) {
872                            return new ArrayList<>();
873                    }
874            }
875    
876            @Override
877            public Properties toProperties(FileInputStream fis) {
878                    Properties properties = new Properties();
879    
880                    try {
881                            properties.load(fis);
882                    }
883                    catch (IOException ioe) {
884                    }
885    
886                    return properties;
887            }
888    
889            @Override
890            public Properties toProperties(String fileName) {
891                    try {
892                            return toProperties(new FileInputStream(fileName));
893                    }
894                    catch (IOException ioe) {
895                            return new Properties();
896                    }
897            }
898    
899            @Override
900            public void touch(File file) throws IOException {
901                    FileUtils.touch(file);
902            }
903    
904            @Override
905            public void touch(String fileName) throws IOException {
906                    touch(new File(fileName));
907            }
908    
909            @Override
910            public void unzip(File source, File destination) {
911                    ExpandTask.expand(source, destination);
912            }
913    
914            @Override
915            public void write(File file, byte[] bytes) throws IOException {
916                    write(file, bytes, 0, bytes.length, false);
917            }
918    
919            @Override
920            public void write(File file, byte[] bytes, boolean append)
921                    throws IOException {
922    
923                    write(file, bytes, 0, bytes.length, append);
924            }
925    
926            @Override
927            public void write(File file, byte[] bytes, int offset, int length)
928                    throws IOException {
929    
930                    write(file, bytes, offset, bytes.length, false);
931            }
932    
933            @Override
934            public void write(
935                            File file, byte[] bytes, int offset, int length, boolean append)
936                    throws IOException {
937    
938                    mkdirsParentFile(file);
939    
940                    try (FileOutputStream fileOutputStream = new FileOutputStream(
941                                    file, append)) {
942    
943                            fileOutputStream.write(bytes, offset, length);
944                    }
945            }
946    
947            @Override
948            public void write(File file, InputStream is) throws IOException {
949                    mkdirsParentFile(file);
950    
951                    StreamUtil.transfer(is, new FileOutputStream(file));
952            }
953    
954            @Override
955            public void write(File file, String s) throws IOException {
956                    write(file, s, false);
957            }
958    
959            @Override
960            public void write(File file, String s, boolean lazy) throws IOException {
961                    write(file, s, lazy, false);
962            }
963    
964            @Override
965            public void write(File file, String s, boolean lazy, boolean append)
966                    throws IOException {
967    
968                    if (s == null) {
969                            return;
970                    }
971    
972                    mkdirsParentFile(file);
973    
974                    if (lazy && file.exists()) {
975                            String content = read(file);
976    
977                            if (content.equals(s)) {
978                                    return;
979                            }
980                    }
981    
982                    try (Writer writer = new OutputStreamWriter(
983                                    new FileOutputStream(file, append), StringPool.UTF8)) {
984    
985                            writer.write(s);
986                    }
987            }
988    
989            @Override
990            public void write(String fileName, byte[] bytes) throws IOException {
991                    write(new File(fileName), bytes);
992            }
993    
994            @Override
995            public void write(String fileName, InputStream is) throws IOException {
996                    write(new File(fileName), is);
997            }
998    
999            @Override
1000            public void write(String fileName, String s) throws IOException {
1001                    write(new File(fileName), s);
1002            }
1003    
1004            @Override
1005            public void write(String fileName, String s, boolean lazy)
1006                    throws IOException {
1007    
1008                    write(new File(fileName), s, lazy);
1009            }
1010    
1011            @Override
1012            public void write(String fileName, String s, boolean lazy, boolean append)
1013                    throws IOException {
1014    
1015                    write(new File(fileName), s, lazy, append);
1016            }
1017    
1018            @Override
1019            public void write(String pathName, String fileName, String s)
1020                    throws IOException {
1021    
1022                    write(new File(pathName, fileName), s);
1023            }
1024    
1025            @Override
1026            public void write(String pathName, String fileName, String s, boolean lazy)
1027                    throws IOException {
1028    
1029                    write(new File(pathName, fileName), s, lazy);
1030            }
1031    
1032            @Override
1033            public void write(
1034                            String pathName, String fileName, String s, boolean lazy,
1035                            boolean append)
1036                    throws IOException {
1037    
1038                    write(new File(pathName, fileName), s, lazy, append);
1039            }
1040    
1041            protected void mkdirsParentFile(File file) throws IOException {
1042                    File parentFile = file.getParentFile();
1043    
1044                    if (parentFile == null) {
1045                            return;
1046                    }
1047    
1048                    try {
1049                            mkdirs(parentFile);
1050                    }
1051                    catch (SecurityException se) {
1052    
1053                            // We may have the permission to write a specific file without
1054                            // having the permission to check if the parent file exists
1055    
1056                    }
1057            }
1058    
1059            private static final String[] _SAFE_FILE_NAME_1 = {
1060                    StringPool.AMPERSAND, StringPool.CLOSE_PARENTHESIS,
1061                    StringPool.OPEN_PARENTHESIS, StringPool.SEMICOLON
1062            };
1063    
1064            private static final String[] _SAFE_FILE_NAME_2 = {
1065                    "_AMP_", "_CP_", "_OP_", "_SEM_"
1066            };
1067    
1068            private static final Log _log = LogFactoryUtil.getLog(FileImpl.class);
1069    
1070            private static final FileImpl _instance = new FileImpl();
1071    
1072            private static class ExtractTextProcessCallable
1073                    implements ProcessCallable<String> {
1074    
1075                    public ExtractTextProcessCallable(byte[] data) {
1076                            _data = data;
1077                    }
1078    
1079                    @Override
1080                    public String call() throws ProcessException {
1081                            Tika tika = new Tika();
1082    
1083                            try {
1084                                    return tika.parseToString(
1085                                            new UnsyncByteArrayInputStream(_data));
1086                            }
1087                            catch (Exception e) {
1088                                    throw new ProcessException(e);
1089                            }
1090                    }
1091    
1092                    private static final long serialVersionUID = 1L;
1093    
1094                    private final byte[] _data;
1095    
1096            }
1097    
1098    }