// "parent" is the AbstractID3-derived instance making use of this frame. public void write(final RandomAccessFile file, AbstractID3 parent) throws IOException { final String str; final Iterator<?> iterator; final byte[] buffer = new byte[6]; final MP3File mp3 = new MP3File(); mp3.seekMP3Frame(file); final long mp3start = file.getFilePointer(); file.seek(0); ID3v2_3Frame frame; str = "ID3"; for (int i = 0; i < str.length(); i++) { buffer[i] = (byte) str.charAt(i); } buffer[3] = 3; buffer[4] = 0; if (this.unsynchronization) { buffer[5] |= TagConstant.MASK_V23_UNSYNCHRONIZATION; } if (this.extended) { buffer[5] |= TagConstant.MASK_V23_EXTENDED_HEADER; } if (this.experimental) { buffer[5] |= TagConstant.MASK_V23_EXPERIMENTAL; } file.write(buffer); // write size file.write(sizeToByteArray((int) mp3start - 10)); if (this.extended) { if (this.crcDataFlag) { file.writeInt(10); buffer[0] = 0; buffer[0] |= TagConstant.MASK_V23_CRC_DATA_PRESENT; file.write(buffer, 0, 2); file.writeInt(this.paddingSize); file.writeInt(this.crcData); } else { file.writeInt(6); file.write(buffer, 0, 2); file.writeInt(this.paddingSize); } } // write all frames iterator = this.getFrameIterator(); while (iterator.hasNext()) { frame = (ID3v2_3Frame) iterator.next(); frame.write(file, parent); } }
public void read(final RandomAccessFile file) throws TagException, IOException { final int size; final byte[] buffer = new byte[4]; if (seek(file) == false) { throw new TagNotFoundException(getIdentifier() + " tag not found"); } // read the major and minor @version number & flags byte file.read(buffer, 0, 3); if ((buffer[0] != 3) || (buffer[1] != 0)) { throw new TagNotFoundException(getIdentifier() + " tag not found"); } setMajorVersion(buffer[0]); setRevision(buffer[1]); this.unsynchronization = (buffer[2] & TagConstant.MASK_V23_UNSYNCHRONIZATION) != 0; this.extended = (buffer[2] & TagConstant.MASK_V23_EXTENDED_HEADER) != 0; this.experimental = (buffer[2] & TagConstant.MASK_V23_EXPERIMENTAL) != 0; // read the size file.read(buffer, 0, 4); size = byteArrayToSize(buffer); final long filePointer = file.getFilePointer(); if (this.extended) { // int is 4 bytes. final int extendedHeaderSize = file.readInt(); // the extended header is only 6 or 10 bytes. if (extendedHeaderSize != 6 && extendedHeaderSize != 10) { throw new InvalidTagException("Invalid Extended Header Size."); } file.read(buffer, 0, 2); this.crcDataFlag = (buffer[0] & TagConstant.MASK_V23_CRC_DATA_PRESENT) != 0; // if it's 10 bytes, the CRC flag must be set // and if it's 6 bytes, it must not be set if (((extendedHeaderSize == 10) && (this.crcDataFlag == false)) || ((extendedHeaderSize == 6) && (this.crcDataFlag == true))) { throw new InvalidTagException("CRC Data flag not set correctly."); } this.paddingSize = file.readInt(); if ((extendedHeaderSize == 10) && this.crcDataFlag) { this.crcData = file.readInt(); } } ID3v2_3Frame next; this.clearFrameMap(); // read all the frames. this.setFileReadBytes(size); AbstractID3v2.resetPaddingCounter(); while ((file.getFilePointer() - filePointer) <= size) { try { next = new ID3v2_3Frame(file, this); final TagIdentifier id = next.getIdentifier(); if (this.hasFrame(id)) { this.appendDuplicateFrameId(id + "; "); this.incrementDuplicateBytes(this.getFrame(id).getSize()); } this.setFrame(next); } catch (InvalidTagException ex) { if (ex.getMessage().equals("Found empty frame")) { this.incrementEmptyFrameBytes(10); } else { this.incrementInvalidFrameBytes(); } } } this.setPaddingSize(getPaddingCounter()); }