Search in sources :

Example 11 with CannotWriteException

use of org.jaudiotagger.audio.exceptions.CannotWriteException in project MusicDNA by harjot-oberai.

the class Mp4TagWriter method write.

/**
 * Write tag to rafTemp file
 *
 * @param tag     tag data
 * @param raf     current file
 * @param rafTemp temporary file for writing
 * @throws CannotWriteException
 * @throws IOException
 */
public void write(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotWriteException, IOException {
    logger.config("Started writing tag data");
    // Read Channel for reading from old file
    FileChannel fileReadChannel = raf.getChannel();
    // Write channel for writing to new file
    FileChannel fileWriteChannel = rafTemp.getChannel();
    // TODO we shouldn'timer need all these variables, and some are very badly named - used by new and old methods
    int oldIlstSize = 0;
    int relativeIlstposition;
    int startIlstWithinFile;
    int newIlstSize;
    int oldMetaLevelFreeAtomSize;
    int topLevelFreePosition;
    int topLevelFreeSize;
    long endOfMoov = 0;
    // Found top level free atom that comes after moov and before mdat, (also true if no free atom ?)
    boolean topLevelFreeAtomComesBeforeMdatAtomAndAfterMetadata;
    // Found top level free atom that comes between ftyp and moov
    boolean topLevelFreeAtomComesBeforeMdatAndMetadata;
    Mp4BoxHeader topLevelFreeHeader;
    Mp4AtomTree atomTree;
    // Build AtomTree
    try {
        atomTree = new Mp4AtomTree(raf, false);
    } catch (CannotReadException cre) {
        throw new CannotWriteException(cre.getMessage());
    }
    Mp4BoxHeader mdatHeader = atomTree.getBoxHeader(atomTree.getMdatNode());
    // Unable to find audio so no chance of saving any changes
    if (mdatHeader == null) {
        throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_CANNOT_FIND_AUDIO.getMsg());
    }
    // Go through every field constructing the data that will appear starting from ilst box
    ByteBuffer rawIlstData = tc.convert(tag);
    rawIlstData.rewind();
    newIlstSize = rawIlstData.limit();
    // Moov Box header
    Mp4BoxHeader moovHeader = atomTree.getBoxHeader(atomTree.getMoovNode());
    long positionWithinFileAfterFindingMoovHeader = moovHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH;
    endOfMoov = moovHeader.getFilePos() + moovHeader.getLength();
    Mp4StcoBox stco = atomTree.getStco();
    Mp4BoxHeader ilstHeader = atomTree.getBoxHeader(atomTree.getIlstNode());
    Mp4BoxHeader udtaHeader = atomTree.getBoxHeader(atomTree.getUdtaNode());
    Mp4BoxHeader metaHeader = atomTree.getBoxHeader(atomTree.getMetaNode());
    Mp4BoxHeader hdlrMetaHeader = atomTree.getBoxHeader(atomTree.getHdlrWithinMetaNode());
    Mp4BoxHeader tagsHeader = atomTree.getBoxHeader(atomTree.getTagsNode());
    Mp4BoxHeader trakHeader = atomTree.getBoxHeader(atomTree.getTrakNodes().get(0));
    ByteBuffer moovBuffer = atomTree.getMoovBuffer();
    // Udta
    if (udtaHeader != null) {
        // Meta
        if (metaHeader != null) {
            // ilst - record where ilst is,and where it ends
            if (ilstHeader != null) {
                oldIlstSize = ilstHeader.getLength();
                // Relative means relative to moov buffer after moov header
                startIlstWithinFile = (int) ilstHeader.getFilePos();
                relativeIlstposition = (int) (startIlstWithinFile - (moovHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH));
            } else {
                // Place ilst immediately after existing hdlr atom
                if (hdlrMetaHeader != null) {
                    startIlstWithinFile = (int) hdlrMetaHeader.getFilePos() + hdlrMetaHeader.getLength();
                    relativeIlstposition = (int) (startIlstWithinFile - (moovHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH));
                } else // Place ilst after data fields in meta atom
                // TODO Should we create a hdlr atom
                {
                    startIlstWithinFile = (int) metaHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH + Mp4MetaBox.FLAGS_LENGTH;
                    relativeIlstposition = (int) ((startIlstWithinFile) - (moovHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH));
                }
            }
        } else {
            // There no ilst or meta header so we set to position where it would be if it existed
            relativeIlstposition = moovHeader.getLength() - Mp4BoxHeader.HEADER_LENGTH;
            startIlstWithinFile = (int) (moovHeader.getFilePos() + moovHeader.getLength());
        }
    } else // There no udta header so we are going to create a new structure, but we have to be aware that there might be
    // an existing meta box structure in which case we preserve it but with our new structure before it.
    {
        // Create new structure just after the end of the trak atom
        if (metaHeader != null) {
            startIlstWithinFile = (int) trakHeader.getFilePos() + trakHeader.getLength();
            relativeIlstposition = (int) (startIlstWithinFile - (moovHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH));
        } else {
            // There no udta,ilst or meta header so we set to position where it would be if it existed
            relativeIlstposition = moovHeader.getLength() - Mp4BoxHeader.HEADER_LENGTH;
            startIlstWithinFile = (int) (moovHeader.getFilePos() + moovHeader.getLength());
        }
    }
    // Find size of Level-4 Free atom (if any) immediately after ilst atom
    oldMetaLevelFreeAtomSize = getMetaLevelFreeAtomSize(atomTree);
    // Level-1 free atom
    topLevelFreePosition = 0;
    topLevelFreeSize = 0;
    topLevelFreeAtomComesBeforeMdatAtomAndAfterMetadata = true;
    topLevelFreeAtomComesBeforeMdatAndMetadata = false;
    for (DefaultMutableTreeNode freeNode : atomTree.getFreeNodes()) {
        DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) freeNode.getParent();
        if (parentNode.isRoot()) {
            topLevelFreeHeader = ((Mp4BoxHeader) freeNode.getUserObject());
            topLevelFreeSize = topLevelFreeHeader.getLength();
            topLevelFreePosition = (int) topLevelFreeHeader.getFilePos();
            break;
        }
    }
    if (topLevelFreeSize > 0) {
        if (topLevelFreePosition > mdatHeader.getFilePos()) {
            topLevelFreeAtomComesBeforeMdatAtomAndAfterMetadata = false;
        } else if (topLevelFreePosition < moovHeader.getFilePos()) {
            topLevelFreeAtomComesBeforeMdatAtomAndAfterMetadata = false;
            topLevelFreeAtomComesBeforeMdatAndMetadata = true;
        }
    } else {
        topLevelFreePosition = (int) mdatHeader.getFilePos();
    }
    logger.config("Read header successfully ready for writing");
    // create a new file identical to first file but with replaced metadata
    if (oldIlstSize == newIlstSize) {
        logger.config("Writing:Option 1:Same Size");
        writeMetadataSameSize(rawIlstData, oldIlstSize, startIlstWithinFile, fileReadChannel, fileWriteChannel, tagsHeader);
    } else // no other changes necessary and total file size remains the same
    if (oldIlstSize > newIlstSize) {
        // after ilst as a child of meta
        if (oldMetaLevelFreeAtomSize > 0) {
            logger.config("Writing:Option 2:Smaller Size have free atom:" + oldIlstSize + ":" + newIlstSize);
            writeDataUptoIncludingIlst(fileReadChannel, fileWriteChannel, oldIlstSize, startIlstWithinFile, rawIlstData);
            // Write the modified free atom that comes after ilst
            int newFreeSize = oldMetaLevelFreeAtomSize + (oldIlstSize - newIlstSize);
            Mp4FreeBox newFreeBox = new Mp4FreeBox(newFreeSize - Mp4BoxHeader.HEADER_LENGTH);
            fileWriteChannel.write(newFreeBox.getHeader().getHeaderData());
            fileWriteChannel.write(newFreeBox.getData());
            // Skip over the read channel old free atom
            fileReadChannel.position(fileReadChannel.position() + oldMetaLevelFreeAtomSize);
            writeDataAfterIlst(fileReadChannel, fileWriteChannel, tagsHeader);
        } else // No free atom we need to create a new one or adjust top level free atom
        {
            int newFreeSize = (oldIlstSize - newIlstSize) - Mp4BoxHeader.HEADER_LENGTH;
            // into account size of new header in calculating size of box
            if (newFreeSize > 0) {
                logger.config("Writing:Option 3:Smaller Size can create free atom");
                writeDataUptoIncludingIlst(fileReadChannel, fileWriteChannel, oldIlstSize, startIlstWithinFile, rawIlstData);
                // Create new free box
                Mp4FreeBox newFreeBox = new Mp4FreeBox(newFreeSize);
                fileWriteChannel.write(newFreeBox.getHeader().getHeaderData());
                fileWriteChannel.write(newFreeBox.getData());
                writeDataAfterIlst(fileReadChannel, fileWriteChannel, tagsHeader);
            } else // Ok everything in this bit of tree has to be recalculated because eight or less bytes smaller
            {
                logger.config("Writing:Option 4:Smaller Size <=8 cannot create free atoms");
                // Size will be this amount smaller
                int sizeReducedBy = oldIlstSize - newIlstSize;
                // Write stuff before Moov (ftyp)
                fileReadChannel.position(0);
                fileWriteChannel.transferFrom(fileReadChannel, 0, moovHeader.getFilePos());
                fileWriteChannel.position(moovHeader.getFilePos());
                // unless mdat is at start of file
                if (mdatHeader.getFilePos() > moovHeader.getFilePos()) {
                    stco.adjustOffsets(-sizeReducedBy);
                }
                // Edit and rewrite the Moov,Udta and Meta header in moov buffer
                adjustSizeOfMoovHeader(moovHeader, moovBuffer, -sizeReducedBy, udtaHeader, metaHeader);
                fileWriteChannel.write(moovHeader.getHeaderData());
                moovBuffer.rewind();
                moovBuffer.limit(relativeIlstposition);
                fileWriteChannel.write(moovBuffer);
                // Now write ilst data
                fileWriteChannel.write(rawIlstData);
                fileReadChannel.position(startIlstWithinFile + oldIlstSize);
                writeDataAfterIlst(fileReadChannel, fileWriteChannel, tagsHeader);
            }
        }
    } else // Size of metadata has increased, the most complex situation, more atoms affected
    {
        int additionalSpaceRequiredForMetadata = newIlstSize - oldIlstSize;
        // solution where can fit in data, but cant fit in free atom header
        if (additionalSpaceRequiredForMetadata <= (oldMetaLevelFreeAtomSize - Mp4BoxHeader.HEADER_LENGTH)) {
            int newFreeSize = oldMetaLevelFreeAtomSize - (additionalSpaceRequiredForMetadata);
            logger.config("Writing:Option 5;Larger Size can use meta free atom need extra:" + newFreeSize + "bytes");
            writeDataUptoIncludingIlst(fileReadChannel, fileWriteChannel, oldIlstSize, startIlstWithinFile, rawIlstData);
            // Create an amended smaller freeBaos atom and write it to file
            Mp4FreeBox newFreeBox = new Mp4FreeBox(newFreeSize - Mp4BoxHeader.HEADER_LENGTH);
            fileWriteChannel.write(newFreeBox.getHeader().getHeaderData());
            fileWriteChannel.write(newFreeBox.getData());
            // Skip over the read channel old free atom
            fileReadChannel.position(fileReadChannel.position() + oldMetaLevelFreeAtomSize);
            writeDataAfterIlst(fileReadChannel, fileWriteChannel, tagsHeader);
        } else // There is not enough padding in the metadata free atom anyway
        // Size meta needs to be increased by (if not writing a free atom)
        // Special Case this could actually be negative (upto -8)if is actually enough space but would
        // not be able to write free atom properly, it doesn'timer matter the parent atoms would still
        // need their sizes adjusted.
        {
            int additionalMetaSizeThatWontFitWithinMetaAtom = additionalSpaceRequiredForMetadata - (oldMetaLevelFreeAtomSize);
            // Write stuff before Moov (ftyp)
            fileReadChannel.position(0);
            fileWriteChannel.transferFrom(fileReadChannel, 0, positionWithinFileAfterFindingMoovHeader - Mp4BoxHeader.HEADER_LENGTH);
            fileWriteChannel.position(positionWithinFileAfterFindingMoovHeader - Mp4BoxHeader.HEADER_LENGTH);
            if (udtaHeader == null) {
                logger.config("Writing:Option 5.1;No udta atom");
                Mp4HdlrBox hdlrBox = Mp4HdlrBox.createiTunesStyleHdlrBox();
                Mp4MetaBox metaBox = Mp4MetaBox.createiTunesStyleMetaBox(hdlrBox.getHeader().getLength() + rawIlstData.limit());
                udtaHeader = new Mp4BoxHeader(Mp4AtomIdentifier.UDTA.getFieldName());
                udtaHeader.setLength(Mp4BoxHeader.HEADER_LENGTH + metaBox.getHeader().getLength());
                additionalMetaSizeThatWontFitWithinMetaAtom = additionalMetaSizeThatWontFitWithinMetaAtom + (udtaHeader.getLength() - rawIlstData.limit());
                // or special case of matching exactly the free atom plus header)
                if ((!topLevelFreeAtomComesBeforeMdatAtomAndAfterMetadata) || ((topLevelFreeSize - Mp4BoxHeader.HEADER_LENGTH < additionalMetaSizeThatWontFitWithinMetaAtom) && (topLevelFreeSize != additionalMetaSizeThatWontFitWithinMetaAtom))) {
                    // by the amount mdat is going to be shifted
                    if (mdatHeader.getFilePos() > moovHeader.getFilePos()) {
                        logger.config("Adjusting Offsets");
                        stco.adjustOffsets(additionalMetaSizeThatWontFitWithinMetaAtom);
                    }
                }
                // Edit and rewrite the Moov header
                moovHeader.setLength(moovHeader.getLength() + additionalMetaSizeThatWontFitWithinMetaAtom);
                fileWriteChannel.write(moovHeader.getHeaderData());
                moovBuffer.rewind();
                moovBuffer.limit(relativeIlstposition);
                fileWriteChannel.write(moovBuffer);
                // Write new atoms required for holding metadata in itunes format
                fileWriteChannel.write(udtaHeader.getHeaderData());
                fileWriteChannel.write(metaBox.getHeader().getHeaderData());
                fileWriteChannel.write(metaBox.getData());
                fileWriteChannel.write(hdlrBox.getHeader().getHeaderData());
                fileWriteChannel.write(hdlrBox.getData());
            } else if (metaHeader == null) {
                // #291:In this case we throwaway editing udta header and create a new one, would be beter if we coul
                // keep the info but rather difficult.
                logger.config("Writing:Option 5.2;No meta atom");
                int oldUdtaHeaderLength = udtaHeader.getLength();
                Mp4HdlrBox hdlrBox = Mp4HdlrBox.createiTunesStyleHdlrBox();
                Mp4MetaBox metaBox = Mp4MetaBox.createiTunesStyleMetaBox(hdlrBox.getHeader().getLength() + rawIlstData.limit());
                udtaHeader = new Mp4BoxHeader(Mp4AtomIdentifier.UDTA.getFieldName());
                udtaHeader.setLength(Mp4BoxHeader.HEADER_LENGTH + metaBox.getHeader().getLength());
                additionalMetaSizeThatWontFitWithinMetaAtom = additionalMetaSizeThatWontFitWithinMetaAtom + (udtaHeader.getLength() - rawIlstData.limit());
                // or special case of matching exactly the free atom plus header)
                if ((!topLevelFreeAtomComesBeforeMdatAtomAndAfterMetadata) || ((topLevelFreeSize - Mp4BoxHeader.HEADER_LENGTH < additionalMetaSizeThatWontFitWithinMetaAtom) && (topLevelFreeSize != additionalMetaSizeThatWontFitWithinMetaAtom))) {
                    // by the amount mdat is going to be shifted
                    if (mdatHeader.getFilePos() > moovHeader.getFilePos()) {
                        logger.config("Adjusting Offsets");
                        stco.adjustOffsets(additionalMetaSizeThatWontFitWithinMetaAtom);
                    }
                }
                // Edit and rewrite the Moov header
                moovHeader.setLength(moovHeader.getLength() - oldUdtaHeaderLength + additionalMetaSizeThatWontFitWithinMetaAtom);
                fileWriteChannel.write(moovHeader.getHeaderData());
                moovBuffer.rewind();
                moovBuffer.limit(relativeIlstposition - oldUdtaHeaderLength);
                fileWriteChannel.write(moovBuffer);
                // Write new atoms required for holding metadata in itunes format
                fileWriteChannel.write(udtaHeader.getHeaderData());
                fileWriteChannel.write(metaBox.getHeader().getHeaderData());
                fileWriteChannel.write(metaBox.getData());
                fileWriteChannel.write(hdlrBox.getHeader().getHeaderData());
                fileWriteChannel.write(hdlrBox.getData());
            } else {
                logger.config("Writing:Option 5.3;udta atom exists");
                // or special case of matching exactly the free atom plus header)
                if ((!topLevelFreeAtomComesBeforeMdatAtomAndAfterMetadata) || ((topLevelFreeSize - Mp4BoxHeader.HEADER_LENGTH < additionalMetaSizeThatWontFitWithinMetaAtom) && (topLevelFreeSize != additionalMetaSizeThatWontFitWithinMetaAtom))) {
                    // by the amount mdat is going to be shifted
                    if (mdatHeader.getFilePos() > moovHeader.getFilePos()) {
                        stco.adjustOffsets(additionalMetaSizeThatWontFitWithinMetaAtom);
                    }
                }
                // Edit and rewrite the Moov header
                adjustSizeOfMoovHeader(moovHeader, moovBuffer, additionalMetaSizeThatWontFitWithinMetaAtom, udtaHeader, metaHeader);
                fileWriteChannel.write(moovHeader.getHeaderData());
                // Now write from this edited buffer up until ilst atom
                moovBuffer.rewind();
                moovBuffer.limit(relativeIlstposition);
                fileWriteChannel.write(moovBuffer);
            }
            // Now write ilst data
            fileWriteChannel.write(rawIlstData);
            // Skip over the read channel old meta level free atom because now used up
            fileReadChannel.position(startIlstWithinFile + oldIlstSize);
            fileReadChannel.position(fileReadChannel.position() + oldMetaLevelFreeAtomSize);
            if (tagsHeader != null) {
                // Write from after ilst upto tags atom
                long writeBetweenIlstAndTags = tagsHeader.getFilePos() - fileReadChannel.position();
                fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), writeBetweenIlstAndTags);
                fileWriteChannel.position(fileWriteChannel.position() + writeBetweenIlstAndTags);
                convertandWriteTagsAtomToFreeAtom(fileWriteChannel, tagsHeader);
                // Write after tags atom upto end of moov
                fileReadChannel.position(tagsHeader.getFilePos() + tagsHeader.getLength());
                long extraData = endOfMoov - fileReadChannel.position();
                fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), extraData);
            } else {
                // Now write the rest of children under moov which wont have changed
                long extraData = endOfMoov - fileReadChannel.position();
                fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), extraData);
                fileWriteChannel.position(fileWriteChannel.position() + extraData);
            }
            // the free atom actually come after the the metadata
            if (topLevelFreeAtomComesBeforeMdatAtomAndAfterMetadata && (topLevelFreePosition >= startIlstWithinFile)) {
                // ok
                if (topLevelFreeSize - Mp4BoxHeader.HEADER_LENGTH >= additionalMetaSizeThatWontFitWithinMetaAtom) {
                    logger.config("Writing:Option 6;Larger Size can use top free atom");
                    Mp4FreeBox freeBox = new Mp4FreeBox((topLevelFreeSize - Mp4BoxHeader.HEADER_LENGTH) - additionalMetaSizeThatWontFitWithinMetaAtom);
                    fileWriteChannel.write(freeBox.getHeader().getHeaderData());
                    fileWriteChannel.write(freeBox.getData());
                    // Skip over the read channel old free atom
                    fileReadChannel.position(fileReadChannel.position() + topLevelFreeSize);
                    // Write Mdat
                    writeDataInChunks(fileReadChannel, fileWriteChannel);
                } else // we could just remove the header
                if (topLevelFreeSize == additionalMetaSizeThatWontFitWithinMetaAtom) {
                    logger.config("Writing:Option 7;Larger Size uses top free atom including header");
                    // Skip over the read channel old free atom
                    fileReadChannel.position(fileReadChannel.position() + topLevelFreeSize);
                    // Write Mdat
                    writeDataInChunks(fileReadChannel, fileWriteChannel);
                } else // Mdat is going to have to move anyway, so keep free atom as is and write it and mdat
                // (have already updated stco above)
                {
                    logger.config("Writing:Option 8;Larger Size cannot use top free atom");
                    fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), fileReadChannel.size() - fileReadChannel.position());
                    writeDataInChunks(fileReadChannel, fileWriteChannel);
                }
            } else {
                logger.config("Writing:Option 9;Top Level Free comes after Mdat or before Metadata so cant use it");
                writeDataInChunks(fileReadChannel, fileWriteChannel);
            }
        }
    }
    // Close all channels to original file
    fileReadChannel.close();
    raf.close();
    checkFileWrittenCorrectly(rafTemp, mdatHeader, fileWriteChannel, stco);
}
Also used : CannotWriteException(org.jaudiotagger.audio.exceptions.CannotWriteException) DefaultMutableTreeNode(org.jaudiotagger.utils.tree.DefaultMutableTreeNode) CannotReadException(org.jaudiotagger.audio.exceptions.CannotReadException) FileChannel(java.nio.channels.FileChannel) ByteBuffer(java.nio.ByteBuffer)

