func (editor *OggTagEditor) makeNewPages(existingCommentPages []byte, tag Tag) ([]byte, []byte, int) { // bitstream number var bitstream int = 31013 if len(existingCommentPages) > oggPageHeaderSize { bitstream = utils.ReadInt32Le(existingCommentPages[14:18]) } commentHeader, existingTagData, setupHeader := editor.splitCommentPages(existingCommentPages) if len(commentHeader) == 0 { commentHeader = make([]byte, 1+len(oggHeaderMagic)+4) commentHeader[0] = 3 copy(commentHeader[1:1+len(oggHeaderMagic)], oggHeaderMagic) utils.WriteInt32Le(0, commentHeader[len(oggHeaderMagic):len(oggHeaderMagic)+4]) } unsupportedTagData, unsupportedFields := getUnsupportedVorbisTags(existingTagData) newTagData, totalFields := serializeVorbisTag(tag, unsupportedFields) tagData := make([]byte, len(commentHeader)+4+len(newTagData)+len(unsupportedTagData)+1) copy(tagData, commentHeader) utils.WriteInt32Le(totalFields, tagData[len(commentHeader):len(commentHeader)+4]) copy(tagData[len(commentHeader)+4:], newTagData) copy(tagData[len(commentHeader)+4+len(newTagData):], unsupportedTagData) tagData[len(tagData)-1] = 1 newCommentHeader, commentPages := editor.packTagDataIntoFrames(bitstream, 1, tagData) newSetupHeader, setupPages := editor.packTagDataIntoFrames(bitstream, commentPages+1, setupHeader) return newCommentHeader, newSetupHeader, commentPages + setupPages }
func (editor *OggTagEditor) WriteTag(src, dst string, tag Tag) error { err := editor.readFile(src) if err != nil { return err } idPage, commentPages, restData := editor.splitFileData(editor.file) newCommentPages, newSetupPages, numberOfPages := editor.makeNewPages(commentPages, tag) newPrefix := make([]byte, len(idPage)+len(newCommentPages)+len(newSetupPages)) copy(newPrefix, idPage) copy(newPrefix[len(idPage):], newCommentPages) copy(newPrefix[len(idPage)+len(newCommentPages):], newSetupPages) // fix page numbers and CRCs sequence := numberOfPages + 1 data := restData for len(data) > oggPageHeaderSize { pageSize := editor.getPageSize(data) utils.WriteInt32Le(sequence, data[18:22]) // number utils.WriteUint32Le(0, data[22:26]) // zero CRC utils.WriteUint32Le(editor.crc(data[:pageSize]), data[22:26]) // CRC sequence++ data = data[pageSize:] } return ioutil.WriteFile(dst, append(newPrefix, restData...), 0666) }
func serializeVorbisTagTextField(text, frameName string, dst []byte, offset int) int { fieldSize := len(frameName) + len(text) + 1 utils.WriteInt32Le(fieldSize, dst[offset:offset+4]) copy(dst[offset+4:offset+4+len(frameName)], frameName) dst[offset+4+len(frameName)] = 0x3d // '=' copy(dst[offset+5+len(frameName):offset+4+fieldSize], text) return offset + 4 + fieldSize }
func (editor *OggTagEditor) fillHeader(dst []byte, bitstream, sequence, totalSize int) (int, int) { copy(dst[0:4], oggPageMagic) // magic dst[4] = 0 // version dst[5] = 0 // header type dst[6] = 0 // granule position dst[7] = 0 dst[8] = 0 dst[9] = 0 dst[10] = 0 dst[11] = 0 dst[12] = 0 dst[13] = 0 utils.WriteInt32Le(bitstream, dst[14:18]) // bitstream serial number utils.WriteInt32Le(sequence, dst[18:22]) // page sequence number dst[22] = 0 // CRC checksum dst[23] = 0 dst[24] = 0 dst[25] = 0 dataSize := totalSize if dataSize > maxFrameDataSize { dataSize = maxFrameDataSize } dst[26] = byte(dataSize / 255) if dataSize%255 != 0 { dst[26]++ } headerSize := 27 + int(dst[26]) for i := 27; i < headerSize; i++ { dst[i] = 0xFF } if dataSize%255 != 0 { dst[headerSize-1] = byte(dataSize % 255) } return headerSize, dataSize }
func (editor *FlacTagEditor) makeNewCommentBlock(tag Tag, existingCommentBlock []byte) []byte { var vendorData []byte = nil var unsupportedTagData []byte = nil var unsupportedFields int = 0 if len(existingCommentBlock) >= 8 { vendorSize := utils.ReadInt32Le(existingCommentBlock[4:8]) vendorData = existingCommentBlock[4 : 8+vendorSize] unsupportedTagData, unsupportedFields = getUnsupportedVorbisTags(existingCommentBlock[8+vendorSize:]) } newCommentData, totalFields := serializeVorbisTag(tag, unsupportedFields) newCommentBlock := make([]byte, 4+len(vendorData)+4+len(newCommentData)+len(unsupportedTagData)) newCommentBlock[0] = commentBlockType utils.WriteInt24Be(len(newCommentBlock)-4, newCommentBlock[1:4]) copy(newCommentBlock[4:], vendorData) utils.WriteInt32Le(totalFields, newCommentBlock[4+len(vendorData):8+len(vendorData)]) copy(newCommentBlock[8+len(vendorData):], newCommentData) copy(newCommentBlock[8+len(vendorData)+len(newCommentData):], unsupportedTagData) return newCommentBlock }