~ubuntu-branches/ubuntu/utopic/libjaudiotagger-java/utopic

« back to all changes in this revision

Viewing changes to org/jaudiotagger/audio/generic/AudioFileWriter.java

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath, Damien Raude-Morvan, Varun Hiremath
  • Date: 2009-04-01 19:17:56 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090401191756-bygniim270guy7o1
Tags: 1.0.9-1
[ Damien Raude-Morvan ]
* New upstream release
* debian/watch: Use java.net repository (which contains new releases!)
* debian/control:
  - Build-Depends on default-jdk-builddep
  - Bump Standards-Version to 3.8.1 (no changes needed)
  - Change section to "java"
* debian/rules: use default-java as JAVA_HOME
* debina/orig-tar.{sh|excludes}: strip audio and others binary files from ZIP
* debian/build.xml:
  - compile with "nowarn" to keep build log readable
  - exclude LogFormatter from build (use com.sun classes)
* debian/ant.properties: new source directory is "src" in orig.tar.gz
* Add myself as Uploaders

[ Varun Hiremath ]
* Accept changes made by Damien Raude-Morvan (Closes: #522130)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Entagged Audio Tag library
3
 
 * Copyright (c) 2003-2005 Rapha�l Slinckx <raphael@slinckx.net>
4
 
 * 
5
 
 * This library is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU Lesser General Public
7
 
 * License as published by the Free Software Foundation; either
8
 
 * version 2.1 of the License, or (at your option) any later version.
9
 
 *  
10
 
 * This library is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
 * Lesser General Public License for more details.
14
 
 * 
15
 
 * You should have received a copy of the GNU Lesser General Public
16
 
 * License along with this library; if not, write to the Free Software
17
 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
 */
19
 
package org.jaudiotagger.audio.generic;
20
 
 
21
 
import java.io.File;
22
 
import java.io.IOException;
23
 
import java.io.RandomAccessFile;
24
 
import java.util.logging.Logger;
25
 
 
26
 
import org.jaudiotagger.audio.AudioFile;
27
 
import org.jaudiotagger.tag.Tag;
28
 
import org.jaudiotagger.audio.exceptions.CannotWriteException;
29
 
import org.jaudiotagger.audio.exceptions.ModifyVetoException;
30
 
import org.jaudiotagger.audio.exceptions.CannotReadException;
31
 
 
32
 
/**
33
 
 * This abstract class is the skeleton for tag writers.
34
 
 *
35
 
 * <p>It handles the creation/closing of the randomaccessfile objects and then call the subclass
36
 
 * method writeTag or deleteTag. These two method have to be implemented in the
37
 
 * subclass.
38
 
 *
39
 
 * @author Raphael Slinckx
40
 
 * @version $Id: AudioFileWriter.java,v 1.6 2007/11/23 14:35:42 paultaylor Exp $
41
 
 * @since v0.02
42
 
 */
43
 
public abstract class AudioFileWriter
44
 
{
45
 
 
46
 
     // Logger Object
47
 
    public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.generic");
48
 
 
49
 
    /**
50
 
     * If not <code>null</code>, this listener is used to notify the listener
51
 
     * about modification events.<br>
52
 
     */
53
 
    private AudioFileModificationListener modificationListener = null;
54
 
 
55
 
    /**
56
 
     * Delete the tag (if any) present in the given file
57
 
     *
58
 
     * @param f The file to process
59
 
     * @throws CannotWriteException if anything went wrong
60
 
     */
61
 
    public synchronized void delete(AudioFile f) throws CannotReadException,CannotWriteException
62
 
    {
63
 
        if (!f.getFile().canWrite())
64
 
        {
65
 
            throw new CannotWriteException("Can't write to file \"" + f.getFile().getAbsolutePath() + "\"");
66
 
        }
67
 
 
68
 
        if (f.getFile().length() <= 150)
69
 
        {
70
 
            throw new CannotWriteException("Less than 150 byte \"" + f.getFile().getAbsolutePath() + "\"");
71
 
        }
72
 
 
73
 
        RandomAccessFile raf = null;
74
 
        RandomAccessFile rafTemp = null;
75
 
        File tempF = null;
76
 
        // Will be set to true on VetoException, causing the finally block to
77
 
        // discard
78
 
        // the tempfile.
79
 
        boolean revert = false;
80
 
        try
81
 
        {
82
 
 
83
 
            tempF = File.createTempFile("entagged", ".tmp", f.getFile().getParentFile());
84
 
            rafTemp = new RandomAccessFile(tempF, "rw");
85
 
            raf = new RandomAccessFile(f.getFile(), "rw");
86
 
            raf.seek(0);
87
 
            rafTemp.seek(0);
88
 
 
89
 
            try
90
 
            {
91
 
                if (this.modificationListener != null)
92
 
                {
93
 
                    this.modificationListener.fileWillBeModified(f, true);
94
 
                }
95
 
                deleteTag(raf, rafTemp);
96
 
                if (this.modificationListener != null)
97
 
                {
98
 
                    this.modificationListener.fileModified(f, tempF);
99
 
                }
100
 
            }
101
 
            catch (ModifyVetoException veto)
102
 
            {
103
 
                throw new CannotWriteException(veto);
104
 
            }
105
 
 
106
 
        }
107
 
        catch (Exception e)
108
 
        {
109
 
            revert = true;
110
 
            throw new CannotWriteException("\"" + f.getFile().getAbsolutePath() + "\" :" + e, e);
111
 
        }
112
 
        finally
113
 
        {
114
 
            // will be set to the remaining file.
115
 
            File result = f.getFile();
116
 
            try
117
 
            {
118
 
                if (raf != null)
119
 
                {
120
 
                    raf.close();
121
 
                }
122
 
                if (rafTemp != null)
123
 
                {
124
 
                    rafTemp.close();
125
 
                }
126
 
 
127
 
                if (tempF.length() > 0 && !revert)
128
 
                {
129
 
                    f.getFile().delete();
130
 
                    tempF.renameTo(f.getFile());
131
 
                    result = tempF;
132
 
                }
133
 
                else
134
 
                {
135
 
                    tempF.delete();
136
 
                }
137
 
            }
138
 
            catch (Exception ex)
139
 
            {
140
 
                System.err.println("AudioFileWriter:113:\"" + f.getFile().getAbsolutePath() + "\" or \"" + tempF.getAbsolutePath() + "\" :" + ex);
141
 
            }
142
 
            // Notify listener
143
 
            if (this.modificationListener != null)
144
 
            {
145
 
                this.modificationListener.fileOperationFinished(result);
146
 
            }
147
 
        }
148
 
    }
149
 
 
150
 
    /**
151
 
     * Delete the tag (if any) present in the given randomaccessfile, and do not
152
 
     * close it at the end.
153
 
     *
154
 
     * @param raf     The source file, already opened in r-write mode
155
 
     * @param tempRaf The temporary file opened in r-write mode
156
 
     * @throws CannotWriteException if anything went wrong
157
 
     */
158
 
    public synchronized void delete(RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotReadException,CannotWriteException, IOException
159
 
    {
160
 
        raf.seek(0);
161
 
        tempRaf.seek(0);
162
 
        deleteTag(raf, tempRaf);
163
 
    }
164
 
 
165
 
    /**
166
 
     * Same as above, but delete tag in the file.
167
 
     *
168
 
     * @throws IOException          is thrown when the RandomAccessFile operations throw it
169
 
     *                              (you should never throw them manually)
170
 
     * @throws CannotWriteException when an error occured during the deletion of the tag
171
 
     */
172
 
    protected abstract void deleteTag(RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotReadException,CannotWriteException, IOException;
173
 
 
174
 
    /**
175
 
     * This method sets the {@link AudioFileModificationListener}.<br>
176
 
     * There is only one listener allowed, if you want more instances to be
177
 
     * supported, use the {@link ModificationHandler} to broadcast those events.<br>
178
 
     *
179
 
     * @param listener The listener. <code>null</code> allowed to deregister.
180
 
     */
181
 
    public synchronized void setAudioFileModificationListener(AudioFileModificationListener listener)
182
 
    {
183
 
        this.modificationListener = listener;
184
 
    }
185
 
 
186
 
    /**
187
 
     * Write the tag (if not empty) present in the AudioFile in the associated
188
 
     * File
189
 
     *
190
 
     * @param af The file we want to process
191
 
     * @throws CannotWriteException if anything went wrong
192
 
     */
193
 
    public synchronized void write(AudioFile af) throws CannotWriteException
194
 
    {
195
 
        logger.info("Started writing tag data for file:"+af.getFile().getName());
196
 
 
197
 
        // Preliminary checks
198
 
        try
199
 
        {
200
 
            if (af.getTag().isEmpty())
201
 
            {
202
 
                delete(af);
203
 
                return;
204
 
            }
205
 
        }
206
 
        catch(CannotReadException re)
207
 
        {
208
 
             throw new CannotWriteException("Can't write to file \"" + af.getFile().getAbsolutePath() + "\"");
209
 
        }
210
 
 
211
 
        if (!af.getFile().canWrite())
212
 
        {
213
 
            throw new CannotWriteException("Can't write to file \"" + af.getFile().getAbsolutePath() + "\"");
214
 
        }
215
 
 
216
 
        if (af.getFile().length() <= 150)
217
 
        {
218
 
            throw new CannotWriteException("Less than 150 byte \"" + af.getFile().getAbsolutePath() + "\"");
219
 
        }
220
 
 
221
 
        RandomAccessFile raf     = null;
222
 
        RandomAccessFile rafTemp = null;
223
 
        File tempF = null;
224
 
 
225
 
        // Will be set to true in exception block to not replace original file.
226
 
        boolean cannotWrite = false;
227
 
        try
228
 
        {
229
 
            //TODO Creates temp file in same folder as the original file, this is safe but would impose a performance
230
 
            //overhead if the original file is on a networked drive
231
 
            tempF   = File.createTempFile("entagged", ".tmp", af.getFile().getParentFile());
232
 
            rafTemp = new RandomAccessFile(tempF, "rw");
233
 
            raf = new RandomAccessFile(af.getFile(), "rw");
234
 
            raf.seek(0);
235
 
            rafTemp.seek(0);
236
 
            try
237
 
            {
238
 
                if (this.modificationListener != null)
239
 
                {
240
 
                    this.modificationListener.fileWillBeModified(af, false);
241
 
                }
242
 
                writeTag(af.getTag(), raf, rafTemp);
243
 
                if (this.modificationListener != null)
244
 
                {
245
 
                    this.modificationListener.fileModified(af, tempF);
246
 
                }
247
 
            }
248
 
            catch (ModifyVetoException veto)
249
 
            {
250
 
                throw new CannotWriteException(veto);
251
 
            }
252
 
        }
253
 
        catch (Exception e)
254
 
        {
255
 
            e.printStackTrace(System.err);
256
 
            cannotWrite = true;            
257
 
            throw new CannotWriteException("\"" + af.getFile().getAbsolutePath() + "\" :" + e.getMessage());
258
 
        }
259
 
        finally
260
 
        {
261
 
            File result = af.getFile();
262
 
            try
263
 
            {
264
 
                if (raf != null)
265
 
                {
266
 
                    raf.close();
267
 
                }
268
 
                if (rafTemp != null)
269
 
                {
270
 
                    rafTemp.close();
271
 
                }
272
 
 
273
 
                //If the tempoaray file was used and there were no problems replace original file with it
274
 
                if (!cannotWrite && tempF.length() > 0)
275
 
                {
276
 
                    af.getFile().delete();
277
 
                    tempF.renameTo(af.getFile());
278
 
                    result = tempF;
279
 
                }
280
 
                //Either the original file was directly written to or the temp file was used but the write failed
281
 
                //in either case delete the temp file.
282
 
                else
283
 
                {                       
284
 
                    tempF.delete();
285
 
                }
286
 
            }
287
 
            catch (Exception ex)
288
 
            {
289
 
                System.err.println("AudioFileWriter:165:\"" + af.getFile().getAbsolutePath() + "\" or \"" + tempF.getAbsolutePath() + "\" :" + ex);
290
 
            }
291
 
 
292
 
            if (this.modificationListener != null)
293
 
            {
294
 
                this.modificationListener.fileOperationFinished(result);
295
 
            }
296
 
        }
297
 
    }
298
 
 
299
 
    /**
300
 
     * This is called when a tag has to be written in a file. Three parameters
301
 
     * are provided, the tag to write (not empty) Two randomaccessfiles, the
302
 
     * first points to the file where we want to write the given tag, and the
303
 
     * second is an empty temporary file that can be used if e.g. the file has
304
 
     * to be bigger than the original.
305
 
     * <p/>
306
 
     * If something has been written in the temporary file, when this method
307
 
     * returns, the original file is deleted, and the temporary file is renamed
308
 
     * the the original name
309
 
     * <p/>
310
 
     * If nothing has been written to it, it is simply deleted.
311
 
     * <p/>
312
 
     * This method can assume the raf, rafTemp are pointing to the first byte of
313
 
     * the file. The subclass must not close these two files when the method
314
 
     * returns.
315
 
     *
316
 
     * @throws IOException          is thrown when the RandomAccessFile operations throw it
317
 
     *                              (you should never throw them manually)
318
 
     * @throws CannotWriteException when an error occured during the generation of the tag
319
 
     */
320
 
    protected abstract void writeTag(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotReadException,CannotWriteException, IOException;
321
 
 
322
 
}