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);
}
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");
}
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");
}
}
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);
}
}
}
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;
}
Aggregations