001    package sears.file;
002    /////////////////////////////////////////////////
003    //This file is part of Sears project.
004    //Subtitle Editor And Re-Synch
005    //A tool to easily modify and resynch movies subtitles.
006    /////////////////////////////////////////////////
007    //This program is free software; 
008    //you can redistribute it and/or modify it under the terms 
009    //of the GNU General Public License 
010    //as published by the Free Software Foundation; 
011    //either version 2 of the License, or (at your option) any later version.
012    /////////////////////////////////////////////////
013    //Sears project is available under sourceforge
014    //at adress: http://sourceforge.net/projects/sears/
015    //Copyright (C) 2005 Booba Skaya
016    //Mail: booba.skaya@gmail.com
017    /////////////////////////////////////////////////
018    
019    //some suggestions about this class: floriaen@gmail.com
020    
021    import java.io.BufferedReader;
022    import java.io.File;
023    import java.io.FileInputStream;
024    import java.io.FileNotFoundException;
025    import java.io.IOException;
026    import java.io.InputStreamReader;
027    import java.io.UnsupportedEncodingException;
028    import java.util.ArrayList;
029    
030    import sears.file.exception.io.FileConversionException;
031    
032    /**
033     * This class must be implemented each time a <tt>java.io.File</tt> object will have to be converted to
034     * a <tt>sears.file.SubtitleFile</tt> object
035     * <br>It wrap a <tt>BufferedReader</tt> and gives method to access to it with respect of the Sears constraints
036     */
037    public abstract class FileConversion {
038    
039            protected File file;
040            private BufferedReader reader;
041            protected int lineCount;
042    
043            /**
044             * Constructs a new instance 
045             * @param file          the file to parse
046             * @param charset       the charset used to read the file
047             * @throws NullPointerException if <tt>file</tt> or/and <tt>charset</tt> are null
048             * @throws FileConversionException
049             */
050            public FileConversion(File file, String charset) throws FileConversionException {
051                    if( file == null ) {
052                            throw new NullPointerException("cannot parse a null file");
053                    }               
054                    if( charset == null ) {
055                            throw new NullPointerException("charset could not be null");
056                    }
057                    this.file = file;
058                    initializeReader(charset);
059            }
060            
061            // **************
062            // CORE METHODS *
063            // **************
064            /**
065             * <br>Principal method:
066             * <br>parses <tt>file</tt> and fill the array list given in parameters with founded subtitles informations
067             * <br>If there's no subtitles found, the array list stays as it was before
068             * @param subtitleList                                  the array of subtitles to fill
069             * @throws FileConversionException              if an error occurs during the conversion
070             */
071            public void parse(ArrayList<Subtitle> subtitleList) throws FileConversionException {
072                    // while there's line to read:
073                    String line = "";
074                    while( (line = readLine()) != null ) {
075                            Subtitle subtitle = getSubtitle(line);
076                            if( subtitle != null ) {
077                                    subtitleList.add(subtitle);
078                            } //else line is empty line, loop
079                    }
080                    if( subtitleList.isEmpty() ) {
081                            //throw new EmptySubtitleFileException(file);
082                            throw FileConversionException.getMalformedSubtitleFileException(
083                                            FileConversionException.EMPTY_SUBTITLE_FILE, file);
084                    }
085            }
086            
087            /**
088             * Constructs and returns the <tt>Subtitle</tt> object which represents subtitles information
089             * begin at line given in parameters
090             * <br>This method is used by the non <tt>abstract</tt> {@link #parse(ArrayList)} method
091             * @param line                                          the first line...
092             * @return                                                      the founded subtitle or null if there's no subtitle found
093             * @throws FileConversionException      if an error occurs during the conversion
094             */
095            protected abstract Subtitle getSubtitle(String line) throws FileConversionException;
096    
097            
098            // ***********************
099            // READER ACCESS METHODS *
100            // ***********************
101            /**
102             * Initializes the reader with the <tt>charset</tt> given in parameters
103             * @param charset                                       if null there's no guarantee to the coherence of this method
104             * @throws FileConversionException      if an error occurs during the initialisation
105             */
106            private void initializeReader(String charset) throws FileConversionException {
107                    try {
108                            lineCount = 0;
109                            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
110                    } catch ( UnsupportedEncodingException e ) {
111                            // fsa.unsupportedEncoding(file, charset);
112                            e.printStackTrace();
113                    } catch ( FileNotFoundException e) {
114                            throw FileConversionException.getAccessException(
115                                            FileConversionException.READ_ACCESS, file);
116                    }
117            }
118            
119            /**
120             * Reads and returns the next line in the buffer and increment the line count
121             * @return                                                      the next line or null if there's no more line to read
122             * @throws FileConversionException      if a basic <tt>IOException</tt> occurs when 
123             *                                                                      attempts to read in the buffer
124             */
125            protected String readLine() throws FileConversionException {
126                    String line = null;
127                    lineCount++;
128                    try {
129                            line = reader.readLine();
130                    } catch (IOException e) {
131                            throw FileConversionException.getAccessException(
132                                            FileConversionException.READ_ACCESS, file);
133                    }
134                    return line;
135            }
136            
137            /**
138             * Place the 'read head' on the next non empty line and returns it
139             * @return the next non empty line or null if there's no more line to read
140             */
141            protected String getTheNextNonEmptyLine() throws FileConversionException {
142                    String str = null;
143                    try {
144                            str = readLine();
145                            while( str != null && str.equals("") ){
146                                    str = readLine();
147                            }
148                    } catch (IOException e) {
149                            throw FileConversionException.getAccessException(
150                                            FileConversionException.READ_ACCESS, file);
151                    }
152                    return str;
153            }
154            
155            /**
156             * Closes the reader and reset line count
157             * @throws FileConversionException      if a basic <tt>IOException</tt> occurs when 
158             *                                                                      attempts to close the the buffer reader
159             */
160            protected void closeReader() throws FileConversionException {
161                    if( reader != null ) {
162                            try {
163                                    reader.close();
164                                    lineCount = 0;
165                            } catch (IOException e) {
166                                    // try to inform that error occurs when closed the file
167                                    //throw new ReadAccessException(file);
168                                    throw FileConversionException.getAccessException(
169                                                    FileConversionException.READ_ACCESS, file);
170                            }
171                    }
172            }
173    
174            // ***************
175            // UTILS METHODS *
176            // ***************
177            /**
178             * Tests the validity of <tt>str</tt>
179             * return       true if <tt>str</tt> is not null and if it is not an empty <tt>String</tt>, false if not
180             * @throws IOException 
181             */
182            protected void ensureStringIsValid(String str) throws FileConversionException {
183                    if ( str == null || str.equals("")) {
184                            //throw new MalformedSubtitleFileException(file, lineCount, "");
185                            throw FileConversionException.getMalformedSubtitleFileException(
186                                            FileConversionException.MALFORMED_SUBTITLE_FILE, 
187                                            file, lineCount, "");
188                    }
189            }
190    
191            /**
192             * If <tt>str</tt> length is more than 100 characters, <tt>str</tt> is cut and returned
193             * @param str   the string to cut
194             * @return              <tt>str</str> or a sub string of this array
195             */
196            protected static String subString(String str) {
197                    if( str.length() > 100 ) {
198                            str = str.substring(0, 100);
199                    }
200                    return str;
201            }
202    }