001    /**
002     * iFish - An iRiver iHP jukebox database creation tool
003     *
004     * Copyright (C) 2009 Richard "Shred" Körber
005     *   http://ifish.shredzone.org
006     *
007     * This program is free software: you can redistribute it and/or modify
008     * it under the terms of the GNU General Public License as published by
009     * the Free Software Foundation, either version 3 of the License, or
010     * (at your option) any later version.
011     *
012     * This program is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015     * GNU General Public License for more details.
016     *
017     * You should have received a copy of the GNU General Public License
018     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
019     */
020    package net.shredzone.ifish.db;
021    
022    import java.io.*;
023    
024    /**
025     * This class represents an Entry which was read from the database.
026     *
027     * @author    Richard Körber &lt;dev@shredzone.de&gt;
028     * @version   $Id: DbEntry.java 291 2009-04-28 21:29:27Z shred $
029     */
030    public class DbEntry extends Entry implements Serializable {
031      private static final long serialVersionUID = 3832905438092932146L;
032    
033      private final File   base;
034      private final String filename;
035      private final String title;
036      private final String artist;
037      private final String album;
038      private final String genre;
039      
040      /**
041       * Create a new Entry from a file database entry.
042       * 
043       * @param   base        Base directory
044       * @param   in          Input stream within the database file
045       * @param   charset     Charset to be used for decoding
046       */
047      public DbEntry( File base, InputStream in, String charset )
048      throws IOException, UnsupportedEncodingException {
049        this.base = base;
050        int fnl  = readLength( in );
051        int titl = readLength( in );
052        int artl = readLength( in );
053        int albl = readLength( in );
054        int genl = readLength( in );
055        filename = readString( in, fnl , charset );
056        title    = readString( in, titl, charset );
057        artist   = readString( in, artl, charset );
058        album    = readString( in, albl, charset );
059        genre    = readString( in, genl, charset );
060      }
061    
062      /**
063       * Read the length of a string. This is a 16 bit little endian number.
064       *
065       * @param   in        InputStream to be read
066       * @param   charset   Charset the database was written in
067       * @return  length read
068       * @throws  IOException    on errors and EOF
069       */
070      private int readLength( InputStream in ) 
071      throws IOException {
072        byte[] b = new byte[2];
073        if( 2 != in.read(b) )
074          throw new IOException( "EOF" );
075        return ((b[1]&0xFF)<<8) | (b[0]&0xFF);
076      }
077      
078      /**
079       * Read a string of a given length. The string encoding of the local
080       * machine will be used.
081       *
082       * @param   in        InputStream to be read
083       * @param   length    String length, including 0 termination
084       * @param   charset   Charset the string was written in
085       * @return  String
086       * @throws  IOException    on errors and EOF
087       * @throws  UnsupportedEncodingException    Charset not known
088       */
089      private String readString( InputStream in, int length, String charset )
090      throws IOException, UnsupportedEncodingException {
091        if( length<=0 ) return "";
092        byte[] b = new byte[length];
093        if( length != in.read(b) )
094          throw new IOException( "EOF" );
095        
096        String str;
097        if( length>=2 && (b[0]&0xFF)==0xFF && (b[1]&0xFF)==0xFE ) {
098          //--- UTF-16SE encoding ---
099          str = new String( b, 2, length-2, "UTF-16LE" );
100        }else if( length>=2 && (b[0]&0xFF)==0xFE && (b[1]&0xFF)==0xFF ) {
101          //--- UTF-16BE encoding ---
102          str = new String( b, 2, length-2, "UTF-16BE" );
103        }else {
104          //--- Standard encoding ---
105          str = new String( b, 0, length, charset );
106        }
107        
108        //--- Remove null termination ---
109        while( str.length()>0 && str.charAt(str.length()-1)=='\0' )
110          str = str.substring( 0, str.length()-1 );
111        
112        return str;
113      }
114    
115      /**
116       * Get the file behind this entry. Returns null if there is no matching
117       * file in the file system.
118       *
119       * @return    File represented by this entry
120       */
121      @Override
122      public File getFile() {
123        String fname = getFileName();
124        
125        //--- Convert Windows to this platform's notation ---
126        if( File.separatorChar != '\\' ) {
127          fname = fname.replace( '\\', File.separatorChar );
128        }
129        
130        //--- Remove leading slashes ---
131        if( fname.charAt(0)==File.separatorChar)
132          fname = fname.substring(1);
133        
134        //--- Open a File for this file ---
135        return new File( base, fname );
136      }
137    
138      /**
139       * Get the file name of this entry. This is the path and file name
140       * relative to the iHP root directory mount point, and always
141       * using wrongslashes (even on unixoid systems). 
142       *
143       * @return    File name
144       */
145      @Override
146      public String getFileName() {
147        return filename;
148      }
149      
150      /**
151       * Get the title of the track, as given by the file's tag. Does not
152       * return null.
153       *
154       * @return    Title
155       */
156      @Override
157      public String getTitle() {
158        return title;
159      }
160      
161      /**
162       * Get the artist of the track, as given by the file's tag. Does not
163       * return null.
164       *
165       * @return    Artist
166       */
167      @Override
168      public String getArtist() {
169        return artist;
170      }
171      
172      /**
173       * Get the album of the track, as given by the file's tag. Does not
174       * return null.
175       *
176       * @return    Album
177       */
178      @Override
179      public String getAlbum() {
180        return album; 
181      }
182      
183      /**
184       * Get the genre of the track, as given by the file's tag. This is
185       * always a word, not a number. Does not return null.
186       *
187       * @return    Genre
188       */
189      @Override
190      public String getGenre() {
191        return genre; 
192      }
193      
194    }
195