Example 12 with CannotWriteException

use of org.jaudiotagger.audio.exceptions.CannotWriteException in project MusicDNA by harjot-oberai.

the class Mp4TagWriter method checkFileWrittenCorrectly.

/**
 * Check File Written Correctly
 *
 * @param rafTemp
 * @param mdatHeader
 * @param fileWriteChannel
 * @param stco
 * @throws CannotWriteException
 * @throws IOException
 */
private void checkFileWrittenCorrectly(RandomAccessFile rafTemp, Mp4BoxHeader mdatHeader, FileChannel fileWriteChannel, Mp4StcoBox stco) throws CannotWriteException, IOException {
    logger.config("Checking file has been written correctly");
    try {
        // Create a tree from the new file
        Mp4AtomTree newAtomTree;
        newAtomTree = new Mp4AtomTree(rafTemp, false);
        // Check we still have audio data file, and check length
        Mp4BoxHeader newMdatHeader = newAtomTree.getBoxHeader(newAtomTree.getMdatNode());
        if (newMdatHeader == null) {
            throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_NO_DATA.getMsg());
        }
        if (newMdatHeader.getLength() != mdatHeader.getLength()) {
            throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_DATA_CORRUPT.getMsg());
        }
        // Should always have udta atom after writing to file
        Mp4BoxHeader newUdtaHeader = newAtomTree.getBoxHeader(newAtomTree.getUdtaNode());
        if (newUdtaHeader == null) {
            throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_NO_TAG_DATA.getMsg());
        }
        // Should always have meta atom after writing to file
        Mp4BoxHeader newMetaHeader = newAtomTree.getBoxHeader(newAtomTree.getMetaNode());
        if (newMetaHeader == null) {
            throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_NO_TAG_DATA.getMsg());
        }
        // Check offsets are correct, may not match exactly in original file so just want to make
        // sure that the discrepancy if any is preserved
        Mp4StcoBox newStco = newAtomTree.getStco();
        logger.finer("stco:Original First Offset" + stco.getFirstOffSet());
        logger.finer("stco:Original Diff" + (int) (stco.getFirstOffSet() - mdatHeader.getFilePos()));
        logger.finer("stco:Original Mdat Pos" + mdatHeader.getFilePos());
        logger.finer("stco:New First Offset" + newStco.getFirstOffSet());
        logger.finer("stco:New Diff" + (int) ((newStco.getFirstOffSet() - newMdatHeader.getFilePos())));
        logger.finer("stco:New Mdat Pos" + newMdatHeader.getFilePos());
        int diff = (int) (stco.getFirstOffSet() - mdatHeader.getFilePos());
        if ((newStco.getFirstOffSet() - newMdatHeader.getFilePos()) != diff) {
            int discrepancy = (int) ((newStco.getFirstOffSet() - newMdatHeader.getFilePos()) - diff);
            throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_INCORRECT_OFFSETS.getMsg(discrepancy));
        }
    } catch (Exception e) {
        if (e instanceof CannotWriteException) {
            throw (CannotWriteException) e;
        } else {
            e.printStackTrace();
            throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED.getMsg() + ":" + e.getMessage());
        }
    } finally {
        // Close references to new file
        rafTemp.close();
        fileWriteChannel.close();
    }
    logger.config("File has been written correctly");
}
Also used : CannotWriteException(org.jaudiotagger.audio.exceptions.CannotWriteException) CannotReadException(org.jaudiotagger.audio.exceptions.CannotReadException) IOException(java.io.IOException) CannotWriteException(org.jaudiotagger.audio.exceptions.CannotWriteException)

