Exemple #1
0
Frame *Frame::createTextualFrame(const String &key, const StringList &values) //static
{
  // check if the key is contained in the key<=>frameID mapping
  ByteVector frameID = keyToFrameID(key);
  if(!frameID.isNull()) {
    if(frameID[0] == 'T'){ // text frame
      TextIdentificationFrame *frame = new TextIdentificationFrame(frameID, String::UTF8);
      frame->setText(values);
      return frame;
    } else if((frameID[0] == 'W') && (values.size() == 1)){  // URL frame (not WXXX); support only one value
        UrlLinkFrame* frame = new UrlLinkFrame(frameID);
        frame->setUrl(values.front());
        return frame;
    }
  }
  if(key == "MUSICBRAINZ_TRACKID" && values.size() == 1) {
    UniqueFileIdentifierFrame *frame = new UniqueFileIdentifierFrame("http://musicbrainz.org", values.front().data(String::UTF8));
    return frame;
  }
  // now we check if it's one of the "special" cases:
  // -LYRICS: depending on the number of values, use USLT or TXXX (with description=LYRICS)
  if((key == "LYRICS" || key.startsWith(lyricsPrefix)) && values.size() == 1){
    UnsynchronizedLyricsFrame *frame = new UnsynchronizedLyricsFrame(String::UTF8);
    frame->setDescription(key == "LYRICS" ? key : key.substr(lyricsPrefix.size()));
    frame->setText(values.front());
    return frame;
  }
  // -URL: depending on the number of values, use WXXX or TXXX (with description=URL)
  if((key == "URL" || key.startsWith(urlPrefix)) && values.size() == 1){
    UserUrlLinkFrame *frame = new UserUrlLinkFrame(String::UTF8);
    frame->setDescription(key == "URL" ? key : key.substr(urlPrefix.size()));
    frame->setUrl(values.front());
    return frame;
  }
  // -COMMENT: depending on the number of values, use COMM or TXXX (with description=COMMENT)
  if((key == "COMMENT" || key.startsWith(commentPrefix)) && values.size() == 1){
    CommentsFrame *frame = new CommentsFrame(String::UTF8);
    if (key != "COMMENT"){
      frame->setDescription(key.substr(commentPrefix.size()));
    }
    frame->setText(values.front());
    return frame;
  }
  // if non of the above cases apply, we use a TXXX frame with the key as description
  return new UserTextIdentificationFrame(keyToTXXX(key), values, String::UTF8);
}
Exemple #2
0
long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &before)
{
    if(!d->stream || pattern.size() > d->bufferSize)
        return -1;

    // The position in the file that the current buffer starts at.

    ByteVector buffer;

    // These variables are used to keep track of a partial match that happens at
    // the end of a buffer.

    /*
    int previousPartialMatch = -1;
    int beforePreviousPartialMatch = -1;
    */

    // Save the location of the current read pointer.  We will restore the
    // position using seek() before all returns.

    long originalPosition = tell();

    // Start the search at the offset.

    long bufferOffset;
    if(fromOffset == 0) {
        seek(-1 * int(d->bufferSize), End);
        bufferOffset = tell();
    }
    else {
        seek(fromOffset + -1 * int(d->bufferSize), Beginning);
        bufferOffset = tell();
    }

    // See the notes in find() for an explanation of this algorithm.

    for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) {

        // TODO: (1) previous partial match

        // (2) pattern contained in current buffer

        long location = buffer.rfind(pattern);
        if(location >= 0) {
            seek(originalPosition);
            return bufferOffset + location;
        }

        if(!before.isNull() && buffer.find(before) >= 0) {
            seek(originalPosition);
            return -1;
        }

        // TODO: (3) partial match

        bufferOffset -= d->bufferSize;
        seek(bufferOffset);
    }

    // Since we hit the end of the file, reset the status before continuing.

    clear();

    seek(originalPosition);

    return -1;
}
Exemple #3
0
long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &before)
{
    if(!d->stream || pattern.size() > d->bufferSize)
        return -1;

    // The position in the file that the current buffer starts at.

    long bufferOffset = fromOffset;
    ByteVector buffer;

    // These variables are used to keep track of a partial match that happens at
    // the end of a buffer.

    int previousPartialMatch = -1;
    int beforePreviousPartialMatch = -1;

    // Save the location of the current read pointer.  We will restore the
    // position using seek() before all returns.

    long originalPosition = tell();

    // Start the search at the offset.

    seek(fromOffset);

    // This loop is the crux of the find method.  There are three cases that we
    // want to account for:
    //
    // (1) The previously searched buffer contained a partial match of the search
    // pattern and we want to see if the next one starts with the remainder of
    // that pattern.
    //
    // (2) The search pattern is wholly contained within the current buffer.
    //
    // (3) The current buffer ends with a partial match of the pattern.  We will
    // note this for use in the next itteration, where we will check for the rest
    // of the pattern.
    //
    // All three of these are done in two steps.  First we check for the pattern
    // and do things appropriately if a match (or partial match) is found.  We
    // then check for "before".  The order is important because it gives priority
    // to "real" matches.

    for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) {

        // (1) previous partial match

        if(previousPartialMatch >= 0 && int(d->bufferSize) > previousPartialMatch) {
            const int patternOffset = (d->bufferSize - previousPartialMatch);
            if(buffer.containsAt(pattern, 0, patternOffset)) {
                seek(originalPosition);
                return bufferOffset - d->bufferSize + previousPartialMatch;
            }
        }

        if(!before.isNull() && beforePreviousPartialMatch >= 0 && int(d->bufferSize) > beforePreviousPartialMatch) {
            const int beforeOffset = (d->bufferSize - beforePreviousPartialMatch);
            if(buffer.containsAt(before, 0, beforeOffset)) {
                seek(originalPosition);
                return -1;
            }
        }

        // (2) pattern contained in current buffer

        long location = buffer.find(pattern);
        if(location >= 0) {
            seek(originalPosition);
            return bufferOffset + location;
        }

        if(!before.isNull() && buffer.find(before) >= 0) {
            seek(originalPosition);
            return -1;
        }

        // (3) partial match

        previousPartialMatch = buffer.endsWithPartialMatch(pattern);

        if(!before.isNull())
            beforePreviousPartialMatch = buffer.endsWithPartialMatch(before);

        bufferOffset += d->bufferSize;
    }

    // Since we hit the end of the file, reset the status before continuing.

    clear();

    seek(originalPosition);

    return -1;
}
void Ogg::FLAC::File::scan()
{
  // Scan the metadata pages

  if(d->scanned)
    return;

  if(!isValid())
    return;

  int ipacket = 0;
  long overhead = 0;

  ByteVector metadataHeader = packet(ipacket);
  if(metadataHeader.isNull())
    return;

  ByteVector header;

  if (!metadataHeader.startsWith("fLaC"))  {
    // FLAC 1.1.2+
    if (metadataHeader.mid(1,4) != "FLAC") return;

    if (metadataHeader[5] != 1) return; // not version 1

    metadataHeader = metadataHeader.mid(13);
  }
  else {
    // FLAC 1.1.0 & 1.1.1
    metadataHeader = packet(++ipacket);

  if(metadataHeader.isNull())
    return;

  }

  header = metadataHeader.mid(0,4);
  // Header format (from spec):
  // <1> Last-metadata-block flag
  // <7> BLOCK_TYPE
  //    0 : STREAMINFO
  //    1 : PADDING
  //    ..
  //    4 : VORBIS_COMMENT
  //    ..
  // <24> Length of metadata to follow

  char blockType = header[0] & 0x7f;
  bool lastBlock = (header[0] & 0x80) != 0;
  uint length = header.mid(1, 3).toUInt();
  overhead += length;

  // Sanity: First block should be the stream_info metadata

  if(blockType != 0) {
    debug("Ogg::FLAC::File::scan() -- Invalid Ogg/FLAC stream");
    return;
  }

  d->streamInfoData = metadataHeader.mid(4,length);

  // Search through the remaining metadata

  while(!lastBlock) {
    metadataHeader = packet(++ipacket);

    if(metadataHeader.isNull())
      return;

    header = metadataHeader.mid(0, 4);
    blockType = header[0] & 0x7f;
    lastBlock = (header[0] & 0x80) != 0;
    length = header.mid(1, 3).toUInt();
    overhead += length;

    if(blockType == 1) {
      // debug("Ogg::FLAC::File::scan() -- Padding found");
    }
    else if(blockType == 4) {
      // debug("Ogg::FLAC::File::scan() -- Vorbis-comments found");
      d->xiphCommentData = metadataHeader.mid(4, length);
      d->hasXiphComment = true;
      d->commentPacket = ipacket;
    }
    else if(blockType > 5)
      debug("Ogg::FLAC::File::scan() -- Unknown metadata block");

  }

  // End of metadata, now comes the datastream
  d->streamStart = overhead;
  d->streamLength = File::length() - d->streamStart;

  d->scanned = true;
}