Coverage Report - org.jaudiotagger.audio.generic.Utils
 
Classes in this File Line Coverage Branch Coverage Complexity
Utils
63%
78/123
46%
13/28
2.241
 
 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 org.jaudiotagger.audio.AudioFile;
 22  
 
 23  
 import java.io.*;
 24  
 import java.nio.ByteBuffer;
 25  
 import java.util.logging.Level;
 26  
 import java.util.logging.Logger;
 27  
 
 28  
 /**
 29  
  * Contains various frequently used static functions in the different tag
 30  
  * formats
 31  
  *
 32  
  * @author Raphael Slinckx
 33  
  */
 34  0
 public class Utils
 35  
 {
 36  
 
 37  
      // Logger Object
 38  4
     public static Logger logger = Logger
 39  
             .getLogger("org.jaudiotagger.audio.generic.utils");
 40  
 
 41  
     /**
 42  
      * Copies the bytes of <code>srd</code> to <code>dst</code> at the
 43  
      * specified offset.
 44  
      *
 45  
      * @param src       The byte to be copied.
 46  
      * @param dst       The array to copy to
 47  
      * @param dstOffset The start offset for the bytes to be copied.
 48  
      */
 49  
     public static void copy(byte[] src, byte[] dst, int dstOffset)
 50  
     {
 51  0
         System.arraycopy(src, 0, dst, dstOffset, src.length);
 52  0
     }
 53  
 
 54  
 
 55  
     /**
 56  
      * Returns {@link String#getBytes()}.<br>
 57  
      *
 58  
      * @param s The String to call, decode bytes using the specfied charset
 59  
      * @param charSet
 60  
      * @return The bytes.
 61  
      */
 62  
     public static byte[] getDefaultBytes(String s, String charSet)
 63  
     {
 64  
         try
 65  
         {
 66  15060
             return s.getBytes(charSet);
 67  
         }
 68  0
         catch (UnsupportedEncodingException uee)
 69  
         {
 70  0
             throw new RuntimeException(uee);
 71  
         }
 72  
 
 73  
     }
 74  
 
 75  
     /*
 76  
       * Returns the extension of the given file.
 77  
       * The extension is empty if there is no extension
 78  
       * The extension is the string after the last "."
 79  
       *
 80  
       * @param f The file whose extension is requested
 81  
       * @return The extension of the given file
 82  
       */
 83  
     public static String getExtension(File f)
 84  
     {
 85  2073
         String name = f.getName().toLowerCase();
 86  2073
         int i = name.lastIndexOf(".");
 87  2073
         if (i == -1)
 88  
         {
 89  0
             return "";
 90  
         }
 91  
 
 92  2073
         return name.substring(i + 1);
 93  
     }
 94  
 
 95  
 
 96  
     /*
 97  
     * Computes a number whereby the 1st byte is the least signifcant and the last
 98  
     * byte is the most significant.
 99  
     *
 100  
     * @param b The byte array @param start The starting offset in b
 101  
     * (b[offset]). The less significant byte @param end The end index
 102  
     * (included) in b (b[end]). The most significant byte @return a long number
 103  
     * represented by the byte sequence.
 104  
     *
 105  
     * So if storing a number which only requires one byte it will be stored in the first
 106  
     * byte.
 107  
     */
 108  
     public static long getLongLE(ByteBuffer b, int start, int end)
 109  
     {
 110  57520
         long number = 0;
 111  287436
         for (int i = 0; i < (end - start + 1); i++)
 112  
         {
 113  229916
             number += ((b.get(start + i) & 0xFF) << i * 8);
 114  
         }
 115  
 
 116  57520
         return number;
 117  
     }
 118  
 
 119  
     /*
 120  
      * Computes a number whereby the 1st byte is the most significant and the last
 121  
      * byte is the least significant.
 122  
      *
 123  
      * So if storing a number which only requires one byte it will be stored in the last
 124  
      * byte.
 125  
      */
 126  
     public static long getLongBE(ByteBuffer b, int start, int end)
 127  
     {
 128  107017
         int number = 0;
 129  515045
         for (int i = 0; i < (end - start + 1); i++)
 130  
         {
 131  408028
             number += ((b.get(end - i) & 0xFF) << i * 8);
 132  
         }
 133  
 
 134  107017
         return number;
 135  
     }
 136  
 
 137  
     public static int getIntLE(byte[] b)
 138  
     {
 139  1941
         return (int) getLongLE(ByteBuffer.wrap(b), 0, b.length - 1);
 140  
     }
 141  
 
 142  
     /*
 143  
       * same as above, but returns an int instead of a long @param b The byte
 144  
       * array @param start The starting offset in b (b[offset]). The less
 145  
       * significant byte @param end The end index (included) in b (b[end]). The
 146  
       * most significant byte @return a int number represented by the byte
 147  
       * sequence.
 148  
       */
 149  
     public static int getIntLE(byte[] b, int start, int end)
 150  
     {
 151  55579
         return (int) getLongLE(ByteBuffer.wrap(b), start, end);
 152  
     }
 153  
 
 154  
     public static int getIntBE(byte[] b, int start, int end)
 155  
     {
 156  70848
         return (int) getLongBE(ByteBuffer.wrap(b), start, end);
 157  
     }
 158  
 
 159  
     public static int getIntBE(ByteBuffer b, int start, int end)
 160  
     {
 161  36169
         return (int) getLongBE(b, start, end);
 162  
     }
 163  
 
 164  
     public static short getShortBE(ByteBuffer b, int start, int end)
 165  
     {
 166  1786
         return (short) getIntBE(b, start, end);
 167  
     }
 168  
 
 169  
     /**
 170  
      * Convert int to byte representation - Big Endian (as used by mp4)
 171  
      *
 172  
      * @param size
 173  
      * @return byte represenetation
 174  
      */
 175  
     public static byte[] getSizeBEInt32(int size)
 176  
     {
 177  25475
         byte[] b = new byte[4];
 178  25475
         b[0] = (byte) ((size >> 24) & 0xFF);
 179  25475
         b[1] = (byte) ((size >> 16) & 0xFF);
 180  25475
         b[2] = (byte) ((size >> 8) & 0xFF);
 181  25475
         b[3] = (byte) (size & 0xFF);
 182  25475
         return b;
 183  
     }
 184  
 
 185  
     /**
 186  
      * Convert short to byte representation - Big Endian (as used by mp4)
 187  
      *
 188  
      * @param size
 189  
      * @return byte represenetation
 190  
      */
 191  
     public static byte[] getSizeBEInt16(short size)
 192  
     {
 193  825
         byte[] b = new byte[2];
 194  825
         b[0] = (byte) ((size >> 8) & 0xFF);
 195  825
         b[1] = (byte) (size & 0xFF);
 196  825
         return b;
 197  
     }
 198  
 
 199  
 
 200  
     /**
 201  
      * Convert int to byte representation - Little Endian (as used by ogg vorbis)
 202  
      *
 203  
      * @param size
 204  
      * @return byte represenetation
 205  
      */
 206  
     public static byte[] getSizeLEInt32(int size)
 207  
     {
 208  310
         byte[] b = new byte[4];
 209  310
         b[0] = (byte) (size & 0xff);
 210  310
         b[1] = (byte) ((size >>> 8) & 0xffL);
 211  310
         b[2] = (byte) ((size >>> 16) & 0xffL);
 212  310
         b[3] = (byte) ((size >>> 24) & 0xffL);
 213  310
         return b;
 214  
     }
 215  
 
 216  
     /**
 217  
      * Create String starting from offset upto length using encoding
 218  
      *
 219  
      * @param b
 220  
      * @param offset
 221  
      * @param length
 222  
      * @param encoding
 223  
      * @return
 224  
      * @throws UnsupportedEncodingException
 225  
      */
 226  
     public static String getString(byte[] b, int offset, int length, String encoding)
 227  
     {
 228  
         try
 229  
         {
 230  73040
             return new String(b, offset, length, encoding);
 231  
         }
 232  0
         catch (UnsupportedEncodingException ue)
 233  
         {
 234  
             //Shouldnt have to worry about this exception as should only be calling with well defined charsets
 235  0
             throw new RuntimeException(ue);
 236  
         }
 237  
     }
 238  
 
 239  
     /**
 240  
      * Create String offset from position by offset upto length using encoding, and position of buffer
 241  
      * is moved to after position + offset + length
 242  
      *
 243  
      * @param buffer
 244  
      * @param offset
 245  
      * @param length
 246  
      * @param encoding
 247  
      * @return
 248  
      */
 249  
     public static String getString(ByteBuffer buffer, int offset, int length, String encoding)
 250  
     {
 251  19556
         byte[] b = new byte[length];
 252  19556
         buffer.position(buffer.position() + offset);
 253  19556
         buffer.get(b);
 254  
         try
 255  
         {
 256  19556
             return new String(b, 0, length, encoding);
 257  
         }
 258  0
         catch (UnsupportedEncodingException uee)
 259  
         {
 260  
             //TODO, will we ever use unsupported encodings
 261  0
             throw new RuntimeException(uee);
 262  
         }
 263  
     }
 264  
 
 265  
     /*
 266  
       * Tries to convert a string into an UTF8 array of bytes If the conversion
 267  
       * fails, return the string converted with the default encoding.
 268  
       *
 269  
       * @param s The string to convert @return The byte array representation of
 270  
       * this string in UTF8 encoding
 271  
       */
 272  
     public static byte[] getUTF8Bytes(String s) throws UnsupportedEncodingException
 273  
     {
 274  298
         return s.getBytes("UTF-8");
 275  
     }
 276  
 
 277  
     /**
 278  
      * Overflow checking since java can't handle unsigned numbers.
 279  
      * @param di
 280  
      * @throws java.io.IOException
 281  
      * @return
 282  
      */
 283  
     public static int readUint32AsInt(DataInput di) throws IOException
 284  
     {
 285  448
         final long l = readUint32(di);
 286  448
         if (l > Integer.MAX_VALUE)
 287  
         {
 288  0
             throw new IOException("uint32 value read overflows int");
 289  
         }
 290  448
         return (int) l;
 291  
     }
 292  
 
 293  
     public static long readUint32(DataInput di) throws IOException
 294  
     {
 295  928
         final byte[] buf8 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 296  928
         di.readFully(buf8, 4, 4);
 297  928
         final long l = ByteBuffer.wrap(buf8).getLong();
 298  928
         return l;
 299  
     }
 300  
 
 301  
     public static int readUint16(DataInput di) throws IOException
 302  
     {
 303  420
         final byte[] buf = {0x00, 0x00, 0x00, 0x00};
 304  420
         di.readFully(buf, 2, 2);
 305  420
         final int i = ByteBuffer.wrap(buf).getInt();
 306  420
         return i;
 307  
     }
 308  
 
 309  
     public static String readString(DataInput di, int charsToRead) throws IOException
 310  
     {
 311  628
         final byte[] buf = new byte[charsToRead];
 312  628
         di.readFully(buf);
 313  628
         return new String(buf);
 314  
     }
 315  
 
 316  
     public static long readUInt64(ByteBuffer b)
 317  
     {
 318  0
         long result = 0;
 319  0
         result += (readUBEInt32(b) << 32);
 320  0
         result += readUBEInt32(b);
 321  0
         return result;
 322  
     }
 323  
 
 324  
     public static int readUBEInt32(ByteBuffer b)
 325  
     {
 326  168
         int result = 0;
 327  168
         result += readUBEInt16(b) << 16;
 328  168
         result += readUBEInt16(b);
 329  168
         return result;
 330  
     }
 331  
 
 332  
     public static int readUBEInt24(ByteBuffer b)
 333  
     {
 334  0
         int result = 0;
 335  0
         result += readUBEInt16(b) << 16;
 336  0
         result += readUInt8(b);
 337  0
         return result;
 338  
     }
 339  
 
 340  
     public static int readUBEInt16(ByteBuffer b)
 341  
     {
 342  378
         int result = 0;
 343  378
         result += readUInt8(b) << 8;
 344  378
         result += readUInt8(b);
 345  378
         return result;
 346  
     }
 347  
 
 348  
     public static int readUInt8(ByteBuffer b)
 349  
     {
 350  1008
         return read(b);
 351  
     }
 352  
 
 353  
 
 354  
     public static int read(ByteBuffer b)
 355  
     {
 356  1008
         int result = (b.get() & 0xFF);
 357  1008
         return result;
 358  
     }
 359  
 
 360  
     /**
 361  
      * @param file
 362  
      * @return filename with audioformat seperator stripped of, lengthened to ensure not too small for valid tempfile
 363  
      *         creation.
 364  
      */
 365  
     public static String getMinBaseFilenameAllowedForTempFile(File file)
 366  
     {
 367  581
         String s = AudioFile.getBaseFilename(file);
 368  581
         if (s.length() >= 3)
 369  
         {
 370  580
             return s;
 371  
         }
 372  1
         if (s.length() == 1)
 373  
         {
 374  0
             return s + "000";
 375  
         }
 376  1
         else if (s.length() == 1)
 377  
         {
 378  0
             return s + "00";
 379  
         }
 380  1
         else if (s.length() == 2)
 381  
         {
 382  1
             return s + "0";
 383  
         }
 384  0
         return s;
 385  
     }
 386  
 
 387  
     /**
 388  
      * Rename file, and if normal rename fails, try copy and delete instead
 389  
      *
 390  
      * @param fromFile
 391  
      * @param toFile
 392  
      * @return
 393  
      */
 394  
     public static boolean rename(File fromFile, File toFile)
 395  
     {
 396  690
         logger.log(Level.CONFIG,"Renaming From:"+fromFile.getAbsolutePath() + " to "+toFile.getAbsolutePath());
 397  
 
 398  690
         if(toFile.exists())
 399  
         {
 400  0
             logger.log(Level.SEVERE,"Destination File:"+toFile + " already exists");
 401  0
             return false;
 402  
         }
 403  
 
 404  
         //Rename File
 405  690
         final boolean result = fromFile.renameTo(toFile);
 406  690
         if (!result)
 407  
         {
 408  
             // Might be trying to rename over filesystem, so try copy and delete instead
 409  0
             if (copy(fromFile, toFile))
 410  
             {
 411  0
                 boolean deleteResult=fromFile.delete();
 412  0
                 if(deleteResult)
 413  
                 {
 414  0
                     logger.log(Level.SEVERE,"Unable to delete File:"+fromFile);
 415  0
                     return false;
 416  
                 }
 417  0
                 return true;
 418  
             }
 419  
             else
 420  
             {
 421  0
                 return false;
 422  
             }
 423  
         }
 424  690
         return true;
 425  
     }
 426  
 
 427  
     /**
 428  
      * Copy a File
 429  
      *
 430  
      * @param fromFile The existing File
 431  
      * @param toFile   The new File
 432  
      * @return <code>true</code> if and only if the renaming succeeded;
 433  
      *         <code>false</code> otherwise
 434  
      */
 435  
     public static boolean copy(File fromFile, File toFile)
 436  
     {
 437  
         try
 438  
         {
 439  0
             FileInputStream in = new FileInputStream(fromFile);
 440  0
             FileOutputStream out = new FileOutputStream(toFile);
 441  0
             byte[] buf = new byte[8192];
 442  
 
 443  
             int len;
 444  
 
 445  0
             while ((len = in.read(buf)) > -1)
 446  
             {
 447  0
                 out.write(buf, 0, len);
 448  
             }
 449  
 
 450  0
             in.close();
 451  0
             out.close();
 452  
 
 453  
             // cleanup if files are not the same length
 454  0
             if (fromFile.length() != toFile.length())
 455  
             {
 456  0
                 toFile.delete();
 457  
 
 458  0
                 return false;
 459  
             }
 460  
 
 461  0
             return true;
 462  
         }
 463  0
         catch (IOException e)
 464  
         {
 465  0
             e.printStackTrace();
 466  0
             return false;
 467  
         }
 468  
     }
 469  
 }