Example 13 with CannotWriteException

use of org.jaudiotagger.audio.exceptions.CannotWriteException in project MusicDNA by harjot-oberai.

the class OggVorbisTagWriter method writeRemainingPages.

/**
 * Write all the remaining pages as they are except that the page sequence needs to be modified.
 *
 * @param pageSequence
 * @param raf
 * @param rafTemp
 * @throws IOException
 * @throws CannotReadException
 * @throws CannotWriteException
 */
public void writeRemainingPages(int pageSequence, RandomAccessFile raf, RandomAccessFile rafTemp) throws IOException, CannotReadException, CannotWriteException {
    long startAudio = raf.getFilePointer();
    long startAudioWritten = rafTemp.getFilePointer();
    // TODO there is a risk we wont have enough memory to create these buffers
    ByteBuffer bb = ByteBuffer.allocate((int) (raf.length() - raf.getFilePointer()));
    ByteBuffer bbTemp = ByteBuffer.allocate((int) (raf.length() - raf.getFilePointer()));
    // Read in the rest of the data into bytebuffer and rewind it to start
    raf.getChannel().read(bb);
    bb.rewind();
    while (bb.hasRemaining()) {
        OggPageHeader nextPage = OggPageHeader.read(bb);
        // Create buffer large enough for next page (header and data) and set byte order to LE so we can use
        // putInt method
        ByteBuffer nextPageHeaderBuffer = ByteBuffer.allocate(nextPage.getRawHeaderData().length + nextPage.getPageLength());
        nextPageHeaderBuffer.order(ByteOrder.LITTLE_ENDIAN);
        nextPageHeaderBuffer.put(nextPage.getRawHeaderData());
        ByteBuffer data = bb.slice();
        data.limit(nextPage.getPageLength());
        nextPageHeaderBuffer.put(data);
        nextPageHeaderBuffer.putInt(OggPageHeader.FIELD_PAGE_SEQUENCE_NO_POS, ++pageSequence);
        calculateChecksumOverPage(nextPageHeaderBuffer);
        bb.position(bb.position() + nextPage.getPageLength());
        nextPageHeaderBuffer.rewind();
        bbTemp.put(nextPageHeaderBuffer);
    }
    // Now just write as a single IO operation
    bbTemp.rewind();
    rafTemp.getChannel().write(bbTemp);
    // TODO could we do any other checks to check data written correctly ?
    if ((raf.length() - startAudio) != (rafTemp.length() - startAudioWritten)) {
        throw new CannotWriteException("File written counts don'timer match, file not written");
    }
}
Also used : CannotWriteException(org.jaudiotagger.audio.exceptions.CannotWriteException) ByteBuffer(java.nio.ByteBuffer) OggPageHeader(org.jaudiotagger.audio.ogg.util.OggPageHeader)

