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 * Abstract class for an entry in the iRiver database. 026 * 027 * @author Richard Körber <dev@shredzone.de> 028 * @version $Id: Entry.java 291 2009-04-28 21:29:27Z shred $ 029 */ 030 public abstract class Entry implements Serializable, Comparable<Entry> { 031 private static final long serialVersionUID = -2272263266038018131L; 032 033 /** 034 * Get the file behind this entry. Returns null if there is no matching 035 * file in the file system. 036 * 037 * @return File represented by this entry 038 */ 039 public File getFile() { 040 return null; 041 } 042 043 /** 044 * Get the file name of this entry. This is the path and file name 045 * relative to the iHP root directory mount point, and always 046 * using wrongslashes (even on unixoid systems). 047 * 048 * @return File name 049 */ 050 public abstract String getFileName(); 051 052 /** 053 * Get the title of the track, as given by the file's tag. Does not 054 * return null. 055 * 056 * @return Title 057 */ 058 public abstract String getTitle(); 059 060 /** 061 * Get the artist of the track, as given by the file's tag. Does not 062 * return null. 063 * 064 * @return Artist 065 */ 066 public abstract String getArtist(); 067 068 /** 069 * Get the album of the track, as given by the file's tag. Does not 070 * return null. 071 * 072 * @return Album 073 */ 074 public abstract String getAlbum(); 075 076 /** 077 * Get the genre of the track, as given by the file's tag. This is 078 * always a word, not a number. Does not return null. 079 * 080 * @return Genre 081 */ 082 public abstract String getGenre(); 083 084 /** 085 * Get the byte size of this entry when saved to the database 086 * 087 * @param charset Charset the iRivNavi.db shall be written in 088 * @return Size 089 * @throws UnsupportedEncodingException 090 */ 091 public int size( String charset ) 092 throws UnsupportedEncodingException { 093 int size = 10; // 5x 2 byte length 094 size += getBytesTerm( getFileName(), charset ).length; 095 size += getBytesTerm( getTitle(), charset ).length; 096 size += getBytesTerm( getArtist(), charset ).length; 097 size += getBytesTerm( getAlbum(), charset ).length; 098 size += getBytesTerm( getGenre(), charset ).length; 099 return size; 100 } 101 102 /** 103 * Write the entry to an OutputStream in iRivDB format. 104 * 105 * @param out OutputStream to write to 106 * @param charset Charset the iRivNavi.db shall be written in 107 * @throws IOException, UnsupportedEncodingException 108 */ 109 public void write( OutputStream out, String charset ) 110 throws IOException, UnsupportedEncodingException { 111 //--- Get the strings --- 112 final byte[] bFileName = getBytesTerm( getFileName(), charset ); 113 final byte[] bTitle = getBytesTerm( getTitle(), charset ); 114 final byte[] bArtist = getBytesTerm( getArtist(), charset ); 115 final byte[] bAlbum = getBytesTerm( getAlbum(), charset ); 116 final byte[] bGenre = getBytesTerm( getGenre(), charset ); 117 118 //--- Write the string lengths --- 119 writeShort( out, bFileName.length ); 120 writeShort( out, bTitle.length ); 121 writeShort( out, bArtist.length ); 122 writeShort( out, bAlbum.length ); 123 writeShort( out, bGenre.length ); 124 125 //--- Write the strings itself --- 126 out.write( bFileName ); // they are already 0 terminated 127 out.write( bTitle ); 128 out.write( bArtist ); 129 out.write( bAlbum ); 130 out.write( bGenre ); 131 } 132 133 /** 134 * Get a byte array of a string, using the given charset. The byte 135 * array will be properly null terminated. 136 * 137 * @param str String to convert 138 * @param charset Charset to be used 139 * @return A byte array of the string, null terminated. 140 */ 141 protected byte[] getBytesTerm( String str, String charset ) 142 throws UnsupportedEncodingException { 143 if( charset.equals("UTF-16") ) { 144 final byte[] data = (str+'\0').getBytes( "UTF-16LE" ); 145 final byte[] rv = new byte[ data.length+2 ]; 146 rv[0] = (byte) 0xFF; // Marker: Little Endian 147 rv[1] = (byte) 0xFE; // The Jukebox is unable to handle big endian! 148 System.arraycopy( data, 0, rv, 2, data.length ); 149 return rv; 150 }else { 151 return (str+'\0').getBytes( charset ); 152 } 153 } 154 155 /** 156 * Write out a short value (16 bit) in little endian order. 157 * 158 * @param out OutputStream to write to 159 * @param val Value 160 */ 161 private void writeShort( OutputStream out, int val ) 162 throws IOException { 163 out.write( (val ) & 0xFF ); 164 out.write( (val>>8) & 0xFF ); 165 } 166 167 /** 168 * Compare one Entry to another. 169 * 170 * @param o Other Entry to compare this entry to 171 * @return positive, 0 or negative value according to the result 172 */ 173 @Override 174 public int compareTo( Entry o ) { 175 return getFileName().compareToIgnoreCase( o.getFileName() ); 176 } 177 178 /** 179 * Check if this Entry is equal to another object. An Entry is never 180 * equal to null or foreign objects. Two Entry are considered equal 181 * if they have the same file name. 182 * 183 * @param o Object to compare with 184 * @return true: same, false: different 185 */ 186 @Override 187 public boolean equals( Object o ) { 188 if( o==null || !(o instanceof Entry) ) 189 return false; 190 Entry e2 = (Entry) o; 191 return getFileName().equalsIgnoreCase( e2.getFileName() ); 192 } 193 194 /** 195 * Return a hash code for this Entry. 196 * 197 * @return int Hash Code 198 */ 199 @Override 200 public int hashCode() { 201 return getFileName().hashCode(); 202 } 203 204 } 205