Coverage Report - org.jaudiotagger.tag.id3.ID3v11Tag
 
Classes in this File Line Coverage Branch Coverage Complexity
ID3v11Tag
64%
138/215
62%
57/92
0
 
 1  
 /**
 2  
  *  @author : Paul Taylor
 3  
  *  @author : Eric Farng
 4  
  *
 5  
  *  Version @version:$Id: ID3v11Tag.java,v 1.25 2008/07/24 13:47:06 paultaylor Exp $
 6  
  *
 7  
  *  MusicTag Copyright (C)2003,2004
 8  
  *
 9  
  *  This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
 10  
  *  General Public  License as published by the Free Software Foundation; either version 2.1 of the License,
 11  
  *  or (at your option) any later version.
 12  
  *
 13  
  *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 14  
  *  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 15  
  *  See the GNU Lesser General Public License for more details.
 16  
  *
 17  
  *  You should have received a copy of the GNU Lesser General Public License along with this library; if not,
 18  
  *  you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software
 19  
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 20  
  *
 21  
  * Description:
 22  
  * This class is for a ID3v1.1 Tag
 23  
  *
 24  
  */
 25  
 package org.jaudiotagger.tag.id3;
 26  
 
 27  
 import org.jaudiotagger.audio.generic.Utils;
 28  
 import org.jaudiotagger.audio.mp3.MP3File;
 29  
 import org.jaudiotagger.logging.ErrorMessage;
 30  
 import org.jaudiotagger.tag.*;
 31  
 import org.jaudiotagger.tag.id3.framebody.*;
 32  
 
 33  
 import java.io.IOException;
 34  
 import java.io.RandomAccessFile;
 35  
 import java.nio.ByteBuffer;
 36  
 import java.nio.channels.FileChannel;
 37  
 import java.util.ArrayList;
 38  
 import java.util.Arrays;
 39  
 import java.util.Iterator;
 40  
 import java.util.List;
 41  
 import java.util.logging.Level;
 42  
 import java.util.regex.Matcher;
 43  
 
 44  
 /**
 45  
  * Represents an ID3v11 tag.
 46  
  *
 47  
  * @author : Eric Farng
 48  
  * @author : Paul Taylor
 49  
  */
 50  
 public class ID3v11Tag extends ID3v1Tag
 51  
 {
 52  
 
 53  
     //For writing output
 54  
     protected static final String TYPE_TRACK = "track";
 55  
 
 56  
     protected static final int TRACK_UNDEFINED = 0;
 57  
     protected static final int TRACK_MAX_VALUE = 255;
 58  
     protected static final int TRACK_MIN_VALUE = 1;
 59  
 
 60  
     protected static final int FIELD_COMMENT_LENGTH = 28;
 61  
     protected static final int FIELD_COMMENT_POS = 97;
 62  
 
 63  
     protected static final int FIELD_TRACK_INDICATOR_LENGTH = 1;
 64  
     protected static final int FIELD_TRACK_INDICATOR_POS = 125;
 65  
 
 66  
     protected static final int FIELD_TRACK_LENGTH = 1;
 67  
     protected static final int FIELD_TRACK_POS = 126;
 68  
 
 69  
     /**
 70  
      * Track is held as a single byte in v1.1
 71  
      */
 72  453
     protected byte track = (byte) TRACK_UNDEFINED;
 73  
 
 74  
     private static final byte RELEASE = 1;
 75  
     private static final byte MAJOR_VERSION = 1;
 76  
     private static final byte REVISION = 0;
 77  
 
 78  
     /**
 79  
      * Retrieve the Release
 80  
      */
 81  
     public byte getRelease()
 82  
     {
 83  4
         return RELEASE;
 84  
     }
 85  
 
 86  
     /**
 87  
      * Retrieve the Major Version
 88  
      */
 89  
     public byte getMajorVersion()
 90  
     {
 91  4
         return MAJOR_VERSION;
 92  
     }
 93  
 
 94  
     /**
 95  
      * Retrieve the Revision
 96  
      */
 97  
     public byte getRevision()
 98  
     {
 99  4
         return REVISION;
 100  
     }
 101  
 
 102  
     /**
 103  
      * Creates a new ID3v11 datatype.
 104  
      */
 105  
     public ID3v11Tag()
 106  10
     {
 107  
 
 108  10
     }
 109  
 
 110  
     public int getFieldCount()
 111  
     {
 112  0
         return 7;
 113  
     }
 114  
 
 115  
     public ID3v11Tag(ID3v11Tag copyObject)
 116  
     {
 117  0
         super(copyObject);
 118  0
         this.track = copyObject.track;
 119  0
     }
 120  
 
 121  
     /**
 122  
      * Creates a new ID3v11 datatype from a non v11 tag
 123  
      *
 124  
      * @param mp3tag
 125  
      * @throws UnsupportedOperationException
 126  
      */
 127  
     public ID3v11Tag(AbstractTag mp3tag)
 128  6
     {
 129  6
         if (mp3tag != null)
 130  
         {
 131  6
             if (mp3tag instanceof ID3v1Tag)
 132  
             {
 133  0
                 if (mp3tag instanceof ID3v11Tag)
 134  
                 {
 135  0
                     throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument");
 136  
                 }
 137  0
                 if (mp3tag instanceof ID3v1Tag)
 138  
                 {
 139  
                     // id3v1_1 objects are also id3v1 objects
 140  0
                     ID3v1Tag id3old = (ID3v1Tag) mp3tag;
 141  0
                     this.title = new String(id3old.title);
 142  0
                     this.artist = new String(id3old.artist);
 143  0
                     this.album = new String(id3old.album);
 144  0
                     this.comment = new String(id3old.comment);
 145  0
                     this.year = new String(id3old.year);
 146  0
                     this.genre = id3old.genre;
 147  0
                 }
 148  
             }
 149  
             else
 150  
             {
 151  
                 ID3v24Tag id3tag;
 152  
                 // first change the tag to ID3v2_4 tag if not one already
 153  6
                 if (!(mp3tag instanceof ID3v24Tag))
 154  
                 {
 155  4
                     id3tag = new ID3v24Tag(mp3tag);
 156  
                 }
 157  
                 else
 158  
                 {
 159  2
                     id3tag = (ID3v24Tag) mp3tag;
 160  
                 }
 161  
                 ID3v24Frame frame;
 162  
                 String text;
 163  6
                 if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_TITLE))
 164  
                 {
 165  0
                     frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_TITLE);
 166  0
                     text = ((FrameBodyTIT2) frame.getBody()).getText();
 167  0
                     this.title = ID3Tags.truncate(text, FIELD_TITLE_LENGTH);
 168  
                 }
 169  6
                 if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_ARTIST))
 170  
                 {
 171  0
                     frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_ARTIST);
 172  0
                     text = ((FrameBodyTPE1) frame.getBody()).getText();
 173  0
                     this.artist = ID3Tags.truncate(text, FIELD_ARTIST_LENGTH);
 174  
                 }
 175  6
                 if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_ALBUM))
 176  
                 {
 177  0
                     frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_ALBUM);
 178  0
                     text = ((FrameBodyTALB) frame.getBody()).getText();
 179  0
                     this.album = ID3Tags.truncate(text, FIELD_ALBUM_LENGTH);
 180  
                 }
 181  6
                 if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_YEAR))
 182  
                 {
 183  0
                     frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_YEAR);
 184  0
                     text = ((FrameBodyTDRC) frame.getBody()).getText();
 185  0
                     this.year = ID3Tags.truncate(text, FIELD_YEAR_LENGTH);
 186  
                 }
 187  
 
 188  6
                 if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_COMMENT))
 189  
                 {
 190  0
                     Iterator iterator = id3tag.getFrameOfType(ID3v24Frames.FRAME_ID_COMMENT);
 191  0
                     text = "";
 192  0
                     while (iterator.hasNext())
 193  
                     {
 194  0
                         frame = (ID3v24Frame) iterator.next();
 195  0
                         text += (((FrameBodyCOMM) frame.getBody()).getText() + " ");
 196  
                     }
 197  0
                     this.comment = ID3Tags.truncate(text, FIELD_COMMENT_LENGTH);
 198  
                 }
 199  6
                 if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_GENRE))
 200  
                 {
 201  0
                     frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_GENRE);
 202  0
                     text = ((FrameBodyTCON) frame.getBody()).getText();
 203  
                     try
 204  
                     {
 205  0
                         this.genre = (byte) ID3Tags.findNumber(text);
 206  
                     }
 207  0
                     catch (TagException ex)
 208  
                     {
 209  0
                         logger.log(Level.WARNING, getLoggingFilename() + ":" + "Unable to convert TCON frame to format suitable for v11 tag", ex);
 210  0
                         this.genre = (byte) ID3v1Tag.GENRE_UNDEFINED;
 211  0
                     }
 212  
                 }
 213  6
                 if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_TRACK))
 214  
                 {
 215  0
                     frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_TRACK);
 216  0
                     text = ((FrameBodyTRCK) frame.getBody()).getText();
 217  
                     try
 218  
                     {
 219  0
                         this.track = (byte) ID3Tags.findNumber(text);
 220  
                     }
 221  0
                     catch (TagException ex)
 222  
                     {
 223  0
                         logger.log(Level.WARNING, getLoggingFilename() + ":" + "Unable to convert TRCK frame to format suitable for v11 tag", ex);
 224  0
                         this.track = (byte) TRACK_UNDEFINED;
 225  0
                     }
 226  
                 }
 227  
             }
 228  
         }
 229  6
     }
 230  
 
 231  
     /**
 232  
      * Creates a new ID3v1_1 datatype.
 233  
      *
 234  
      * @param file
 235  
      * @param loggingFilename
 236  
      * @throws TagNotFoundException
 237  
      * @throws IOException
 238  
      */
 239  
     public ID3v11Tag(RandomAccessFile file, String loggingFilename) throws TagNotFoundException, IOException
 240  437
     {
 241  437
         setLoggingFilename(loggingFilename);
 242  
         FileChannel fc;
 243  437
         ByteBuffer byteBuffer = ByteBuffer.allocate(TAG_LENGTH);
 244  
 
 245  437
         fc = file.getChannel();
 246  437
         fc.position(file.length() - TAG_LENGTH);
 247  437
         byteBuffer = ByteBuffer.allocate(TAG_LENGTH);
 248  437
         fc.read(byteBuffer);
 249  437
         byteBuffer.flip();
 250  437
         read(byteBuffer);
 251  
 
 252  11
     }
 253  
 
 254  
     /**
 255  
      * Creates a new ID3v1_1 datatype.
 256  
      *
 257  
      * @param file
 258  
      * @throws TagNotFoundException
 259  
      * @throws IOException
 260  
      * @deprecated use {@link #ID3v11Tag(RandomAccessFile,String)} instead
 261  
      */
 262  
     public ID3v11Tag(RandomAccessFile file) throws TagNotFoundException, IOException
 263  
     {
 264  0
         this(file, "");
 265  
 
 266  0
     }
 267  
 
 268  
     /**
 269  
      * Set Comment
 270  
      *
 271  
      * @param comment
 272  
      */
 273  
     public void setComment(String comment)
 274  
     {
 275  9
         if (comment == null)
 276  
         {
 277  1
             throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
 278  
         }
 279  8
         this.comment = ID3Tags.truncate(comment, this.FIELD_COMMENT_LENGTH);
 280  8
     }
 281  
 
 282  
     /**
 283  
      * Get Comment
 284  
      *
 285  
      * @return comment
 286  
      */
 287  
     public String getFirstComment()
 288  
     {
 289  12
         return comment;
 290  
     }
 291  
 
 292  
     /**
 293  
      * Set the track, v11 stores track numbers in a single byte value so can only
 294  
      * handle a simple number in the range 0-255.
 295  
      *
 296  
      * @param trackValue
 297  
      */
 298  
     @Override
 299  
     public void setTrack(String trackValue)
 300  
     {
 301  
         int trackAsInt;
 302  
         //Try and convert String representation of track into an integer
 303  
         try
 304  
         {
 305  7
             trackAsInt = Integer.parseInt(trackValue);
 306  
         }
 307  0
         catch (NumberFormatException e)
 308  
         {
 309  0
             trackAsInt = 0;
 310  7
         }
 311  
 
 312  
         //This value cannot be held in v1_1
 313  7
         if ((trackAsInt > TRACK_MAX_VALUE) || (trackAsInt < TRACK_MIN_VALUE))
 314  
         {
 315  0
             this.track = (byte) TRACK_UNDEFINED;
 316  
         }
 317  
         else
 318  
         {
 319  7
             this.track = (byte) Integer.parseInt(trackValue);
 320  
         }
 321  7
     }
 322  
 
 323  
     /**
 324  
      * Return the track number as a String.
 325  
      *
 326  
      * @return track
 327  
      */
 328  
     @Override
 329  
     public String getFirstTrack()
 330  
     {
 331  12
         return String.valueOf(track & BYTE_TO_UNSIGNED);
 332  
     }
 333  
 
 334  
     @Override
 335  
     public void addTrack(String track)
 336  
     {
 337  0
         setTrack(track);
 338  0
     }
 339  
 
 340  
     @Override
 341  
     public List<TagField> getTrack()
 342  
     {
 343  4
         if (getFirstTrack().length() > 0)
 344  
         {
 345  4
             ID3v1TagField field = new ID3v1TagField(ID3v1FieldKey.TRACK.name(), getFirstTrack());
 346  4
             return returnFieldToList(field);
 347  
         }
 348  
         else
 349  
         {
 350  0
             return new ArrayList<TagField>();
 351  
         }
 352  
     }
 353  
 
 354  
     public void set(TagField field)
 355  
     {
 356  11
         TagFieldKey genericKey = TagFieldKey.valueOf(field.getId());
 357  11
         if (genericKey == TagFieldKey.TRACK)
 358  
         {
 359  2
             setTrack(field.toString());
 360  
         }
 361  
         else
 362  
         {
 363  9
             super.set(field);
 364  
         }
 365  10
     }
 366  
 
 367  
     public List<TagField> get(TagFieldKey genericKey)
 368  
     {
 369  7
         if (genericKey == TagFieldKey.TRACK)
 370  
         {
 371  1
             return getTrack();
 372  
         }
 373  
         else
 374  
         {
 375  6
             return super.get(genericKey);
 376  
         }
 377  
     }
 378  
 
 379  
     public TagField getFirstField(String id)
 380  
     {
 381  7
         List<TagField> results = null;
 382  
 
 383  7
         if (TagFieldKey.TRACK.name().equals(id))
 384  
         {
 385  1
             results = getTrack();
 386  1
             if (results != null)
 387  
             {
 388  1
                 if (results.size() > 0)
 389  
                 {
 390  1
                     return results.get(0);
 391  
                 }
 392  
             }
 393  0
             return null;
 394  
         }
 395  
         else
 396  
         {
 397  6
             return super.getFirstField(id);
 398  
         }
 399  
     }
 400  
 
 401  
     public boolean isEmpty()
 402  
     {
 403  3
         if (track > 0)
 404  
         {
 405  1
             return false;
 406  
         }
 407  2
         return super.isEmpty();
 408  
     }
 409  
 
 410  
     /**
 411  
      * Delete any instance of tag fields with this key
 412  
      *
 413  
      * @param genericKey
 414  
      */
 415  
     public void deleteTagField(TagFieldKey genericKey)
 416  
     {
 417  8
         if (genericKey == TagFieldKey.TRACK)
 418  
         {
 419  1
             track = 0;
 420  
         }
 421  
         else
 422  
         {
 423  7
             super.deleteTagField(genericKey);
 424  
         }
 425  8
     }
 426  
 
 427  
     /**
 428  
      * Compares Object with this only returns true if both v1_1 tags with all
 429  
      * fields set to same value
 430  
      *
 431  
      * @param obj Comparing Object
 432  
      * @return
 433  
      */
 434  
     public boolean equals(Object obj)
 435  
     {
 436  0
         if ((obj instanceof ID3v11Tag) == false)
 437  
         {
 438  0
             return false;
 439  
         }
 440  0
         ID3v11Tag object = (ID3v11Tag) obj;
 441  0
         if (this.track != object.track)
 442  
         {
 443  0
             return false;
 444  
         }
 445  0
         return super.equals(obj);
 446  
     }
 447  
 
 448  
 
 449  
     /**
 450  
      * Find identifer within byteBuffer to indicate that a v11 tag exists within the buffer
 451  
      *
 452  
      * @param byteBuffer
 453  
      * @return true if find header for v11 tag within buffer
 454  
      */
 455  
     public boolean seek(ByteBuffer byteBuffer)
 456  
     {
 457  446
         byte[] buffer = new byte[FIELD_TAGID_LENGTH];
 458  
         // read the TAG value
 459  446
         byteBuffer.get(buffer, 0, FIELD_TAGID_LENGTH);
 460  446
         if (!(Arrays.equals(buffer, TAG_ID)))
 461  
         {
 462  364
             return false;
 463  
         }
 464  
 
 465  
         // Check for the empty byte before the TRACK
 466  82
         byteBuffer.position(this.FIELD_TRACK_INDICATOR_POS);
 467  82
         if (byteBuffer.get() != END_OF_FIELD)
 468  
         {
 469  4
             return false;
 470  
         }
 471  
         //Now check for TRACK if the next byte is also null byte then not v1.1
 472  
         //tag, however this means cannot have v1_1 tag with track set to zero/undefined
 473  
         //because on next read will be v1 tag.
 474  78
         if (byteBuffer.get() == END_OF_FIELD)
 475  
         {
 476  66
             return false;
 477  
         }
 478  12
         return true;
 479  
     }
 480  
 
 481  
     /**
 482  
      * Read in a tag from the ByteBuffer
 483  
      *
 484  
      * @param byteBuffer from where to read in a tag
 485  
      * @throws TagNotFoundException if unable to read a tag in the byteBuffer
 486  
      */
 487  
     public void read(ByteBuffer byteBuffer) throws TagNotFoundException
 488  
     {
 489  437
         if (seek(byteBuffer) == false)
 490  
         {
 491  426
             throw new TagNotFoundException("ID3v1 tag not found");
 492  
         }
 493  11
         logger.finer("Reading v1.1 tag");
 494  
 
 495  
         //Do single file read of data to cut down on file reads
 496  11
         byte[] dataBuffer = new byte[TAG_LENGTH];
 497  11
         byteBuffer.position(0);
 498  11
         byteBuffer.get(dataBuffer, 0, TAG_LENGTH);
 499  11
         title = Utils.getString(dataBuffer, FIELD_TITLE_POS, this.FIELD_TITLE_LENGTH, "ISO-8859-1").trim();
 500  11
         Matcher m = endofStringPattern.matcher(title);
 501  11
         if (m.find() == true)
 502  
         {
 503  0
             title = title.substring(0, m.start());
 504  
         }
 505  11
         artist = Utils.getString(dataBuffer, FIELD_ARTIST_POS, this.FIELD_ARTIST_LENGTH, "ISO-8859-1").trim();
 506  11
         m = endofStringPattern.matcher(artist);
 507  11
         if (m.find() == true)
 508  
         {
 509  0
             artist = artist.substring(0, m.start());
 510  
         }
 511  11
         album = Utils.getString(dataBuffer, FIELD_ALBUM_POS, this.FIELD_ALBUM_LENGTH, "ISO-8859-1").trim();
 512  11
         m = endofStringPattern.matcher(album);
 513  11
         if (m.find() == true)
 514  
         {
 515  0
             album = album.substring(0, m.start());
 516  
         }
 517  11
         year = Utils.getString(dataBuffer, FIELD_YEAR_POS, this.FIELD_YEAR_LENGTH, "ISO-8859-1").trim();
 518  11
         m = endofStringPattern.matcher(year);
 519  11
         if (m.find() == true)
 520  
         {
 521  0
             year = year.substring(0, m.start());
 522  
         }
 523  11
         comment = Utils.getString(dataBuffer, FIELD_COMMENT_POS, this.FIELD_COMMENT_LENGTH, "ISO-8859-1").trim();
 524  11
         m = endofStringPattern.matcher(comment);
 525  11
         if (m.find() == true)
 526  
         {
 527  0
             comment = comment.substring(0, m.start());
 528  
         }
 529  11
         track = dataBuffer[FIELD_TRACK_POS];
 530  11
         genre = dataBuffer[FIELD_GENRE_POS];
 531  11
     }
 532  
 
 533  
 
 534  
     /**
 535  
      * Write this representation of tag to the file indicated
 536  
      *
 537  
      * @param file that this tag should be written to
 538  
      * @throws IOException thrown if there were problems writing to the file
 539  
      */
 540  
     public void write(RandomAccessFile file) throws IOException
 541  
     {
 542  9
         logger.info("Saving ID3v11 tag to file");
 543  9
         byte[] buffer = new byte[TAG_LENGTH];
 544  
         int i;
 545  
         String str;
 546  9
         delete(file);
 547  9
         file.seek(file.length());
 548  9
         System.arraycopy(TAG_ID, this.FIELD_TAGID_POS, buffer, this.FIELD_TAGID_POS, TAG_ID.length);
 549  9
         int offset = this.FIELD_TITLE_POS;
 550  9
         if (TagOptionSingleton.getInstance().isId3v1SaveTitle())
 551  
         {
 552  9
             str = ID3Tags.truncate(title, this.FIELD_TITLE_LENGTH);
 553  36
             for (i = 0; i < str.length(); i++)
 554  
             {
 555  27
                 buffer[i + offset] = (byte) str.charAt(i);
 556  
             }
 557  
         }
 558  9
         offset = this.FIELD_ARTIST_POS;
 559  9
         if (TagOptionSingleton.getInstance().isId3v1SaveArtist())
 560  
         {
 561  9
             str = ID3Tags.truncate(artist, this.FIELD_ARTIST_LENGTH);
 562  84
             for (i = 0; i < str.length(); i++)
 563  
             {
 564  75
                 buffer[i + offset] = (byte) str.charAt(i);
 565  
             }
 566  
         }
 567  9
         offset = this.FIELD_ALBUM_POS;
 568  9
         if (TagOptionSingleton.getInstance().isId3v1SaveAlbum())
 569  
         {
 570  9
             str = ID3Tags.truncate(album, this.FIELD_ALBUM_LENGTH);
 571  78
             for (i = 0; i < str.length(); i++)
 572  
             {
 573  69
                 buffer[i + offset] = (byte) str.charAt(i);
 574  
             }
 575  
         }
 576  9
         offset = this.FIELD_YEAR_POS;
 577  9
         if (TagOptionSingleton.getInstance().isId3v1SaveYear())
 578  
         {
 579  9
             str = ID3Tags.truncate(year, this.FIELD_YEAR_LENGTH);
 580  17
             for (i = 0; i < str.length(); i++)
 581  
             {
 582  8
                 buffer[i + offset] = (byte) str.charAt(i);
 583  
             }
 584  
         }
 585  9
         offset = this.FIELD_COMMENT_POS;
 586  9
         if (TagOptionSingleton.getInstance().isId3v1SaveComment())
 587  
         {
 588  9
             str = ID3Tags.truncate(comment, this.FIELD_COMMENT_LENGTH);
 589  16
             for (i = 0; i < str.length(); i++)
 590  
             {
 591  7
                 buffer[i + offset] = (byte) str.charAt(i);
 592  
             }
 593  
         }
 594  9
         offset = this.FIELD_TRACK_POS;
 595  9
         buffer[offset] = track; // skip one byte extra blank for 1.1 definition
 596  9
         offset = this.FIELD_GENRE_POS;
 597  9
         if (TagOptionSingleton.getInstance().isId3v1SaveGenre())
 598  
         {
 599  9
             buffer[offset] = genre;
 600  
         }
 601  9
         file.write(buffer);
 602  
 
 603  9
         logger.info("Saved ID3v11 tag to file");
 604  9
     }
 605  
 
 606  
 
 607  
     public void createStructure()
 608  
     {
 609  0
         MP3File.getStructureFormatter().openHeadingElement(TYPE_TAG, getIdentifier());
 610  
         //Header
 611  0
         MP3File.getStructureFormatter().addElement(TYPE_TITLE, this.title);
 612  0
         MP3File.getStructureFormatter().addElement(TYPE_ARTIST, this.artist);
 613  0
         MP3File.getStructureFormatter().addElement(TYPE_ALBUM, this.album);
 614  0
         MP3File.getStructureFormatter().addElement(TYPE_YEAR, this.year);
 615  0
         MP3File.getStructureFormatter().addElement(TYPE_COMMENT, this.comment);
 616  0
         MP3File.getStructureFormatter().addElement(TYPE_TRACK, this.track);
 617  0
         MP3File.getStructureFormatter().addElement(TYPE_GENRE, this.genre);
 618  0
         MP3File.getStructureFormatter().closeHeadingElement(TYPE_TAG);
 619  
 
 620  0
     }
 621  
 }