Example 14 with CannotWriteException

use of org.jaudiotagger.audio.exceptions.CannotWriteException in project MusicDNA by harjot-oberai.

the class AudioFileWriter method delete.

/**
 * Delete the tag (if any) present in the given file
 *
 * @param af The file to process
 * @throws CannotWriteException if anything went wrong
 * @throws org.jaudiotagger.audio.exceptions.CannotReadException
 */
public void delete(AudioFile af) throws CannotReadException, CannotWriteException {
    if (!af.getFile().canWrite()) {
        throw new CannotWriteException(ErrorMessage.GENERAL_DELETE_FAILED.getMsg(af.getFile().getPath()));
    }
    if (af.getFile().length() <= MINIMUM_FILESIZE) {
        throw new CannotWriteException(ErrorMessage.GENERAL_DELETE_FAILED.getMsg(af.getFile().getPath()));
    }
    RandomAccessFile raf = null;
    RandomAccessFile rafTemp = null;
    File tempF = null;
    // Will be set to true on VetoException, causing the finally block to
    // discard the tempfile.
    boolean revert = false;
    try {
        tempF = File.createTempFile(af.getFile().getName().replace('.', '_'), TEMP_FILENAME_SUFFIX, af.getFile().getParentFile());
        rafTemp = new RandomAccessFile(tempF, WRITE_MODE);
        raf = new RandomAccessFile(af.getFile(), WRITE_MODE);
        raf.seek(0);
        rafTemp.seek(0);
        try {
            if (this.modificationListener != null) {
                this.modificationListener.fileWillBeModified(af, true);
            }
            deleteTag(raf, rafTemp);
            if (this.modificationListener != null) {
                this.modificationListener.fileModified(af, tempF);
            }
        } catch (ModifyVetoException veto) {
            throw new CannotWriteException(veto);
        }
    } catch (Exception e) {
        revert = true;
        throw new CannotWriteException("\"" + af.getFile().getAbsolutePath() + "\" :" + e, e);
    } finally {
        // will be set to the remaining file.
        File result = af.getFile();
        try {
            if (raf != null) {
                raf.close();
            }
            if (rafTemp != null) {
                rafTemp.close();
            }
            if (tempF.length() > 0 && !revert) {
                boolean deleteResult = af.getFile().delete();
                if (!deleteResult) {
                    logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_ORIGINAL_FILE.getMsg(af.getFile().getPath(), tempF.getPath()));
                    throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_ORIGINAL_FILE.getMsg(af.getFile().getPath(), tempF.getPath()));
                }
                boolean renameResult = tempF.renameTo(af.getFile());
                if (!renameResult) {
                    logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE.getMsg(af.getFile().getPath(), tempF.getPath()));
                    throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE.getMsg(af.getFile().getPath(), tempF.getPath()));
                }
                result = tempF;
                // If still exists we can now delete
                if (tempF.exists()) {
                    if (!tempF.delete()) {
                        // Non critical failed deletion
                        logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE.getMsg(tempF.getPath()));
                    }
                }
            } else {
                // It was created but never used
                if (!tempF.delete()) {
                    // Non critical failed deletion
                    logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE.getMsg(tempF.getPath()));
                }
            }
        } catch (Exception ex) {
            logger.severe("AudioFileWriter exception cleaning up delete:" + af.getFile().getPath() + " or" + tempF.getAbsolutePath() + ":" + ex);
        }
        // Notify listener
        if (this.modificationListener != null) {
            this.modificationListener.fileOperationFinished(result);
        }
    }
}
Also used : CannotWriteException(org.jaudiotagger.audio.exceptions.CannotWriteException) RandomAccessFile(java.io.RandomAccessFile) RandomAccessFile(java.io.RandomAccessFile) AudioFile(org.jaudiotagger.audio.AudioFile) File(java.io.File) MP3File(org.jaudiotagger.audio.mp3.MP3File) ModifyVetoException(org.jaudiotagger.audio.exceptions.ModifyVetoException) CannotReadException(org.jaudiotagger.audio.exceptions.CannotReadException) ModifyVetoException(org.jaudiotagger.audio.exceptions.ModifyVetoException) IOException(java.io.IOException) CannotWriteException(org.jaudiotagger.audio.exceptions.CannotWriteException)

