void ID3_TagHeader::Render(ID3_Writer& writer) const
{
  writer.writeChars((uchar *) ID, strlen(ID));

  writer.writeChar(ID3_V2SpecToVer(ID3V2_LATEST));
  writer.writeChar(ID3_V2SpecToRev(ID3V2_LATEST));

  // set the flags byte in the header
  writer.writeChar(static_cast<uchar>(_flags.get() & MASK8));
  io::writeUInt28(writer, this->GetDataSize()); //now includes the extended header

  // now we render the extended header
  if (_flags.test(HEADER_FLAG_EXTENDED))
  {
    if (this->GetSpec() == ID3V2_4_0)
    {
      io::writeUInt28(writer, 6); //write 4 bytes of v2.4.0 ext header containing size '6'
      io::writeBENumber(writer, 1, 1); //write that it has only one flag byte (value '1')
      io::writeBENumber(writer, 0, 1); //write flag byte with value '0'
    }
    else if (this->GetSpec() == ID3V2_3_0)
    {
      io::writeBENumber(writer, 6, sizeof(uint32));
      for (size_t i = 0; i < 6; ++i)
      {
        if (writer.writeChar('\0') == ID3_Writer::END_OF_WRITER)
        {
          break;
        }
      }
    }
  //  else //not implemented
  }
}
Beispiel #2
0
size_t io::writeUnicodeText(ID3_Writer& writer, String data, bool bom)
{
  ID3_Writer::pos_type beg = writer.getCur();
  size_t size = (data.size() / 2) * 2;
  if (size == 0)
  {
    return 0;
  }
  if (bom)
  {
    // Write the BOM: 0xFEFF
    unicode_t BOM = 0xFEFF;
    writer.writeChars((const unsigned char*) &BOM, 2);
  }
  // AF outside if( bom )

    for (size_t i = 0; i < size; i += 2)
    {
    // AF TODO FIXME PATCH      unicode_t ch = (data[i] << 8) | data[i+1];
        // AF: SWAP BYTES AND PERFORM unsigned char cast
        unicode_t ch = (static_cast<unsigned char>(data[i+1]) << 8) | static_cast<unsigned char>(data[i]);
        writer.writeChars((const unsigned char*) &ch, 2);
    }

    return writer.getCur() - beg;
}
Beispiel #3
0
void id3::v2::render(ID3_Writer& writer, const ID3_TagImpl& tag)
{
    // There has to be at least one frame for there to be a tag...
    if (tag.NumFrames() == 0)
    {
        ID3D_WARNING( "id3::v2::render(): no frames to render" );
        return;
    }

    ID3D_NOTICE( "id3::v2::render(): rendering" );
    ID3_TagHeader hdr;
    hdr.SetSpec(tag.GetSpec());
    hdr.SetExtended(tag.GetExtended());
    hdr.SetExperimental(tag.GetExperimental());

    // set up the encryption and grouping IDs

    // ...
    String frms;
    io::StringWriter frmWriter(frms);
    if (!tag.GetUnsync())
    {
        ID3D_NOTICE( "id3::v2::render(): rendering frames" );
        renderFrames(frmWriter, tag);
        hdr.SetUnsync(false);
    }
    else
    {
        ID3D_NOTICE( "id3::v2::render(): rendering unsynced frames" );
        io::UnsyncedWriter uw(frmWriter);
        renderFrames(uw, tag);
        uw.flush();
        ID3D_NOTICE( "id3::v2::render(): numsyncs = " << uw.getNumSyncs() );
        hdr.SetUnsync(uw.getNumSyncs() > 0);
    }
    size_t frmSize = frms.size();
    if (frmSize == 0)
    {
        ID3D_WARNING( "id3::v2::render(): rendered frame size is 0 bytes" );
        return;
    }

    // zero the remainder of the buffer so that our padding bytes are zero
    luint nPadding = tag.PaddingSize(frmSize);
    ID3D_NOTICE( "id3::v2::render(): padding size = " << nPadding );
    hdr.SetDataSize(frmSize + nPadding);

    hdr.Render(writer);

    writer.writeChars(frms.data(), frms.size());

    for (size_t i = 0; i < nPadding; ++i)
    {
        if (writer.writeChar('\0') == ID3_Writer::END_OF_WRITER)
        {
            break;
        }
    }
}
size_t io::writeTrailingSpaces(ID3_Writer& writer, String buf, size_t len)
{
  ID3_Writer::pos_type beg = writer.getCur();
  ID3_Writer::size_type strLen = buf.size();
  ID3_Writer::size_type size = min((unsigned int)len, (unsigned int)strLen);
  writer.writeChars(buf.data(), size);
  for (; size < len; ++size)
  {
    writer.writeChar('\0');
  }
  return writer.getCur() - beg;
}
Beispiel #5
0
size_t ID3_Tag::Render(ID3_Writer& writer, ID3_TagType tt) const
{
  ID3_Writer::pos_type beg = writer.getCur();
  if (ID3TT_ID3V2 & tt)
  {
    id3::v2::render(writer, *this);
  }
  else if (ID3TT_ID3V1 & tt)
  {
    id3::v1::render(writer, *this);
  }
  return writer.getCur() - beg;
}
size_t io::writeBENumber(ID3_Writer& writer, uint32 val, size_t len)
{
  ID3_Writer::char_type bytes[sizeof(uint32)];
  ID3_Writer::size_type size = min<ID3_Reader::size_type>(len, sizeof(uint32));
  renderNumber(bytes, val, size);
  return writer.writeChars(bytes, size);
}
size_t io::writeUnicodeString(ID3_Writer& writer, String data, bool bom)
{
  size_t size = writeUnicodeText(writer, data, bom);
  unicode_t null = NULL_UNICODE;
  writer.writeChars((const unsigned char*) &null, 2);
  return size + 2;
}
Beispiel #8
0
void ID3_FrameHeader::Render(ID3_Writer& writer) const
{
  size_t size = 0;

  if (NULL == _frame_def)
  {
    // TODO: log this
    ID3D_WARNING( "ID3_FrameHeader::Render(): _frame_def is NULL!" );
    return;
    //ID3_THROW(ID3E_InvalidFrameID);
  }
  char *textID;
  if (_info->frame_bytes_id == strlen(_frame_def->sShortTextID))
  {
    textID = _frame_def->sShortTextID;
  }
  else
  {
    textID = _frame_def->sLongTextID;
  }

  ID3D_NOTICE( "ID3_FrameHeader::Render(): writing " << textID << ", " << (int) _info->frame_bytes_size << " bytes");
  writer.writeChars((uchar *) textID, _info->frame_bytes_id);

  io::writeBENumber(writer, _data_size, _info->frame_bytes_size);
  io::writeBENumber(writer, _flags.get(), _info->frame_bytes_flags);
}
Beispiel #9
0
size_t io::writeUnicodeText(ID3_Writer& writer, String data, bool bom)
{
  ID3_Writer::pos_type beg = writer.getCur();
  size_t size = (data.size() / 2) * 2;
  if (size == 0)
  {
    return 0;
  }
  if (bom)
  {
    // Write the BOM: 0xFEFF
    unicode_t BOM = 0xFEFF;
    writer.writeChars((const unsigned char*) &BOM, 2);
  }
  writer.writeChars(&data[0], size);
  return writer.getCur() - beg;
}
Beispiel #10
0
void ID3_TagHeader::Render(ID3_Writer& writer) const
{
  writer.writeChars((uchar *) ID, strlen(ID));

  writer.writeChar(ID3_V2SpecToVer(ID3V2_LATEST));
  writer.writeChar(ID3_V2SpecToRev(ID3V2_LATEST));
  
  // set the flags byte in the header
  writer.writeChar(static_cast<uchar>(_flags.get() & MASK8));
  io::writeUInt28(writer, this->GetDataSize());

  // now we render the extended header
  if (_flags.test(EXTENDED))
  {
    io::writeBENumber(writer, _info->extended_bytes, sizeof(uint32));
  }
}
size_t io::writeUnicodeText(ID3_Writer& writer, String data, bool bom)
{
  ID3_Writer::pos_type beg = writer.getCur();
  size_t size = (data.size() / 2) * 2;
  if (size == 0)
  {
    return 0;
  }
  int is_bom = isBOM(data[0],data[1]);
  if (!is_bom && bom) {
    // Write the BOM: 0xFEFF
    const unsigned char BOMch1 = 0xFE;
    const unsigned char BOMch2 = 0xFF;
    writer.writeChars(&BOMch1, 1);
    writer.writeChars(&BOMch2, 1);
  }
  for (size_t i = 0; i < size; i += 2)
  {
    if (!i && !bom && is_bom) {
      // Skip unneeded leading BOM
      continue;
    }
    if (is_bom >= 0) {
      writer.writeChars(data.data()+i, 1);
      writer.writeChars(data.data()+i+1, 1);
    }
    else {
      writer.writeChars(data.data()+i+1, 1);
      writer.writeChars(data.data()+i, 1);
    }
  }
  return writer.getCur() - beg;
}
Beispiel #12
0
size_t io::writeUnicodeText(ID3_Writer& writer, String data, bool bom)
{
  ID3_Writer::pos_type beg = writer.getCur();
  size_t size = (data.size() / 2) * 2;
  if (size == 0)
  {
    return 0;
  }
  if (bom)
  {
    // Write the BOM: 0xFEFF
    unicode_t BOM = 0xFEFF;
    writer.writeChars((const unsigned char*) &BOM, 2);
    for (size_t i = 0; i < size; i += 2)
    {
      unicode_t ch = (data[i] << 8) | data[i+1];
      writer.writeChars((const unsigned char*) &ch, 2);
    }
  }
  return writer.getCur() - beg;
}
Beispiel #13
0
void id3::v1::render(ID3_Writer& writer, const ID3_TagImpl& tag)
{
    writer.writeChars("TAG", 3);

    io::writeTrailingSpaces(writer, id3::v2::getTitle(tag),  ID3_V1_LEN_TITLE);
    io::writeTrailingSpaces(writer, id3::v2::getArtist(tag), ID3_V1_LEN_ARTIST);
    io::writeTrailingSpaces(writer, id3::v2::getAlbum(tag),  ID3_V1_LEN_ALBUM);
    io::writeTrailingSpaces(writer, id3::v2::getYear(tag),   ID3_V1_LEN_YEAR);

    size_t track = id3::v2::getTrackNum(tag);
    String comment = id3::v2::getV1Comment(tag);
    if (track > 0)
    {
        io::writeTrailingSpaces(writer, comment, ID3_V1_LEN_COMMENT - 2);
        writer.writeChar('\0');
        writer.writeChar((char) track);
    }
    else
    {
        io::writeTrailingSpaces(writer, comment, ID3_V1_LEN_COMMENT);
    }
    writer.writeChar((char) id3::v2::getGenreNum(tag));
}
size_t io::writeUInt28(ID3_Writer& writer, uint32 val)
{
  uchar data[sizeof(uint32)];
  const unsigned short BITSUSED = 7;
  const uint32 MAXVAL = MASK(BITSUSED * sizeof(uint32));
  val = min(val, MAXVAL);
  // This loop renders the value to the character buffer in reverse order, as 
  // it is easy to extract the last 7 bits of an integer.  This is why the
  // loop shifts the value of the integer by 7 bits for each iteration.
  for (size_t i = 0; i < sizeof(uint32); ++i)
  {
    // Extract the last BITSUSED bits from val and put it in its appropriate
    // place in the data buffer
    data[sizeof(uint32) - i - 1] = static_cast<uchar>(val & MASK(BITSUSED));

    // The last BITSUSED bits were extracted from the val.  So shift it to the
    // right by that many bits for the next iteration
    val >>= BITSUSED;
  }
  
  // Should always render 4 bytes
  return writer.writeChars(data, sizeof(uint32));
}
Beispiel #15
0
void ID3_FrameImpl::Render(ID3_Writer& writer) const
{
  // Return immediately if we have no fields, which (usually) means we're
  // trying to render a frame which has been Cleared or hasn't been initialized
  if (!this->NumFields())
  {
    return;
  }

  ID3_FrameHeader hdr;
  
  const size_t hdr_size = hdr.Size();

  // 1.  Write out the field data to the buffer, with the assumption that
  //     we won't be decompressing, since this is the usual behavior
  String flds;
  io::StringWriter fldWriter(flds);
  size_t origSize = 0;
  if (!this->GetCompression())
  {
    renderFields(fldWriter, *this);
    origSize = flds.size();
    ID3D_NOTICE ( "ID3_FrameImpl::Render(): uncompressed fields" );
  }
  else
  {
    io::CompressedWriter cr(fldWriter);
    renderFields(cr, *this);
    cr.flush();
    origSize = cr.getOrigSize();
    ID3D_NOTICE ( "ID3_FrameImpl::Render(): compressed fields, orig size = " <<
                  origSize );
  }

  size_t fldSize = flds.size();
  ID3D_NOTICE ( "ID3_FrameImpl::Render(): field size = " << fldSize );
// No need to not write empty frames, why would we not? They can be used to fill up padding space
// which is even recommended in the id3 spec.
//  if (fldSize == 0)
//  {
//    ID3D_WARNING ( "ID3_FrameImpl::Render(): no field data" );
//    return;
//  }
  
  // determine which flags need to be set
  uchar eID = this->GetEncryptionID(), gID = this->GetGroupingID();
  ID3_FrameID fid = this->GetID();
  if (fid == ID3FID_NOFRAME)
  {
    const char *tid = this->GetTextID();
    hdr.SetUnknownFrame(tid);
  }
  else
  {
    hdr.SetFrameID(fid);
  }
  hdr.SetEncryption(eID > 0);
  hdr.SetGrouping(gID > 0);
  hdr.SetCompression(origSize > fldSize);
  hdr.SetDataSize(fldSize + ((hdr.GetCompression() ? 4 : 0) + 
                             (hdr.GetEncryption()  ? 1 : 0) + 
                             (hdr.GetGrouping()    ? 1 : 0)));

  // write out the header
  hdr.Render(writer);

  if (fldSize != 0)
  {
    // No-man's land!  Not part of the header, not part of the data
    if (hdr.GetCompression())
    {
      io::writeBENumber(writer, origSize, sizeof(uint32));
      ID3D_NOTICE( "ID3_FrameImpl::Render(): frame is compressed, wrote origSize = " << origSize );
    }
    if (hdr.GetEncryption())
    {
      writer.writeChar(eID);
      ID3D_NOTICE( "ID3_FrameImpl::Render(): frame is compressed, encryption id = " << eID );
    }
    if (hdr.GetGrouping())
    {
      writer.writeChar(gID);
      ID3D_NOTICE( "ID3_FrameImpl::Render(): frame is compressed, grouping id = " << gID );
    }

    // Write the field data
    writer.writeChars(flds.data(), fldSize);
  }
  _changed = false;
}
Beispiel #16
0
void ID3_FieldImpl::RenderBinary(ID3_Writer& writer) const
{
  writer.writeChars(this->GetRawBinary(), this->Size());
}
size_t io::writeText(ID3_Writer& writer, String data)
{
  ID3_Writer::pos_type beg = writer.getCur();
  writer.writeChars(data.data(), data.size());
  return writer.getCur() - beg;
}
size_t io::writeString(ID3_Writer& writer, String data)
{
  size_t size = writeText(writer, data);
  writer.writeChar('\0');
  return size + 1;
}