summaryrefslogtreecommitdiff
path: root/src/proguard/io/DirectoryWriter.java
blob: e44e195e12d61e400b3d2855688de0823becc10f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
 * ProGuard -- shrinking, optimization, obfuscation, and preverification
 *             of Java bytecode.
 *
 * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package proguard.io;

import proguard.classfile.ClassConstants;

import java.io.*;


/**
 * This DataEntryWriter writes data entries to individual files in a given
 * directory.
 *
 * @author Eric Lafortune
 */
public class DirectoryWriter implements DataEntryWriter
{
    private final File    baseFile;
    private final boolean isFile;

    private File         currentFile;
    private OutputStream currentOutputStream;
    private Finisher     currentFinisher;


    /**
     * Creates a new DirectoryWriter.
     * @param baseFile the base directory to which all files will be written.
     */
    public DirectoryWriter(File    baseFile,
                           boolean isFile)
    {
        this.baseFile = baseFile;
        this.isFile   = isFile;
    }


    // Implementations for DataEntryWriter.

    public boolean createDirectory(DataEntry dataEntry) throws IOException
    {
        // Should we close the current file?
        if (!isFile &&
            currentFile != null)
        {
            closeEntry();
        }

        File directory = getFile(dataEntry);
        if (!directory.exists() &&
            !directory.mkdirs())
        {
            throw new IOException("Can't create directory [" + directory.getPath() + "]");
        }

        return true;
    }


    public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
    {
        return getOutputStream(dataEntry,  null);
    }


    public OutputStream getOutputStream(DataEntry dataEntry,
                                        Finisher  finisher) throws IOException
    {
        File file = getFile(dataEntry);

        // Should we close the current file?
        if (!isFile             &&
            currentFile != null &&
            !currentFile.equals(file))
        {
            closeEntry();
        }

        // Do we need a new stream?
        if (currentOutputStream == null)
        {
            // Make sure the parent directories exist.
            File parentDirectory = file.getParentFile();
            if (parentDirectory != null   &&
                !parentDirectory.exists() &&
                !parentDirectory.mkdirs())
            {
                throw new IOException("Can't create directory [" + parentDirectory.getPath() + "]");
            }

            // Open a new output stream for writing to the file.
            currentOutputStream =
                new BufferedOutputStream(
                new FileOutputStream(file));

            currentFinisher = finisher;
            currentFile     = file;
        }

        return currentOutputStream;
    }


    public void close() throws IOException
    {
        // Close the file stream, if any.
        closeEntry();
    }


    // Small utility methods.

    /**
     * Returns the file for the given data entry.
     */
    private File getFile(DataEntry dataEntry)
    {
        // Use the specified file, or construct a new file.
        return isFile ?
            baseFile :
            new File(baseFile,
                     dataEntry.getName().replace(ClassConstants.PACKAGE_SEPARATOR,
                                                 File.separatorChar));
    }


    /**
     * Closes the previous file, if any.
     */
    private void closeEntry() throws IOException
    {
        // Close the file stream, if any.
        if (currentOutputStream != null)
        {
            // Let any finisher finish up first.
            if (currentFinisher != null)
            {
                currentFinisher.finish();
                currentFinisher = null;
            }

            currentOutputStream.close();
            currentOutputStream = null;
            currentFile         = null;
        }
    }
}