Example 15 with CannotWriteException

use of org.jaudiotagger.audio.exceptions.CannotWriteException in project Shuttle by timusus.

the class TaggerTask method doInBackground.

@Override
protected Boolean doInBackground(Object... params) {
    boolean success = false;
    boolean requiresPermission = TaggerUtils.requiresPermission(applicationContext, paths);
    for (int i = 0; i < paths.size(); i++) {
        final String path = paths.get(i);
        try {
            File orig = new File(path);
            AudioFile audioFile = AudioFileIO.read(orig);
            Tag tag = audioFile.getTag();
            if (tag == null) {
                break;
            }
            TagUpdate tagUpdate = new TagUpdate(tag);
            tagUpdate.softSetArtist(artistText);
            tagUpdate.softSetAlbumArtist(albumArtistText);
            tagUpdate.softSetGenre(genreText);
            tagUpdate.softSetYear(yearText);
            if (showAlbum) {
                tagUpdate.softSetAlbum(albumText);
                tagUpdate.softSetDiscTotal(discTotalText);
            }
            if (showTrack) {
                tagUpdate.softSetTitle(titleText);
                tagUpdate.softSetTrack(trackText);
                tagUpdate.softSetTrackTotal(trackTotalText);
                tagUpdate.softSetDisc(discText);
                tagUpdate.softSetLyrics(lyricsText);
                tagUpdate.softSetComment(commentText);
            }
            File temp = null;
            if (tagUpdate.hasChanged()) {
                if (TaggerUtils.requiresPermission(applicationContext, paths)) {
                    temp = new File(applicationContext.getFilesDir(), orig.getName());
                    tempFiles.add(temp);
                    TaggerUtils.copyFile(orig, temp);
                    audioFile = AudioFileIO.read(temp);
                    tag = audioFile.getTag();
                    if (tag == null) {
                        break;
                    }
                }
                tagUpdate.updateTag(tag);
                AudioFileIO.write(audioFile);
                if (requiresPermission && temp != null) {
                    DocumentFile documentFile = documentFiles.get(i);
                    if (documentFile != null) {
                        ParcelFileDescriptor pfd = applicationContext.getContentResolver().openFileDescriptor(documentFile.getUri(), "w");
                        if (pfd != null) {
                            FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
                            TaggerUtils.copyFile(temp, fileOutputStream);
                            pfd.close();
                        }
                        if (temp.delete()) {
                            if (tempFiles.contains(temp)) {
                                tempFiles.remove(temp);
                            }
                        }
                    }
                }
            }
            publishProgress(i);
            success = true;
        } catch (CannotWriteException | IOException | CannotReadException | InvalidAudioFrameException | TagException | ReadOnlyFileException e) {
            e.printStackTrace();
        } finally {
            // Try to clean up our temp files
            if (tempFiles != null && tempFiles.size() != 0) {
                for (int j = tempFiles.size() - 1; j >= 0; j--) {
                    File file = tempFiles.get(j);
                    file.delete();
                    tempFiles.remove(j);
                }
            }
        }
    }
    return success;
}
Also used : CannotWriteException(org.jaudiotagger.audio.exceptions.CannotWriteException) DocumentFile(android.support.v4.provider.DocumentFile) CannotReadException(org.jaudiotagger.audio.exceptions.CannotReadException) InvalidAudioFrameException(org.jaudiotagger.audio.exceptions.InvalidAudioFrameException) IOException(java.io.IOException) TagUpdate(com.simplecity.amp_library.model.TagUpdate) AudioFile(org.jaudiotagger.audio.AudioFile) TagException(org.jaudiotagger.tag.TagException) FileOutputStream(java.io.FileOutputStream) ParcelFileDescriptor(android.os.ParcelFileDescriptor) ReadOnlyFileException(org.jaudiotagger.audio.exceptions.ReadOnlyFileException) Tag(org.jaudiotagger.tag.Tag) File(java.io.File) AudioFile(org.jaudiotagger.audio.AudioFile) DocumentFile(android.support.v4.provider.DocumentFile)

