From 097ae0d78552658b15d6f0dd5ff55aac235b4c87 Mon Sep 17 00:00:00 2001 From: Scott Wheeler Date: Sun, 12 Jul 2009 21:53:18 +0000 Subject: [PATCH] Use flac padding. Updated patch from Toby Dickenson BUG:107659 git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@995518 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- taglib/flac/flacfile.cpp | 83 ++++++++++++++++++++++++++++++++++++---- taglib/flac/flacfile.h | 1 + 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/taglib/flac/flacfile.cpp b/taglib/flac/flacfile.cpp index 2cf35ad2..ed3d6db9 100644 --- a/taglib/flac/flacfile.cpp +++ b/taglib/flac/flacfile.cpp @@ -42,6 +42,7 @@ namespace { enum { XiphIndex = 0, ID3v2Index = 1, ID3v1Index = 2 }; enum { StreamInfo = 0, Padding, Application, SeekTable, VorbisComment, CueSheet }; + enum { MinPaddingLength = 4096 }; } class FLAC::File::FilePrivate @@ -167,9 +168,49 @@ bool FLAC::File::save() uint blockLength = header.mid(1, 3).toUInt(); if(blockType == VorbisComment) { - data[0] = header[0]; - insert(data, nextBlockOffset, blockLength + 4); - break; + + long paddingBreak = 0; + + if(!isLastBlock) { + paddingBreak = findPaddingBreak(nextBlockOffset + blockLength + 4, + nextBlockOffset + d->xiphCommentData.size() + 8, + &isLastBlock); + } + + uint paddingLength = 0; + + if(paddingBreak) { + + // There is space for comment and padding blocks without rewriting the + // whole file. Note: This cannot overflow. + + paddingLength = paddingBreak - (nextBlockOffset + d->xiphCommentData.size() + 8); + } + else { + + // Not enough space, so we will have to rewrite the whole file + // following this block + + paddingLength = d->xiphCommentData.size(); + + if(paddingLength < MinPaddingLength) + paddingLength = MinPaddingLength; + + paddingBreak = nextBlockOffset + blockLength + 4; + } + + ByteVector padding = ByteVector::fromUInt(paddingLength); + + padding[0] = 1; + + if(isLastBlock) + padding[0] |= 0x80; + + padding.resize(paddingLength + 4); + ByteVector pair(data); + pair.append(padding); + insert(pair, nextBlockOffset, paddingBreak - nextBlockOffset); + break; } nextBlockOffset += blockLength + 4; @@ -373,11 +414,8 @@ void FLAC::File::scan() isLastBlock = (header[0] & 0x80) != 0; length = header.mid(1, 3).toUInt(); - if(blockType == Padding) { - // debug("FLAC::File::scan() -- Padding found"); - } // Found the vorbis-comment - else if(blockType == VorbisComment) { + if(blockType == VorbisComment) { d->xiphCommentData = readBlock(length); d->hasXiphComment = true; } @@ -429,3 +467,34 @@ long FLAC::File::findID3v2() return -1; } + +long FLAC::File::findPaddingBreak(long nextBlockOffset, long targetOffset, bool *isLast) +{ + // Starting from nextBlockOffset, step over padding blocks to find the + // address of a block which is after targetOffset. Return zero if + // a non-padding block occurs before that point. + + while(true) { + seek(nextBlockOffset); + + ByteVector header = readBlock(4); + char blockType = header[0] & 0x7f; + bool isLastBlock = header[0] & 0x80; + uint length = header.mid(1, 3).toUInt(); + + if(blockType != Padding) + break; + + nextBlockOffset += 4 + length; + + if(nextBlockOffset >= targetOffset) { + *isLast = isLastBlock; + return nextBlockOffset; + } + + if(isLastBlock) + break; + } + + return 0; +} diff --git a/taglib/flac/flacfile.h b/taglib/flac/flacfile.h index ae1fe69b..015ecc8e 100644 --- a/taglib/flac/flacfile.h +++ b/taglib/flac/flacfile.h @@ -191,6 +191,7 @@ namespace TagLib { long findID3v2(); long findID3v1(); ByteVector xiphCommentData() const; + long findPaddingBreak(long nextPageOffset, long targetOffset, bool *isLast); class FilePrivate; FilePrivate *d;