Aggregations

CannotWriteException (org.jaudiotagger.audio.exceptions.CannotWriteException)15 CannotReadException (org.jaudiotagger.audio.exceptions.CannotReadException)12 IOException (java.io.IOException)10 File (java.io.File)9 AudioFile (org.jaudiotagger.audio.AudioFile)9 InvalidAudioFrameException (org.jaudiotagger.audio.exceptions.InvalidAudioFrameException)7 ReadOnlyFileException (org.jaudiotagger.audio.exceptions.ReadOnlyFileException)7 Tag (org.jaudiotagger.tag.Tag)7 TagException (org.jaudiotagger.tag.TagException)6 FileOutputStream (java.io.FileOutputStream)4 ContentValues (android.content.ContentValues)3 Cursor (android.database.Cursor)3 ByteBuffer (java.nio.ByteBuffer)3 FieldDataInvalidException (org.jaudiotagger.tag.FieldDataInvalidException)3 KeyNotFoundException (org.jaudiotagger.tag.KeyNotFoundException)3 Intent (android.content.Intent)2 ParcelFileDescriptor (android.os.ParcelFileDescriptor)2 DocumentFile (android.support.v4.provider.DocumentFile)2 DBAccessHelper (com.jams.music.player.DBHelpers.DBAccessHelper)2 TagUpdate (com.simplecity.amp_library.model.TagUpdate)2