Overview

Packages

  • admin
  • classes
    • media
  • CodeIgniter
    • Libraries
  • core
  • functions
  • JSMin
  • None
  • OpenID
  • PHP
  • PHPMailer
  • plugins
    • admin
    • development
    • feed
    • mail
    • media
    • misc
    • seo
    • spam
    • uploader
    • users
    • zenpage
    • zenphoto
      • news
  • Services
    • JSON

Classes

  • _zp_captcha
  • _zp_HTML_cache
  • admin_approval
  • Album
  • AlbumBase
  • AlbumZip
  • AMFReader
  • AMFStream
  • AnyFile
  • AnyFile_Options
  • Auth_OpenID
  • Auth_OpenID_AlreadySigned
  • Auth_OpenID_AssociateRequest
  • Auth_OpenID_Association
  • Auth_OpenID_AuthRequest
  • Auth_OpenID_AX
  • Auth_OpenID_AX_AttrInfo
  • Auth_OpenID_AX_Error
  • Auth_OpenID_AX_FetchRequest
  • Auth_OpenID_AX_FetchResponse
  • Auth_OpenID_AX_KeyValueMessage
  • Auth_OpenID_AX_Message
  • Auth_OpenID_AX_StoreRequest
  • Auth_OpenID_AX_StoreResponse
  • Auth_OpenID_BcMathWrapper
  • Auth_OpenID_CancelResponse
  • Auth_OpenID_CheckAuthRequest
  • Auth_OpenID_CheckIDRequest
  • Auth_OpenID_Consumer
  • Auth_OpenID_ConsumerResponse
  • Auth_OpenID_CryptUtil
  • Auth_OpenID_DatabaseConnection
  • Auth_OpenID_Decoder
  • Auth_OpenID_DiffieHellman
  • Auth_OpenID_DiffieHellmanSHA1ConsumerSession
  • Auth_OpenID_DiffieHellmanSHA1ServerSession
  • Auth_OpenID_DiffieHellmanSHA256ConsumerSession
  • Auth_OpenID_DiffieHellmanSHA256ServerSession
  • Auth_OpenID_DumbStore
  • Auth_OpenID_Encoder
  • Auth_OpenID_EncodingError
  • Auth_OpenID_Extension
  • Auth_OpenID_FailureResponse
  • Auth_OpenID_FileStore
  • Auth_OpenID_GenericConsumer
  • Auth_OpenID_GmpMathWrapper
  • Auth_OpenID_KVForm
  • Auth_OpenID_MalformedReturnURL
  • Auth_OpenID_MalformedTrustRoot
  • Auth_OpenID_Mapping
  • Auth_OpenID_MathLibrary
  • Auth_OpenID_MDB2Store
  • Auth_OpenID_MemcachedStore
  • Auth_OpenID_Message
  • Auth_OpenID_MySQLStore
  • Auth_OpenID_NamespaceMap
  • Auth_OpenID_NoReturnToError
  • Auth_OpenID_OpenIDStore
  • Auth_OpenID_PAPE_Request
  • Auth_OpenID_PAPE_Response
  • Auth_OpenID_Parse
  • Auth_OpenID_PlainTextConsumerSession
  • Auth_OpenID_PlainTextServerSession
  • Auth_OpenID_PostgreSQLStore
  • Auth_OpenID_Request
  • Auth_OpenID_Server
  • Auth_OpenID_ServerError
  • Auth_OpenID_ServerErrorContainer
  • Auth_OpenID_ServerRequest
  • Auth_OpenID_ServerResponse
  • Auth_OpenID_ServiceEndpoint
  • Auth_OpenID_ServiceEndpointLoader
  • Auth_OpenID_SessionNegotiator
  • Auth_OpenID_SetupNeededResponse
  • Auth_OpenID_Signatory
  • Auth_OpenID_SigningEncoder
  • Auth_OpenID_SQLiteStore
  • Auth_OpenID_SQLStore
  • Auth_OpenID_SRegBase
  • Auth_OpenID_SRegRequest
  • Auth_OpenID_SRegResponse
  • Auth_OpenID_SuccessResponse
  • Auth_OpenID_TrustRoot
  • Auth_OpenID_TypeURIMismatch
  • Auth_OpenID_UntrustedReturnURL
  • Auth_OpenID_WebResponse
  • Auth_Yadis_Discovery
  • Auth_Yadis_DiscoveryResult
  • Auth_Yadis_dom
  • Auth_Yadis_domxml
  • Auth_Yadis_HTTPFetcher
  • Auth_Yadis_HTTPResponse
  • Auth_Yadis_Manager
  • Auth_Yadis_ManagerLoader
  • Auth_Yadis_ParanoidHTTPFetcher
  • Auth_Yadis_ParseHTML
  • Auth_Yadis_PHPSession
  • Auth_Yadis_PlainHTTPFetcher
  • Auth_Yadis_ProxyResolver
  • Auth_Yadis_Service
  • Auth_Yadis_SessionLoader
  • Auth_Yadis_XMLParser
  • Auth_Yadis_XRDS
  • Auth_Yadis_Yadis
  • auto_backup
  • AVCSequenceParameterSetReader
  • bxslider
  • cacheManager
  • cacheManagerFeed
  • CI_jsmin
  • CI_load
  • cloneZenphoto
  • codeIgniter_kludge
  • colorbox
  • Comment
  • comment_form
  • contactformOptions
  • crop_image
  • cycle
  • defaultCodeblocks
  • deprecated_functions
  • DownloadList
  • dynamic_locale
  • dynamicAlbum
  • elFinder_options
  • email_new_user
  • exampleMacros
  • external_auth
  • ExternalFeed
  • externalFeed_options
  • favorites
  • favoritesOptions
  • federated_logon
  • feed
  • fieldExtender
  • flag_thumbnail
  • Gallery
  • galleryArticles
  • getID3
  • getid3_aac
  • getid3_apetag
  • getid3_flv
  • getid3_handler
  • getid3_id3v1
  • getid3_id3v2
  • getid3_lib
  • getid3_lyrics3
  • getid3_mp3
  • getid3_mpeg
  • getid3_quicktime
  • getid3_swf
  • GoogleMap
  • Googlemaps
  • googleVerifyOptions
  • hitcounter
  • HTML
  • htmlmetatags
  • http_auth
  • Image
  • image_effects
  • internal_deprecations
  • ipBlocker
  • jcarousel
  • jPlayer
  • jplayer_options
  • jquery_rating
  • JSMin
  • lib_GD_Options
  • lib_Imagick_Options
  • lib_NoGraphics
  • MediaObject
  • menu_manager
  • MergedRSS
  • MergedRSSOptions
  • mobile
  • Mobile_Detect
  • mobileTheme
  • multipleLayoutOptions
  • null_seo
  • OAuthConsumer
  • OAuthDataStore
  • OAuthRequest
  • OAuthServer
  • OAuthSignatureMethod
  • OAuthSignatureMethod_HMAC_SHA1
  • OAuthSignatureMethod_PLAINTEXT
  • OAuthSignatureMethod_RSA_SHA1
  • OAuthToken
  • OAuthUtil
  • pagedThumbsNav
  • pagedthumbsOptions
  • PclZip
  • PersistentObject
  • PHPMailer
  • PlainText
  • POP3
  • print_album_menu
  • pseudoPlayer
  • publishContent
  • quota_manager
  • reCaptcha
  • ReCaptchaResponse
  • register_user
  • rewriteRules
  • rewriteTokens
  • RSS
  • RSS_internal_deprecations
  • rss_options
  • search_statistics
  • SearchEngine
  • security_logger
  • seo_locale
  • Services_JSON
  • Services_JSON_Error
  • setupexternalFeed
  • setupRSS
  • show_not_loggedin
  • sitemap
  • slideshow
  • SMTP
  • static_html_cache
  • tagsuggest
  • TextObject
  • TextObject_internal_deprecations
  • TextObject_Options
  • ThemeObject
  • themeSwitcher
  • tinymce4Options
  • tinyURL
  • Transientimage
  • tweet
  • TwitterOAuth
  • UploadHandler
  • user_expiry
  • user_groups
  • user_logout_options
  • userAddressFields
  • utf8
  • Video
  • Video_internal_deprecations
  • VideoObject_Options
  • viewer_size_image_options
  • WEBdocs
  • WEBdocs_Options
  • xmpMetadata
  • Zenpage
  • Zenpage_internal_deprecations
  • ZenpageCategory
  • zenpagecms
  • ZenpageItems
  • ZenpageNews
  • ZenpagePage
  • ZenpageRoot
  • Zenphoto_Administrator
  • Zenphoto_Authority
  • zenphoto_org_news
  • zenphoto_seo
  • zenphotoDonate
  • ZipStream
  • zp_PHPMailer
  • zpCaptcha
  • zpFunctions
  • zpLegacySpam
  • zpMutex
  • zpSimpleSpam
  • zpTrivialSpam

Exceptions

  • BadFunctionCallException
  • BadMethodCallException
  • Exception
  • getid3_exception
  • JSMin_UnterminatedCommentException
  • JSMin_UnterminatedRegExpException
  • JSMin_UnterminatedStringException
  • LogicException
  • OAuthExcept
  • phpmailerException

Functions

  • __autoload
  • _escape_xref
  • _recaptcha_aes_encrypt
  • _recaptcha_aes_pad
  • _recaptcha_http_post
  • _recaptcha_mailhide_email_parts
  • _recaptcha_mailhide_urlbase64
  • _recaptcha_qsencode
  • accessAllAlbums
  • add_context
  • addalbumsToDatabase
  • addCategoriesToDatabase
  • addGeoCoord
  • addItem
  • addPagesToDatabase
  • addPluginScript
  • addPluginType
  • addSubalbumMenus
  • admin_album_list
  • admin_securityChecks
  • admin_showupdate
  • adminPageNav
  • adminToolbox
  • albumNumber
  • applyMacros
  • Auth_OpenID_arrangeByType
  • Auth_OpenID_AX_checkAlias
  • Auth_OpenID_AX_toTypeURIs
  • Auth_OpenID_bestMatchingService
  • Auth_OpenID_checkFieldName
  • Auth_OpenID_checkSessionType
  • Auth_OpenID_checkTimestamp
  • Auth_OpenID_detectMathLibrary
  • Auth_OpenID_discover
  • Auth_OpenID_discoverURI
  • Auth_OpenID_discoverWithoutYadis
  • Auth_OpenID_discoverWithYadis
  • Auth_OpenID_discoverXRI
  • Auth_OpenID_extractReturnURL
  • Auth_OpenID_findOPLocalIdentifier
  • Auth_OpenID_getAllAssociationTypes
  • Auth_OpenID_getAllowedReturnURLs
  • Auth_OpenID_getAuthorityPattern
  • Auth_OpenID_getAvailableSessionTypes
  • Auth_OpenID_getDefaultAssociationOrder
  • Auth_OpenID_getDefaultGen
  • Auth_OpenID_getDefaultMod
  • Auth_OpenID_getDefaultNegotiator
  • Auth_OpenID_getEncodedPattern
  • Auth_OpenID_getEncryptedNegotiator
  • Auth_OpenID_getEscapeRE
  • Auth_OpenID_getMathLib
  • Auth_OpenID_getOnlyEncryptedOrder
  • Auth_OpenID_getOpenIDConsumerTypeURIs
  • Auth_OpenID_getOpenIDTypeName
  • Auth_OpenID_getOpenIDTypeURIs
  • Auth_OpenID_getOPOrUserServices
  • Auth_OpenID_getSecretSize
  • Auth_OpenID_getSessionTypes
  • Auth_OpenID_getSupportedAssociationTypes
  • Auth_OpenID_getUnreserved
  • Auth_OpenID_getURIPattern
  • Auth_OpenID_getURLIllegalCharRE
  • Auth_OpenID_HMACSHA1
  • Auth_OpenID_HMACSHA256
  • Auth_OpenID_include_init
  • Auth_OpenID_isError
  • Auth_OpenID_isOpenID1
  • Auth_OpenID_legacy_discover
  • Auth_OpenID_makeOpenIDEndpoints
  • Auth_OpenID_math_extensions
  • Auth_OpenID_mkNonce
  • Auth_OpenID_noMathSupport
  • Auth_OpenID_pct_encoded_replace
  • Auth_OpenID_pct_encoded_replace_unreserved
  • Auth_OpenID_registerNamespaceAlias
  • Auth_OpenID_remove_dot_segments
  • Auth_OpenID_removeNamespaceAlias
  • Auth_OpenID_returnToMatches
  • Auth_OpenID_setNoMathSupport
  • Auth_OpenID_SHA1
  • Auth_OpenID_SHA256
  • Auth_OpenID_splitNonce
  • Auth_OpenID_supportsSReg
  • Auth_OpenID_urinorm
  • Auth_OpenID_verifyReturnTo
  • Auth_Yadis_array_scramble
  • Auth_Yadis_escapeForIRI
  • Auth_Yadis_getCanonicalID
  • Auth_Yadis_getDefaultProxy
  • Auth_Yadis_getEscapeRE
  • Auth_Yadis_getIPrivateChars
  • Auth_Yadis_getNSMap
  • Auth_Yadis_getServiceEndpoints
  • Auth_Yadis_getSupportedExtensions
  • Auth_Yadis_getUCSChars
  • Auth_Yadis_getXMLParser
  • Auth_Yadis_getXRDExpiration
  • Auth_Yadis_getXrefRE
  • Auth_Yadis_getXRIAuthorities
  • Auth_Yadis_identifierScheme
  • Auth_Yadis_iriToURI
  • Auth_Yadis_pct_escape_unicode
  • Auth_Yadis_providerIsAuthoritative
  • Auth_Yadis_rootAuthority
  • Auth_Yadis_setDefaultParser
  • Auth_Yadis_startswith
  • Auth_Yadis_toIRINormal
  • Auth_Yadis_toURINormal
  • Auth_Yadis_XRI
  • Auth_Yadis_XRIAppendArgs
  • authorSelector
  • build_query
  • build_url
  • bulkActionRedirect
  • bulkTags
  • byteConvert
  • cacheImage
  • checkAccess
  • checkAlbumimagesort
  • checkAlbumParentid
  • checkAlbumPassword
  • checkChosenItemStatus
  • checkChosenMenuset
  • checked
  • checkFolder
  • checkForEmptyTitle
  • checkForGuest
  • checkForPage
  • checkForPassword
  • checkForUpdate
  • checkHitcounterDisplay
  • checkIfChecked
  • checkIfLockedNews
  • checkIfLockedPage
  • checkIfNew
  • checkInstall
  • checkLayoutUseForImages
  • checkNewsAccess
  • checkNewsCategoryPassword
  • checkObjectsThumb
  • checkPagePassword
  • checkPageValidity
  • checkParentLayouts
  • checkPublishDates
  • checkRequiredField
  • checkSelectedAlbum
  • checkSignature
  • cleanAlbum
  • cleanHTML
  • clearSitemapCache
  • clonedFrom
  • codeblocktabsJS
  • comment_form_addComment
  • comment_form_handle_comment
  • comment_form_PaginationJS
  • comment_form_postcomment
  • comment_form_print10Most
  • comment_form_visualEditor
  • commentFormUseCaptcha
  • commentReply
  • commentsAllowed
  • consolidatedEditMessages
  • copyLayoutSelection
  • copyThemeDirectory
  • countArticles
  • countCombiNews
  • createMenuIfNotExists
  • createRelatedItemsResultArray
  • cron_starter
  • currentRelativeURL
  • customOptions
  • dateDiff
  • datepickerJS
  • dateTimeConvert
  • db_affected_rows
  • db_close
  • db_collation
  • db_connect
  • db_count
  • db_create
  • db_create_table
  • db_error
  • db_fetch_assoc
  • db_fetch_row
  • db_free_result
  • db_getSQLmode
  • db_insert_id
  • db_LIKE_escape
  • db_list_fields
  • db_name
  • db_num_rows
  • db_permissions
  • db_quote
  • db_setSQLmode
  • db_show
  • db_software
  • db_table_update
  • db_truncate_table
  • debug404
  • debugLog
  • debugLogBacktrace
  • debugLogVar
  • defaultCodeblocks_codebox
  • deleteArticle
  • deleteCategory
  • deleteItem
  • deleteLayoutSelection
  • deletePage
  • deleteThemeDirectory
  • detect_fetcher
  • detect_math
  • detect_query_corruption
  • detect_random
  • detect_stores
  • detect_xml
  • dircopy
  • displayError
  • doIncludes
  • elFinder_admin_tabs
  • elFinder_tinymce
  • enableExtension
  • escape
  • executeRSS
  • exitZP
  • exposeZenPhotoInformations
  • extensionEnabled
  • fetchComments
  • filesystemToInternal
  • filter_extractReturnURL
  • filter_MatchesAnyOpenIDConsumerType
  • filter_MatchesAnyOpenIDType
  • filterImageQuery
  • fix_path_redirect
  • formatList
  • fullText
  • galleryAlbumsPerPage
  • genAlbumList
  • generateCaptcha
  • generateLanguageList
  • generateListFromArray
  • generateListFromFiles
  • generateRadiobuttonsFromArray
  • generateSitemapCacheFile
  • generateSitemapIndexCacheFile
  • generateUnorderedListFromArray
  • get_AnyFile_suffixes
  • get_context
  • get_filterScript
  • get_instance
  • get_language_string
  • getAdminThumb
  • getAlbumArray
  • getAlbumBreadcrumb
  • getAlbumBreadcrumbAdmin
  • getAlbumCustomData
  • getAlbumData
  • getAlbumDate
  • getAlbumDesc
  • getAlbumFolder
  • getAlbumGeodata
  • getAlbumId
  • getAlbumInherited
  • getAlbumLinkURL
  • getAlbumLocation
  • getAlbumPage
  • getAlbumPlace
  • getAlbumStatistic
  • getAlbumThumb
  • getAlbumTitle
  • getAlbumURL
  • getAllAccessibleAlbums
  • getAllAlbums
  • getAllArticleDates
  • getAllCategories
  • getAllDates
  • getAllowedTags
  • getAllSubAlbumIDs
  • getAllSubalbums
  • getAllTagsCount
  • getAllTagsFromAlbum
  • getAllTagsFromAlbum_multi_unique
  • getAllTagsFromZenpage
  • getAllTagsUnique
  • getAllTranslations
  • getAnnotatedAlbumTitle
  • getAnnotatedImageTitle
  • getArticles
  • getAuthor
  • getBare
  • getBareAlbumDesc
  • getBareAlbumTitle
  • getBareGalleryDesc
  • getBareGalleryTitle
  • getBareImageDesc
  • getBareImageTitle
  • getBareNewsAlbumTitle
  • getBareNewsTitle
  • getBarePageTitle
  • getCategory
  • getCategoryID
  • getCategoryLink
  • getCategoryParentID
  • getCategorySortOrder
  • getCategoryTitle
  • getCheckboxState
  • getCodeblock
  • getCombiNews
  • getCommentAddress
  • getCommentAuthorEmail
  • getCommentAuthorLink
  • getCommentAuthorName
  • getCommentAuthorSite
  • getCommentBody
  • getCommentCount
  • getCommentDate
  • getCommentDateTime
  • getCommentErrors
  • getCommentsAllowed
  • getCommentStored
  • getCommentTime
  • getConsumer
  • getContentShorten
  • getCurrentMenuItem
  • getCurrentNewsArchive
  • getCurrentNewsCategory
  • getCurrentNewsCategoryID
  • getCurrentNewsCategoryParentID
  • getCurrentNewsPage
  • getCurrentPage
  • getCurrentTheme
  • getCustomAlbumThumb
  • getCustomAlbumThumbMaxSpace
  • getCustomImageURL
  • getCustomPageURL
  • getCustomSizedImageMaxSpace
  • getCustomSizedImageThumbMaxSpace
  • getDefaultHeight
  • getDefaultSizedImage
  • getDefaultWidth
  • getDownloadLink
  • getdownloadList
  • getDownloadURL
  • getE
  • getEnabledPlugins
  • getExpiryDatePost
  • getFavoritesURL
  • getField
  • getFirstImageURL
  • getFullHeight
  • getFullImageURL
  • getFullNewsImage
  • getFullWidth
  • getGalleryDesc
  • getGalleryIndexURL
  • getGalleryTitle
  • getGeoCoord
  • getHeadTitle
  • getHitcounter
  • getImageArgs
  • getImageCacheFilename
  • getImageCachePostfix
  • getImageCity
  • getImageCountry
  • getImageCustomData
  • getImageData
  • getImageDate
  • getImageDesc
  • getImageEXIFData
  • getImageGeodata
  • getImageID
  • getImageLinkURL
  • getImageLocation
  • getImageMetaData
  • getImageParameters
  • getImageProcessorURI
  • getImageProcessorURIFromCacheName
  • getImageRotation
  • getImageSortOrder
  • getImageState
  • getImageStatistic
  • getImageThumb
  • getImageTitle
  • getImageURI
  • getImageURL
  • getItem
  • getItemByID
  • getItemTitleAndURL
  • getjPlayerSkinCSS
  • getjPlayerSkins
  • getLanguageArray
  • getLanguageFlag
  • getLastImageURL
  • getLatestComments
  • getLatestNews
  • getLatestZenpageComments
  • getLayout
  • getLayoutSelector
  • getLink
  • getLinkHTML
  • getLogTabs
  • getMacros
  • getMainSiteName
  • getMainSiteURL
  • getManagedAlbumList
  • getMaxSpaceContainer
  • getMenuFromLink
  • getMenuItemChilds
  • getMenuItems
  • getMenumanagerPredicessor
  • getMenumanagerSuccessor
  • getMenuSetSelector
  • getMenuVisibility
  • getMimeString
  • getNestedAlbumList
  • getNewsAdminOption
  • getNewsAdminOptionPath
  • getNewsAlbumName
  • getNewsAlbumTitle
  • getNewsAlbumURL
  • getNewsArchivePath
  • getNewsArchiveURL
  • getNewsAuthor
  • getNewsCategories
  • getNewsCategoryCustomData
  • getNewsCategoryDesc
  • getNewsCategoryPath
  • getNewsCategoryURL
  • getNewsContent
  • getNewsContentShorten
  • getNewsCustomData
  • getNewsDate
  • getNewsExtraContent
  • getNewsID
  • getNewsImageTags
  • getNewsIndexURL
  • getNewsLink
  • getNewsPagesStatistic
  • getNewsPathNav
  • getNewsReadMore
  • getNewsTitle
  • getNewsTitleLink
  • getNewsTitlePath
  • getNewsType
  • getNewsURL
  • getNewsVideoContent
  • getNextAlbum
  • getNextAlbumURL
  • getNextImageThumb
  • getNextImageURL
  • getNextNewsPageURL
  • getNextNewsURL
  • getNextPageURL
  • getNextPrevNews
  • getNotViewableAlbums
  • getNotViewableImages
  • getNumAlbums
  • getNumAllSubalbums
  • getNumImages
  • getNumNews
  • getNumPages
  • getNumSubalbums
  • getOpenIDURL
  • getOption
  • getOptionFromDB
  • getOptionList
  • getPageAuthor
  • getPageContent
  • getPageCustomData
  • getPageDate
  • getPageExtraContent
  • getPageID
  • getPageLastChangeDate
  • getPageLinkPath
  • getPageLinkURL
  • getPageNavList
  • getPageNumURL
  • getPageParentID
  • getPageRedirect
  • getPages
  • getPageSelector
  • getPageSortorder
  • getPageTitle
  • getPageTitleLink
  • getPageURL
  • getParentAlbums
  • getParentAlbumsAdmin
  • getParentBreadcrumb
  • getParentItems
  • getParentMenuItems
  • getParentNewsCategories
  • getParentPages
  • getPasswordProtectImage
  • getPHPFiles
  • getPlugin
  • getPluginFiles
  • getPluginTabs
  • getPrevAlbum
  • getPrevAlbumURL
  • getPrevImageThumb
  • getPrevImageURL
  • getPrevNewsPageURL
  • getPrevNewsURL
  • getPrevPageURL
  • getProtectedImageURL
  • getRandomImages
  • getRandomImagesAlbum
  • getRating
  • getRelatedItems
  • getRequestURI
  • getReturnTo
  • getRSSHeaderLink
  • getRSSLink
  • getScheme
  • getSearchDate
  • getSearchURL
  • getSearchWords
  • getSelectedLayout
  • getSerializedArray
  • getSetClause
  • getSiteHomeURL
  • getSitemapAlbumList
  • getSitemapAlbums
  • getSitemapGoogleImageVideoExtras
  • getSitemapGoogleLoopIndex
  • getSitemapImages
  • getSitemapIndexLinks
  • getSitemapZenpageNewsArticles
  • getSitemapZenpageNewsCategories
  • getSitemapZenpageNewsIndex
  • getSitemapZenpagePages
  • getSizeCustomImage
  • getSizeDefaultImage
  • getSizeDefaultThumb
  • getSizedImageURL
  • getSizeFullImage
  • getStore
  • getSubCategories
  • getSubtabs
  • getSuffix
  • getTagCountByAccess
  • getTagOrder
  • getTags
  • gettext_pl
  • gettext_th
  • getTheme
  • getThemeFiles
  • getThemeOption
  • getTimezones
  • getTinyMCE4ConfigFiles
  • getTitle
  • getTotalArticles
  • getTotalImagesIn
  • getTotalNewsPages
  • getTotalPages
  • getTrustRoot
  • getUnprotectedImageURL
  • getUrAlbum
  • getURL
  • getUserIP
  • getUserLocale
  • getVersion
  • getViewerImageSize
  • getWatermarkParam
  • getWatermarkPath
  • getWatermarks
  • getWhereClause
  • getXSRFToken
  • getZenpageHitcounter
  • getZenpageRSSHeaderLink
  • getZenpageRSSLink
  • getZenpageStatistic
  • googleVerifyHead
  • handleSearchParms
  • hasDynamicAlbumSuffix
  • hasNextImage
  • hasNextPage
  • hasPrevImage
  • hasPrevPage
  • hitcounter
  • html_decode
  • html_encode
  • html_encodeTagged
  • httpsRedirect
  • httpUploadHandler
  • httpUploadHandler_admin_tabs
  • i18nSetLocale
  • imageBlurGD
  • imageDebug
  • imageError
  • imageNumber
  • imgSrcURI
  • in_context
  • inNewsCategory
  • inProtectedNewsCategory
  • installSignature
  • instrument
  • inSubNewsCategoryOf
  • internalToFilesystem
  • inventMenuItem
  • iptc_make_tag
  • is_AdminEditPage
  • is_connected
  • is_GalleryNewsType
  • is_News
  • is_NewsArchive
  • is_NewsArticle
  • is_NewsCategory
  • is_NewsPage
  • is_NewsType
  • is_Pages
  • is_valid_email_zp
  • is_valid_image
  • is_valid_other_type
  • is_zip
  • isAlbumClass
  • isAlbumPage
  • isArchive
  • isHandledAlbum
  • isImageClass
  • isImagePage
  • isImagePhoto
  • isImageVideo
  • isLandscape
  • isMyAlbum
  • isMyNews
  • isMyPage
  • isolate
  • isProtectedAlbum
  • isProtectedNewsCategory
  • isProtectedPage
  • isSubNewsCategoryOf
  • isValidURL
  • jQueryUpload_head
  • jQueryUpload_headers
  • jQueryUploadHandler
  • jQueryUploadHandler_admin_tabs
  • js_encode
  • json_decode
  • json_encode
  • kses
  • kses_array_lc
  • kses_attr
  • kses_bad_protocol
  • kses_bad_protocol_once
  • kses_bad_protocol_once2
  • kses_check_attr_val
  • kses_decode_entities
  • kses_hair
  • kses_hook
  • kses_html_error
  • kses_js_entities
  • kses_no_null
  • kses_normalize_entities
  • kses_normalize_entities2
  • kses_split
  • kses_split2
  • kses_stripslashes
  • kses_version
  • ksesProcess
  • layoutSelector
  • layoutSelector_album
  • listDBUses
  • listDirectoryFiles
  • listUses
  • load_zenpage_news
  • load_zenpage_pages
  • loadLocalOptions
  • log_message
  • lookupSortKey
  • macro_admin_tabs
  • macroList_show
  • makeAlbumCurrent
  • makeImageCurrent
  • makeSpecialImageName
  • markRelease_button
  • mb_strlen
  • mb_strpos
  • mb_strrpos
  • mb_strtolower
  • mb_strtoupper
  • mb_substr
  • mb_substr_count
  • menu_admin_toolbox_global
  • menu_tabs
  • minDiff
  • mkdir_recursive
  • my_truncate_string
  • myts_date
  • newAlbum
  • newImage
  • next_album
  • next_comment
  • next_image
  • next_news
  • next_page
  • ngettext_pl
  • ngettext_th
  • normalizeColumns
  • omsAdditions
  • openedForComments
  • parse_query
  • parse_size
  • parseAllowedTags
  • parseHttpAcceptLanguage
  • passAlbums
  • passImages
  • pathurlencode
  • PclZipUtilCopyBlock
  • PclZipUtilOptionText
  • PclZipUtilPathInclusion
  • PclZipUtilPathReduction
  • PclZipUtilRename
  • PclZipUtilTranslateWinPath
  • PHPMailerAutoload
  • populateManagedObjectsList
  • postAlbumSort
  • postIndexDecode
  • postIndexEncode
  • prefix
  • prepareAlbumPage
  • prepareCustomPage
  • prepareImagePage
  • prepareIndexPage
  • print404status
  • print_language_string_list
  • printAddToFavorites
  • printAdminFooter
  • printAdminHeader
  • printAdminRightsTable
  • printAdminToolbox
  • printAlbumBreadcrumb
  • printAlbumButtons
  • printAlbumCustomData
  • printAlbumData
  • printAlbumDate
  • printAlbumDesc
  • printAlbumEditForm
  • printAlbumEditRow
  • printAlbumLegend
  • printAlbumLink
  • printAlbumLocation
  • printAlbumMap
  • printAlbumMenu
  • printAlbumMenuJump
  • printAlbumMenuList
  • printAlbumMenuListAlbum
  • printAlbumPlace
  • printAlbumRating
  • printAlbumsSelector
  • printAlbumStatistic
  • printAlbumStatisticItem
  • printAlbumThumbImage
  • printAlbumTitle
  • printAlbumURL
  • printAlbumZip
  • printAllDates
  • printAllNewsCategories
  • printAllTags
  • printAllTagsAs
  • printAllTagsFromAlbum
  • printAllTagsFromZenpage
  • printAnnotatedAlbumTitle
  • printAnnotatedImageTitle
  • printArticleCategories
  • printArticleDatesDropdown
  • printArticlesPerPageDropdown
  • printBareAlbumDesc
  • printBareAlbumTitle
  • printBareGalleryDesc
  • printBareGalleryTitle
  • printBareImageDesc
  • printBareImageTitle
  • printBareNewsTitle
  • printBarePageTitle
  • printBulkActions
  • printCaptcha
  • printCategoriesStatistic
  • printCategoryCheckboxListEntry
  • printCategoryDropdown
  • printCategoryListSortableTable
  • printCategorySelection
  • printCodeblock
  • printCodeblockEdit
  • printCommentAuthorLink
  • printCommentErrors
  • printCommentForm
  • printContactForm
  • printCurrentNewsArchive
  • printCurrentNewsCategory
  • printCustomAlbumThumbImage
  • printCustomAlbumThumbMaxSpace
  • printCustomMenu
  • printCustomPageSelector
  • printCustomPageURL
  • printCustomSizedImage
  • printCustomSizedImageMaxHeight
  • printCustomSizedImageMaxSpace
  • printCustomSizedImageThumbMaxSpace
  • printDefaultSizedImage
  • printDownloadAlbumZipURL
  • printDownloadLink
  • printDownloadLinkAlbumZip
  • printdownloadList
  • printDownloadURL
  • printEditable
  • printEditCommentLink
  • printEditDropdown
  • printExpired
  • printFavoritesLink
  • printFavoritesURL
  • printField
  • printGalleryDesc
  • printGalleryIndexURL
  • printGalleryTitle
  • printGoogleMap
  • printHeadTitle
  • printHomeLink
  • printImageCustomData
  • printImageData
  • printImageDate
  • printImageDesc
  • printImageDiv
  • printImageEXIFData
  • printImageID
  • printImageLink
  • printImageMap
  • printImageMetadata
  • printImageRating
  • printImageSortOrder
  • printImageStatistic
  • printImageThumb
  • printImageTitle
  • printImageURL
  • printItemEditLink
  • printItemsList
  • printItemsListTable
  • printItemStatusDropdown
  • printjCarouselThumbNav
  • printjPlayerPlaylist
  • printLanguageSelector
  • printLatestAlbums
  • printLatestComments
  • printLatestImages
  • printLatestImagesByDate
  • printLatestImagesByMtime
  • printLatestNews
  • printLatestUpdatedAlbums
  • printLatestZenpageComments
  • printLink
  • printLinkHTML
  • printLogoAndLinks
  • printManagedObjects
  • printMenuemanagerPageList
  • printMenuemanagerPageListWithNav
  • printMenumanagerBreadcrumb
  • printMenumanagerNextLink
  • printMenumanagerPrevLink
  • printMostPopularItems
  • printMostRatedAlbums
  • printMostRatedImages
  • printMostRatedItems
  • printNestedAlbumsList
  • printNestedItemsList
  • printNestedMenu
  • printNews
  • printNewsArchive
  • printNewsAuthor
  • printNewsCategories
  • printNewsCategoryCustomData
  • printNewsCategoryDesc
  • printNewsCategoryURL
  • printNewsContent
  • printNewsCustomData
  • printNewsDate
  • printNewsExtraContent
  • printNewsImageTags
  • printNewsIndexURL
  • printNewsLink
  • printNewsPageList
  • printNewsPageListWithNav
  • printNewsReadMoreLink
  • printNewsStatistic
  • printNewsTitle
  • printNewsTitleLink
  • printNewsURL
  • printNextNewsLink
  • printNextNewsPageLink
  • printNextPageLink
  • printNextPageURL
  • printPageArticleTags
  • printPageAuthor
  • printPageContent
  • printPageCustomData
  • printPageDate
  • printPagedThumbsNav
  • printPageExtraContent
  • printPageID
  • printPageLastChangeDate
  • printPageLinkURL
  • printPageList
  • printPageListWithNav
  • printPageMenu
  • printPageNav
  • printPageSelector
  • printPagesListTable
  • printPagesStatistic
  • printPageTitle
  • printPageTitleLink
  • printPageURL
  • printParentBreadcrumb
  • printParentPagesBreadcrumb
  • printPasswordForm
  • printPopularAlbums
  • printPopularImages
  • printPreloadScript
  • printPrevNewsLink
  • printPrevNewsPageLink
  • printPrevPageLink
  • printPrevPageURL
  • printPublished
  • printPublishIconLink
  • printRandomImages
  • printRating
  • printRegisterURL
  • printRegistrationForm
  • printRelatedItems
  • printRSSHeaderLink
  • printRSSLink
  • printSearchBreadcrumb
  • printSearchForm
  • printSiteHomeURL
  • printSizedImageLink
  • printSizedImageURL
  • printSlideShow
  • printSlideShowJS
  • printSlideShowLink
  • printSortableHead
  • printSortOrderDropdown
  • printSubPagesExcerpts
  • printSubtabs
  • printTabs
  • printTags
  • printThumbNav
  • printTopRatedAlbums
  • printTopRatedImages
  • printTopRatedItems
  • printUnpublishedDropdown
  • printUserLogin_out
  • printUserSizeImage
  • printUserSizeSelector
  • printVersion
  • printZenJavascripts
  • printZenpageIconLegend
  • printZenpageItemsBreadcrumb
  • printZenpageNewsCategorySelector
  • printZenpagePagesSelector
  • printZenpageRSSHeaderLink
  • printZenpageRSSLink
  • printZenpageStatistic
  • printZenphotoLink
  • process_language_string_save
  • processAlbumBulkActions
  • processAlbumEdit
  • processCodeblockSave
  • processCommentBulkActions
  • processCredentials
  • processCustomOptionSave
  • processEditSelection
  • processExpired
  • processImageBulkActions
  • processImageEdit
  • processManagedObjects
  • processMenuBulkActions
  • processOrder
  • processRights
  • processTags
  • processZenpageBulkActions
  • propSizes
  • publishItem
  • purgeOption
  • query
  • query_full_array
  • query_single_row
  • rc4
  • read_exif_data_protected
  • readTags
  • recaptcha_check_answer
  • recaptcha_get_html
  • recaptcha_get_signup_url
  • recaptcha_mailhide_html
  • recaptcha_mailhide_url
  • reconfigureAction
  • reconfigureCS
  • reconfigurePage
  • recordMissing
  • rem_context
  • removeParentAlbumNames
  • resetCurrentAlbum
  • restore_context
  • reveal
  • rewrite_get_album_image
  • rewrite_path
  • rewrite_path_zenpage
  • RSS_Channel
  • RSS_Retrieve
  • RSS_Tags
  • rulesList
  • run
  • safe_fnmatch
  • safe_glob
  • sanitize
  • sanitize_numeric
  • sanitize_path
  • sanitize_script
  • sanitize_string
  • sanitizeRedirect
  • save_context
  • saveLayoutSelection
  • saveZenphotoLayoutSelection
  • search_quote
  • secureServer
  • seo_cleanup_button
  • seoFriendly
  • seoFriendlyJS
  • set_context
  • setAlbumCustomData
  • setAlbumSubtabs
  • setImageCustomData
  • setMainDomain
  • setOption
  • setOptionDefault
  • setPluginDomain
  • setThemeColumns
  • setThemeDomain
  • setThemeOption
  • setThemeOptionDefault
  • setupAllowedMaps
  • setupCurrentLocale
  • setupDomain
  • setupTheme
  • shortenContent
  • showOrNotShowField
  • shuffle_assoc
  • signatureChange
  • site_upgrade_button
  • site_upgrade_status
  • sitemap_echonl
  • sitemap_getChangefreq
  • sitemap_getDateformat
  • sitemap_getDBLimit
  • sitemap_getISO8601Date
  • skipScheduledPublishing
  • sortByKey
  • sortByMultilingual
  • sortMultiArray
  • standardScripts
  • standardThemeOptions
  • stickyNews
  • storeConfig
  • storeTags
  • stripSuffix
  • submenuOf
  • switchLog
  • tagSelector
  • tagSuggestJS
  • tagSuggestJS_admin
  • tagSuggestJS_frontend
  • themeIsEditable
  • themeSetup
  • timezoneDiff
  • tinymce4ConfigJS
  • truncate_string
  • unpublishedZenphotoItemCheck
  • unpublishSubalbums
  • unQuote
  • unzip
  • updateArticle
  • updateCacheName
  • updateCategory
  • updateConfigItem
  • updateItemSortorder
  • updateItemsSortorder
  • updateMenuItem
  • updatePage
  • upload_extra
  • upload_form
  • upload_head
  • user_mailing_list_button
  • validateLocale
  • wordpress_import_button
  • wp_prefix
  • wp_query_full_array
  • wpimport_TryAgainError
  • XSRFdefender
  • XSRFToken
  • zenJavascript
  • zenpageAlbumImage
  • zenpageBulkActionMessage
  • zenpageHitcounter
  • zenpageJSCSS
  • zenpageOpenedForComments
  • zenpagePublish
  • zenphoto_PHPMailer
  • zenphoto_sendmail
  • zenPhotoTheme
  • zp_apply_filter
  • zp_clearCookie
  • zp_colorAllocate
  • zp_cookieEncode
  • zp_copyCanvas
  • zp_createImage
  • zp_drawRectangle
  • zp_error
  • zp_filter_slot
  • zp_filter_unique_id
  • zp_getCookie
  • zp_getFonts
  • zp_graphicsLibInfo
  • zp_handle_password
  • zp_handle_password_single
  • zp_has_filter
  • zp_image_types
  • zp_imageCanRotate
  • zp_imageColorTransparent
  • zp_imageDims
  • zp_imageFill
  • zp_imageFontHeight
  • zp_imageFontWidth
  • zp_imageFromString
  • zp_imageGet
  • zp_imageGray
  • zp_imageHeight
  • zp_imageIPTC
  • zp_imageKill
  • zp_imageLoadFont
  • zp_imageMerge
  • zp_imageOutput
  • zp_imageResizeAlpha
  • zp_imageUnsharpMask
  • zp_imageWidth
  • zp_load_album
  • zp_load_gallery
  • zp_load_image
  • zp_load_page
  • zp_load_request
  • zp_load_search
  • zp_loggedin
  • zp_mail
  • zp_register_filter
  • zp_remove_filter
  • zp_resampleImage
  • zp_rotateImage
  • zp_session_start
  • zp_setCookie
  • zp_writeString
  • zpErrorHandler
  • zpFormattedDate
  • zpRewriteURL
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
   1: <?php
   2: /////////////////////////////////////////////////////////////////
   3: /// getID3() by James Heinrich <info@getid3.org>               //
   4: //  available at http://getid3.sourceforge.net                 //
   5: //            or http://www.getid3.org                         //
   6: //          also https://github.com/JamesHeinrich/getID3       //
   7: /////////////////////////////////////////////////////////////////
   8: // See readme.txt for more details                             //
   9: /////////////////////////////////////////////////////////////////
  10: ///                                                            //
  11: // module.tag.id3v2.php                                        //
  12: // module for analyzing ID3v2 tags                             //
  13: // dependencies: module.tag.id3v1.php                          //
  14: //                                                            ///
  15: /////////////////////////////////////////////////////////////////
  16: 
  17: getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
  18: 
  19: class getid3_id3v2 extends getid3_handler
  20: {
  21:     public $StartingOffset = 0;
  22: 
  23:     public function Analyze() {
  24:         $info = &$this->getid3->info;
  25: 
  26:         //    Overall tag structure:
  27:         //        +-----------------------------+
  28:         //        |      Header (10 bytes)      |
  29:         //        +-----------------------------+
  30:         //        |       Extended Header       |
  31:         //        | (variable length, OPTIONAL) |
  32:         //        +-----------------------------+
  33:         //        |   Frames (variable length)  |
  34:         //        +-----------------------------+
  35:         //        |           Padding           |
  36:         //        | (variable length, OPTIONAL) |
  37:         //        +-----------------------------+
  38:         //        | Footer (10 bytes, OPTIONAL) |
  39:         //        +-----------------------------+
  40: 
  41:         //    Header
  42:         //        ID3v2/file identifier      "ID3"
  43:         //        ID3v2 version              $04 00
  44:         //        ID3v2 flags                (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
  45:         //        ID3v2 size             4 * %0xxxxxxx
  46: 
  47: 
  48:         // shortcuts
  49:         $info['id3v2']['header'] = true;
  50:         $thisfile_id3v2                  = &$info['id3v2'];
  51:         $thisfile_id3v2['flags']         =  array();
  52:         $thisfile_id3v2_flags            = &$thisfile_id3v2['flags'];
  53: 
  54: 
  55:         $this->fseek($this->StartingOffset);
  56:         $header = $this->fread(10);
  57:         if (substr($header, 0, 3) == 'ID3'  &&  strlen($header) == 10) {
  58: 
  59:             $thisfile_id3v2['majorversion'] = ord($header{3});
  60:             $thisfile_id3v2['minorversion'] = ord($header{4});
  61: 
  62:             // shortcut
  63:             $id3v2_majorversion = &$thisfile_id3v2['majorversion'];
  64: 
  65:         } else {
  66: 
  67:             unset($info['id3v2']);
  68:             return false;
  69: 
  70:         }
  71: 
  72:         if ($id3v2_majorversion > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists)
  73: 
  74:             $info['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion'];
  75:             return false;
  76: 
  77:         }
  78: 
  79:         $id3_flags = ord($header{5});
  80:         switch ($id3v2_majorversion) {
  81:             case 2:
  82:                 // %ab000000 in v2.2
  83:                 $thisfile_id3v2_flags['unsynch']     = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
  84:                 $thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40); // b - Compression
  85:                 break;
  86: 
  87:             case 3:
  88:                 // %abc00000 in v2.3
  89:                 $thisfile_id3v2_flags['unsynch']     = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
  90:                 $thisfile_id3v2_flags['exthead']     = (bool) ($id3_flags & 0x40); // b - Extended header
  91:                 $thisfile_id3v2_flags['experim']     = (bool) ($id3_flags & 0x20); // c - Experimental indicator
  92:                 break;
  93: 
  94:             case 4:
  95:                 // %abcd0000 in v2.4
  96:                 $thisfile_id3v2_flags['unsynch']     = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
  97:                 $thisfile_id3v2_flags['exthead']     = (bool) ($id3_flags & 0x40); // b - Extended header
  98:                 $thisfile_id3v2_flags['experim']     = (bool) ($id3_flags & 0x20); // c - Experimental indicator
  99:                 $thisfile_id3v2_flags['isfooter']    = (bool) ($id3_flags & 0x10); // d - Footer present
 100:                 break;
 101:         }
 102: 
 103:         $thisfile_id3v2['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
 104: 
 105:         $thisfile_id3v2['tag_offset_start'] = $this->StartingOffset;
 106:         $thisfile_id3v2['tag_offset_end']   = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
 107: 
 108: 
 109: 
 110:         // create 'encoding' key - used by getid3::HandleAllTags()
 111:         // in ID3v2 every field can have it's own encoding type
 112:         // so force everything to UTF-8 so it can be handled consistantly
 113:         $thisfile_id3v2['encoding'] = 'UTF-8';
 114: 
 115: 
 116:     //    Frames
 117: 
 118:     //        All ID3v2 frames consists of one frame header followed by one or more
 119:     //        fields containing the actual information. The header is always 10
 120:     //        bytes and laid out as follows:
 121:     //
 122:     //        Frame ID      $xx xx xx xx  (four characters)
 123:     //        Size      4 * %0xxxxxxx
 124:     //        Flags         $xx xx
 125: 
 126:         $sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header
 127:         if (!empty($thisfile_id3v2['exthead']['length'])) {
 128:             $sizeofframes -= ($thisfile_id3v2['exthead']['length'] + 4);
 129:         }
 130:         if (!empty($thisfile_id3v2_flags['isfooter'])) {
 131:             $sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
 132:         }
 133:         if ($sizeofframes > 0) {
 134: 
 135:             $framedata = $this->fread($sizeofframes); // read all frames from file into $framedata variable
 136: 
 137:             //    if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
 138:             if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) {
 139:                 $framedata = $this->DeUnsynchronise($framedata);
 140:             }
 141:             //        [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
 142:             //        of on tag level, making it easier to skip frames, increasing the streamability
 143:             //        of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
 144:             //        there exists an unsynchronised frame, while the new unsynchronisation flag in
 145:             //        the frame header [S:4.1.2] indicates unsynchronisation.
 146: 
 147: 
 148:             //$framedataoffset = 10 + ($thisfile_id3v2['exthead']['length'] ? $thisfile_id3v2['exthead']['length'] + 4 : 0); // how many bytes into the stream - start from after the 10-byte header (and extended header length+4, if present)
 149:             $framedataoffset = 10; // how many bytes into the stream - start from after the 10-byte header
 150: 
 151: 
 152:             //    Extended Header
 153:             if (!empty($thisfile_id3v2_flags['exthead'])) {
 154:                 $extended_header_offset = 0;
 155: 
 156:                 if ($id3v2_majorversion == 3) {
 157: 
 158:                     // v2.3 definition:
 159:                     //Extended header size  $xx xx xx xx   // 32-bit integer
 160:                     //Extended Flags        $xx xx
 161:                     //     %x0000000 %00000000 // v2.3
 162:                     //     x - CRC data present
 163:                     //Size of padding       $xx xx xx xx
 164: 
 165:                     $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), 0);
 166:                     $extended_header_offset += 4;
 167: 
 168:                     $thisfile_id3v2['exthead']['flag_bytes'] = 2;
 169:                     $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
 170:                     $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
 171: 
 172:                     $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x8000);
 173: 
 174:                     $thisfile_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
 175:                     $extended_header_offset += 4;
 176: 
 177:                     if ($thisfile_id3v2['exthead']['flags']['crc']) {
 178:                         $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
 179:                         $extended_header_offset += 4;
 180:                     }
 181:                     $extended_header_offset += $thisfile_id3v2['exthead']['padding_size'];
 182: 
 183:                 } elseif ($id3v2_majorversion == 4) {
 184: 
 185:                     // v2.4 definition:
 186:                     //Extended header size   4 * %0xxxxxxx // 28-bit synchsafe integer
 187:                     //Number of flag bytes       $01
 188:                     //Extended Flags             $xx
 189:                     //     %0bcd0000 // v2.4
 190:                     //     b - Tag is an update
 191:                     //         Flag data length       $00
 192:                     //     c - CRC data present
 193:                     //         Flag data length       $05
 194:                     //         Total frame CRC    5 * %0xxxxxxx
 195:                     //     d - Tag restrictions
 196:                     //         Flag data length       $01
 197: 
 198:                     $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), true);
 199:                     $extended_header_offset += 4;
 200: 
 201:                     $thisfile_id3v2['exthead']['flag_bytes'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should always be 1
 202:                     $extended_header_offset += 1;
 203: 
 204:                     $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
 205:                     $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
 206: 
 207:                     $thisfile_id3v2['exthead']['flags']['update']       = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x40);
 208:                     $thisfile_id3v2['exthead']['flags']['crc']          = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x20);
 209:                     $thisfile_id3v2['exthead']['flags']['restrictions'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x10);
 210: 
 211:                     if ($thisfile_id3v2['exthead']['flags']['update']) {
 212:                         $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 0
 213:                         $extended_header_offset += 1;
 214:                     }
 215: 
 216:                     if ($thisfile_id3v2['exthead']['flags']['crc']) {
 217:                         $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 5
 218:                         $extended_header_offset += 1;
 219:                         $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $ext_header_chunk_length), true, false);
 220:                         $extended_header_offset += $ext_header_chunk_length;
 221:                     }
 222: 
 223:                     if ($thisfile_id3v2['exthead']['flags']['restrictions']) {
 224:                         $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 1
 225:                         $extended_header_offset += 1;
 226: 
 227:                         // %ppqrrstt
 228:                         $restrictions_raw = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
 229:                         $extended_header_offset += 1;
 230:                         $thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']  = ($restrictions_raw & 0xC0) >> 6; // p - Tag size restrictions
 231:                         $thisfile_id3v2['exthead']['flags']['restrictions']['textenc']  = ($restrictions_raw & 0x20) >> 5; // q - Text encoding restrictions
 232:                         $thisfile_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw & 0x18) >> 3; // r - Text fields size restrictions
 233:                         $thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']   = ($restrictions_raw & 0x04) >> 2; // s - Image encoding restrictions
 234:                         $thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']  = ($restrictions_raw & 0x03) >> 0; // t - Image size restrictions
 235: 
 236:                         $thisfile_id3v2['exthead']['flags']['restrictions_text']['tagsize']  = $this->LookupExtendedHeaderRestrictionsTagSizeLimits($thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']);
 237:                         $thisfile_id3v2['exthead']['flags']['restrictions_text']['textenc']  = $this->LookupExtendedHeaderRestrictionsTextEncodings($thisfile_id3v2['exthead']['flags']['restrictions']['textenc']);
 238:                         $thisfile_id3v2['exthead']['flags']['restrictions_text']['textsize'] = $this->LookupExtendedHeaderRestrictionsTextFieldSize($thisfile_id3v2['exthead']['flags']['restrictions']['textsize']);
 239:                         $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgenc']   = $this->LookupExtendedHeaderRestrictionsImageEncoding($thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']);
 240:                         $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgsize']  = $this->LookupExtendedHeaderRestrictionsImageSizeSize($thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']);
 241:                     }
 242: 
 243:                     if ($thisfile_id3v2['exthead']['length'] != $extended_header_offset) {
 244:                         $info['warning'][] = 'ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')';
 245:                     }
 246:                 }
 247: 
 248:                 $framedataoffset += $extended_header_offset;
 249:                 $framedata = substr($framedata, $extended_header_offset);
 250:             } // end extended header
 251: 
 252: 
 253:             while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse
 254:                 if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) {
 255:                     // insufficient room left in ID3v2 header for actual data - must be padding
 256:                     $thisfile_id3v2['padding']['start']  = $framedataoffset;
 257:                     $thisfile_id3v2['padding']['length'] = strlen($framedata);
 258:                     $thisfile_id3v2['padding']['valid']  = true;
 259:                     for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) {
 260:                         if ($framedata{$i} != "\x00") {
 261:                             $thisfile_id3v2['padding']['valid'] = false;
 262:                             $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
 263:                             $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
 264:                             break;
 265:                         }
 266:                     }
 267:                     break; // skip rest of ID3v2 header
 268:                 }
 269:                 if ($id3v2_majorversion == 2) {
 270:                     // Frame ID  $xx xx xx (three characters)
 271:                     // Size      $xx xx xx (24-bit integer)
 272:                     // Flags     $xx xx
 273: 
 274:                     $frame_header = substr($framedata, 0, 6); // take next 6 bytes for header
 275:                     $framedata    = substr($framedata, 6);    // and leave the rest in $framedata
 276:                     $frame_name   = substr($frame_header, 0, 3);
 277:                     $frame_size   = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3), 0);
 278:                     $frame_flags  = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs
 279: 
 280:                 } elseif ($id3v2_majorversion > 2) {
 281: 
 282:                     // Frame ID  $xx xx xx xx (four characters)
 283:                     // Size      $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
 284:                     // Flags     $xx xx
 285: 
 286:                     $frame_header = substr($framedata, 0, 10); // take next 10 bytes for header
 287:                     $framedata    = substr($framedata, 10);    // and leave the rest in $framedata
 288: 
 289:                     $frame_name = substr($frame_header, 0, 4);
 290:                     if ($id3v2_majorversion == 3) {
 291:                         $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
 292:                     } else { // ID3v2.4+
 293:                         $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 1); // 32-bit synchsafe integer (28-bit value)
 294:                     }
 295: 
 296:                     if ($frame_size < (strlen($framedata) + 4)) {
 297:                         $nextFrameID = substr($framedata, $frame_size, 4);
 298:                         if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion)) {
 299:                             // next frame is OK
 300:                         } elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) {
 301:                             // MP3ext known broken frames - "ok" for the purposes of this test
 302:                         } elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) {
 303:                             $info['warning'][] = 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3';
 304:                             $id3v2_majorversion = 3;
 305:                             $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
 306:                         }
 307:                     }
 308: 
 309: 
 310:                     $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2));
 311:                 }
 312: 
 313:                 if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) {
 314:                     // padding encountered
 315: 
 316:                     $thisfile_id3v2['padding']['start']  = $framedataoffset;
 317:                     $thisfile_id3v2['padding']['length'] = strlen($frame_header) + strlen($framedata);
 318:                     $thisfile_id3v2['padding']['valid']  = true;
 319: 
 320:                     $len = strlen($framedata);
 321:                     for ($i = 0; $i < $len; $i++) {
 322:                         if ($framedata{$i} != "\x00") {
 323:                             $thisfile_id3v2['padding']['valid'] = false;
 324:                             $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
 325:                             $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
 326:                             break;
 327:                         }
 328:                     }
 329:                     break; // skip rest of ID3v2 header
 330:                 }
 331: 
 332:                 if ($frame_name == 'COM ') {
 333:                     $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]';
 334:                     $frame_name = 'COMM';
 335:                 }
 336:                 if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
 337: 
 338:                     unset($parsedFrame);
 339:                     $parsedFrame['frame_name']      = $frame_name;
 340:                     $parsedFrame['frame_flags_raw'] = $frame_flags;
 341:                     $parsedFrame['data']            = substr($framedata, 0, $frame_size);
 342:                     $parsedFrame['datalength']      = getid3_lib::CastAsInt($frame_size);
 343:                     $parsedFrame['dataoffset']      = $framedataoffset;
 344: 
 345:                     $this->ParseID3v2Frame($parsedFrame);
 346:                     $thisfile_id3v2[$frame_name][] = $parsedFrame;
 347: 
 348:                     $framedata = substr($framedata, $frame_size);
 349: 
 350:                 } else { // invalid frame length or FrameID
 351: 
 352:                     if ($frame_size <= strlen($framedata)) {
 353: 
 354:                         if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion)) {
 355: 
 356:                             // next frame is valid, just skip the current frame
 357:                             $framedata = substr($framedata, $frame_size);
 358:                             $info['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.';
 359: 
 360:                         } else {
 361: 
 362:                             // next frame is invalid too, abort processing
 363:                             //unset($framedata);
 364:                             $framedata = null;
 365:                             $info['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.';
 366: 
 367:                         }
 368: 
 369:                     } elseif ($frame_size == strlen($framedata)) {
 370: 
 371:                         // this is the last frame, just skip
 372:                         $info['warning'][] = 'This was the last ID3v2 frame.';
 373: 
 374:                     } else {
 375: 
 376:                         // next frame is invalid too, abort processing
 377:                         //unset($framedata);
 378:                         $framedata = null;
 379:                         $info['warning'][] = 'Invalid ID3v2 frame size, aborting.';
 380: 
 381:                     }
 382:                     if (!$this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)) {
 383: 
 384:                         switch ($frame_name) {
 385:                             case "\x00\x00".'MP':
 386:                             case "\x00".'MP3':
 387:                             case ' MP3':
 388:                             case 'MP3e':
 389:                             case "\x00".'MP':
 390:                             case ' MP':
 391:                             case 'MP3':
 392:                                 $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]';
 393:                                 break;
 394: 
 395:                             default:
 396:                                 $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).';
 397:                                 break;
 398:                         }
 399: 
 400:                     } elseif (!isset($framedata) || ($frame_size > strlen($framedata))) {
 401: 
 402:                         $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.(isset($framedata) ? strlen($framedata) : 'null').')).';
 403: 
 404:                     } else {
 405: 
 406:                         $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).';
 407: 
 408:                     }
 409: 
 410:                 }
 411:                 $framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion));
 412: 
 413:             }
 414: 
 415:         }
 416: 
 417: 
 418:     //    Footer
 419: 
 420:     //    The footer is a copy of the header, but with a different identifier.
 421:     //        ID3v2 identifier           "3DI"
 422:     //        ID3v2 version              $04 00
 423:     //        ID3v2 flags                %abcd0000
 424:     //        ID3v2 size             4 * %0xxxxxxx
 425: 
 426:         if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
 427:             $footer = $this->fread(10);
 428:             if (substr($footer, 0, 3) == '3DI') {
 429:                 $thisfile_id3v2['footer'] = true;
 430:                 $thisfile_id3v2['majorversion_footer'] = ord($footer{3});
 431:                 $thisfile_id3v2['minorversion_footer'] = ord($footer{4});
 432:             }
 433:             if ($thisfile_id3v2['majorversion_footer'] <= 4) {
 434:                 $id3_flags = ord(substr($footer{5}));
 435:                 $thisfile_id3v2_flags['unsynch_footer']  = (bool) ($id3_flags & 0x80);
 436:                 $thisfile_id3v2_flags['extfoot_footer']  = (bool) ($id3_flags & 0x40);
 437:                 $thisfile_id3v2_flags['experim_footer']  = (bool) ($id3_flags & 0x20);
 438:                 $thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10);
 439: 
 440:                 $thisfile_id3v2['footerlength'] = getid3_lib::BigEndian2Int(substr($footer, 6, 4), 1);
 441:             }
 442:         } // end footer
 443: 
 444:         if (isset($thisfile_id3v2['comments']['genre'])) {
 445:             $genres = array();
 446:             foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) {
 447:                 foreach ($this->ParseID3v2GenreString($value) as $genre) {
 448:                     $genres[] = $genre;
 449:                 }
 450:             }
 451:             $thisfile_id3v2['comments']['genre'] = array_unique($genres);
 452:             unset($key, $value, $genres, $genre);
 453:         }
 454: 
 455:         if (isset($thisfile_id3v2['comments']['track'])) {
 456:             foreach ($thisfile_id3v2['comments']['track'] as $key => $value) {
 457:                 if (strstr($value, '/')) {
 458:                     list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);
 459:                 }
 460:             }
 461:         }
 462: 
 463:         if (!isset($thisfile_id3v2['comments']['year']) && !empty($thisfile_id3v2['comments']['recording_time'][0]) && preg_match('#^([0-9]{4})#', trim($thisfile_id3v2['comments']['recording_time'][0]), $matches)) {
 464:             $thisfile_id3v2['comments']['year'] = array($matches[1]);
 465:         }
 466: 
 467: 
 468:         if (!empty($thisfile_id3v2['TXXX'])) {
 469:             // MediaMonkey does this, maybe others: write a blank RGAD frame, but put replay-gain adjustment values in TXXX frames
 470:             foreach ($thisfile_id3v2['TXXX'] as $txxx_array) {
 471:                 switch ($txxx_array['description']) {
 472:                     case 'replaygain_track_gain':
 473:                         if (empty($info['replay_gain']['track']['adjustment']) && !empty($txxx_array['data'])) {
 474:                             $info['replay_gain']['track']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
 475:                         }
 476:                         break;
 477:                     case 'replaygain_track_peak':
 478:                         if (empty($info['replay_gain']['track']['peak']) && !empty($txxx_array['data'])) {
 479:                             $info['replay_gain']['track']['peak'] = floatval($txxx_array['data']);
 480:                         }
 481:                         break;
 482:                     case 'replaygain_album_gain':
 483:                         if (empty($info['replay_gain']['album']['adjustment']) && !empty($txxx_array['data'])) {
 484:                             $info['replay_gain']['album']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
 485:                         }
 486:                         break;
 487:                 }
 488:             }
 489:         }
 490: 
 491: 
 492:         // Set avdataoffset
 493:         $info['avdataoffset'] = $thisfile_id3v2['headerlength'];
 494:         if (isset($thisfile_id3v2['footer'])) {
 495:             $info['avdataoffset'] += 10;
 496:         }
 497: 
 498:         return true;
 499:     }
 500: 
 501: 
 502:     public function ParseID3v2GenreString($genrestring) {
 503:         // Parse genres into arrays of genreName and genreID
 504:         // ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)'
 505:         // ID3v2.4.x: '21' $00 'Eurodisco' $00
 506:         $clean_genres = array();
 507:         if (strpos($genrestring, "\x00") === false) {
 508:             $genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring);
 509:         }
 510: 
 511:         // note: MusicBrainz Picard incorrectly stores plaintext genres separated by "/" when writing in ID3v2.3 mode, hack-fix here:
 512:         // replace / with NULL, then replace back the two ID3v1 genres that legitimately have "/" as part of the single genre name
 513:         $genrestring = str_replace('/', "\x00", $genrestring);
 514:         $genrestring = str_replace('Pop'."\x00".'Funk', 'Pop/Funk', $genrestring);
 515:         $genrestring = str_replace('Rock'."\x00".'Rock', 'Folk/Rock', $genrestring);
 516: 
 517:         // some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal"
 518:         $genrestring = str_replace(';', "\x00", $genrestring);
 519: 
 520:         $genre_elements = explode("\x00", $genrestring);
 521:         foreach ($genre_elements as $element) {
 522:             $element = trim($element);
 523:             if ($element) {
 524:                 if (preg_match('#^[0-9]{1,3}#', $element)) {
 525:                     $clean_genres[] = getid3_id3v1::LookupGenreName($element);
 526:                 } else {
 527:                     $clean_genres[] = str_replace('((', '(', $element);
 528:                 }
 529:             }
 530:         }
 531:         return $clean_genres;
 532:     }
 533: 
 534: 
 535:     public function ParseID3v2Frame(&$parsedFrame) {
 536: 
 537:         // shortcuts
 538:         $info = &$this->getid3->info;
 539:         $id3v2_majorversion = $info['id3v2']['majorversion'];
 540: 
 541:         $parsedFrame['framenamelong']  = $this->FrameNameLongLookup($parsedFrame['frame_name']);
 542:         if (empty($parsedFrame['framenamelong'])) {
 543:             unset($parsedFrame['framenamelong']);
 544:         }
 545:         $parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']);
 546:         if (empty($parsedFrame['framenameshort'])) {
 547:             unset($parsedFrame['framenameshort']);
 548:         }
 549: 
 550:         if ($id3v2_majorversion >= 3) { // frame flags are not part of the ID3v2.2 standard
 551:             if ($id3v2_majorversion == 3) {
 552:                 //    Frame Header Flags
 553:                 //    %abc00000 %ijk00000
 554:                 $parsedFrame['flags']['TagAlterPreservation']  = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation
 555:                 $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // b - File alter preservation
 556:                 $parsedFrame['flags']['ReadOnly']              = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // c - Read only
 557:                 $parsedFrame['flags']['compression']           = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080); // i - Compression
 558:                 $parsedFrame['flags']['Encryption']            = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // j - Encryption
 559:                 $parsedFrame['flags']['GroupingIdentity']      = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020); // k - Grouping identity
 560: 
 561:             } elseif ($id3v2_majorversion == 4) {
 562:                 //    Frame Header Flags
 563:                 //    %0abc0000 %0h00kmnp
 564:                 $parsedFrame['flags']['TagAlterPreservation']  = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation
 565:                 $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // b - File alter preservation
 566:                 $parsedFrame['flags']['ReadOnly']              = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000); // c - Read only
 567:                 $parsedFrame['flags']['GroupingIdentity']      = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // h - Grouping identity
 568:                 $parsedFrame['flags']['compression']           = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008); // k - Compression
 569:                 $parsedFrame['flags']['Encryption']            = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004); // m - Encryption
 570:                 $parsedFrame['flags']['Unsynchronisation']     = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation
 571:                 $parsedFrame['flags']['DataLengthIndicator']   = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001); // p - Data length indicator
 572: 
 573:                 // Frame-level de-unsynchronisation - ID3v2.4
 574:                 if ($parsedFrame['flags']['Unsynchronisation']) {
 575:                     $parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']);
 576:                 }
 577: 
 578:                 if ($parsedFrame['flags']['DataLengthIndicator']) {
 579:                     $parsedFrame['data_length_indicator'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4), 1);
 580:                     $parsedFrame['data']                  =                           substr($parsedFrame['data'], 4);
 581:                 }
 582:             }
 583: 
 584:             //    Frame-level de-compression
 585:             if ($parsedFrame['flags']['compression']) {
 586:                 $parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4));
 587:                 if (!function_exists('gzuncompress')) {
 588:                     $info['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"';
 589:                 } else {
 590:                     if ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) {
 591:                     //if ($decompresseddata = @gzuncompress($parsedFrame['data'])) {
 592:                         $parsedFrame['data'] = $decompresseddata;
 593:                         unset($decompresseddata);
 594:                     } else {
 595:                         $info['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"';
 596:                     }
 597:                 }
 598:             }
 599:         }
 600: 
 601:         if (!empty($parsedFrame['flags']['DataLengthIndicator'])) {
 602:             if ($parsedFrame['data_length_indicator'] != strlen($parsedFrame['data'])) {
 603:                 $info['warning'][] = 'ID3v2 frame "'.$parsedFrame['frame_name'].'" should be '.$parsedFrame['data_length_indicator'].' bytes long according to DataLengthIndicator, but found '.strlen($parsedFrame['data']).' bytes of data';
 604:             }
 605:         }
 606: 
 607:         if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0)) {
 608: 
 609:             $warning = 'Frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset'].' has no data portion';
 610:             switch ($parsedFrame['frame_name']) {
 611:                 case 'WCOM':
 612:                     $warning .= ' (this is known to happen with files tagged by RioPort)';
 613:                     break;
 614: 
 615:                 default:
 616:                     break;
 617:             }
 618:             $info['warning'][] = $warning;
 619: 
 620:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1   UFID Unique file identifier
 621:             (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI'))) {  // 4.1   UFI  Unique file identifier
 622:             //   There may be more than one 'UFID' frame in a tag,
 623:             //   but only one with the same 'Owner identifier'.
 624:             // <Header for 'Unique file identifier', ID: 'UFID'>
 625:             // Owner identifier        <text string> $00
 626:             // Identifier              <up to 64 bytes binary data>
 627:             $exploded = explode("\x00", $parsedFrame['data'], 2);
 628:             $parsedFrame['ownerid'] = (isset($exploded[0]) ? $exploded[0] : '');
 629:             $parsedFrame['data']    = (isset($exploded[1]) ? $exploded[1] : '');
 630: 
 631:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame
 632:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX'))) {    // 4.2.2 TXX  User defined text information frame
 633:             //   There may be more than one 'TXXX' frame in each tag,
 634:             //   but only one with the same description.
 635:             // <Header for 'User defined text information frame', ID: 'TXXX'>
 636:             // Text encoding     $xx
 637:             // Description       <text string according to encoding> $00 (00)
 638:             // Value             <text string according to encoding>
 639: 
 640:             $frame_offset = 0;
 641:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
 642:             $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
 643:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
 644:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
 645:                 $frame_textencoding_terminator = "\x00";
 646:             }
 647:             $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
 648:             if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
 649:                 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
 650:             }
 651:             $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
 652:             if (ord($frame_description) === 0) {
 653:                 $frame_description = '';
 654:             }
 655:             $parsedFrame['encodingid']  = $frame_textencoding;
 656:             $parsedFrame['encoding']    = $this->TextEncodingNameLookup($frame_textencoding);
 657: 
 658:             $parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $frame_description));
 659:             $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
 660:             if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
 661:                 $commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
 662:                 if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
 663:                     $info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
 664:                 } else {
 665:                     $info['id3v2']['comments'][$parsedFrame['framenameshort']][]            = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
 666:                 }
 667:             }
 668:             //unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain
 669: 
 670: 
 671:         } elseif ($parsedFrame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame
 672:             //   There may only be one text information frame of its kind in an tag.
 673:             // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
 674:             // excluding 'TXXX' described in 4.2.6.>
 675:             // Text encoding                $xx
 676:             // Information                  <text string(s) according to encoding>
 677: 
 678:             $frame_offset = 0;
 679:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
 680:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
 681:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
 682:             }
 683: 
 684:             $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
 685: 
 686:             $parsedFrame['encodingid'] = $frame_textencoding;
 687:             $parsedFrame['encoding']   = $this->TextEncodingNameLookup($frame_textencoding);
 688: 
 689:             if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
 690:                 // ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with /
 691:                 // This of course breaks when an artist name contains slash character, e.g. "AC/DC"
 692:                 // MP3tag (maybe others) implement alternative system where multiple artists are null-separated, which makes more sense
 693:                 // getID3 will split null-separated artists into multiple artists and leave slash-separated ones to the user
 694:                 switch ($parsedFrame['encoding']) {
 695:                     case 'UTF-16':
 696:                     case 'UTF-16BE':
 697:                     case 'UTF-16LE':
 698:                         $wordsize = 2;
 699:                         break;
 700:                     case 'ISO-8859-1':
 701:                     case 'UTF-8':
 702:                     default:
 703:                         $wordsize = 1;
 704:                         break;
 705:                 }
 706:                 $Txxx_elements = array();
 707:                 $Txxx_elements_start_offset = 0;
 708:                 for ($i = 0; $i < strlen($parsedFrame['data']); $i += $wordsize) {
 709:                     if (substr($parsedFrame['data'], $i, $wordsize) == str_repeat("\x00", $wordsize)) {
 710:                         $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
 711:                         $Txxx_elements_start_offset = $i + $wordsize;
 712:                     }
 713:                 }
 714:                 $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
 715:                 foreach ($Txxx_elements as $Txxx_element) {
 716:                     $string = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $Txxx_element);
 717:                     if (!empty($string)) {
 718:                         $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $string;
 719:                     }
 720:                 }
 721:                 unset($string, $wordsize, $i, $Txxx_elements, $Txxx_element, $Txxx_elements_start_offset);
 722:             }
 723: 
 724:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame
 725:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX'))) {    // 4.3.2 WXX  User defined URL link frame
 726:             //   There may be more than one 'WXXX' frame in each tag,
 727:             //   but only one with the same description
 728:             // <Header for 'User defined URL link frame', ID: 'WXXX'>
 729:             // Text encoding     $xx
 730:             // Description       <text string according to encoding> $00 (00)
 731:             // URL               <text string>
 732: 
 733:             $frame_offset = 0;
 734:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
 735:             $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
 736:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
 737:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
 738:                 $frame_textencoding_terminator = "\x00";
 739:             }
 740:             $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
 741:             if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
 742:                 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
 743:             }
 744:             $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
 745: 
 746:             if (ord($frame_description) === 0) {
 747:                 $frame_description = '';
 748:             }
 749:             $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
 750: 
 751:             $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator);
 752:             if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
 753:                 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
 754:             }
 755:             if ($frame_terminatorpos) {
 756:                 // there are null bytes after the data - this is not according to spec
 757:                 // only use data up to first null byte
 758:                 $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);
 759:             } else {
 760:                 // no null bytes following data, just use all data
 761:                 $frame_urldata = (string) $parsedFrame['data'];
 762:             }
 763: 
 764:             $parsedFrame['encodingid']  = $frame_textencoding;
 765:             $parsedFrame['encoding']    = $this->TextEncodingNameLookup($frame_textencoding);
 766: 
 767:             $parsedFrame['url']         = $frame_urldata;
 768:             $parsedFrame['description'] = $frame_description;
 769:             if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
 770:                 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['url']);
 771:             }
 772:             unset($parsedFrame['data']);
 773: 
 774: 
 775:         } elseif ($parsedFrame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames
 776:             //   There may only be one URL link frame of its kind in a tag,
 777:             //   except when stated otherwise in the frame description
 778:             // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
 779:             // described in 4.3.2.>
 780:             // URL              <text string>
 781: 
 782:             $parsedFrame['url'] = trim($parsedFrame['data']);
 783:             if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
 784:                 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url'];
 785:             }
 786:             unset($parsedFrame['data']);
 787: 
 788: 
 789:         } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) || // 4.4  IPLS Involved people list (ID3v2.3 only)
 790:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL'))) {     // 4.4  IPL  Involved people list (ID3v2.2 only)
 791:             // http://id3.org/id3v2.3.0#sec4.4
 792:             //   There may only be one 'IPL' frame in each tag
 793:             // <Header for 'User defined URL link frame', ID: 'IPL'>
 794:             // Text encoding     $xx
 795:             // People list strings    <textstrings>
 796: 
 797:             $frame_offset = 0;
 798:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
 799:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
 800:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
 801:             }
 802:             $parsedFrame['encodingid'] = $frame_textencoding;
 803:             $parsedFrame['encoding']   = $this->TextEncodingNameLookup($parsedFrame['encodingid']);
 804:             $parsedFrame['data_raw']   = (string) substr($parsedFrame['data'], $frame_offset);
 805: 
 806:             // http://www.getid3.org/phpBB3/viewtopic.php?t=1369
 807:             // "this tag typically contains null terminated strings, which are associated in pairs"
 808:             // "there are users that use the tag incorrectly"
 809:             $IPLS_parts = array();
 810:             if (strpos($parsedFrame['data_raw'], "\x00") !== false) {
 811:                 $IPLS_parts_unsorted = array();
 812:                 if (((strlen($parsedFrame['data_raw']) % 2) == 0) && ((substr($parsedFrame['data_raw'], 0, 2) == "\xFF\xFE") || (substr($parsedFrame['data_raw'], 0, 2) == "\xFE\xFF"))) {
 813:                     // UTF-16, be careful looking for null bytes since most 2-byte characters may contain one; you need to find twin null bytes, and on even padding
 814:                     $thisILPS  = '';
 815:                     for ($i = 0; $i < strlen($parsedFrame['data_raw']); $i += 2) {
 816:                         $twobytes = substr($parsedFrame['data_raw'], $i, 2);
 817:                         if ($twobytes === "\x00\x00") {
 818:                             $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
 819:                             $thisILPS  = '';
 820:                         } else {
 821:                             $thisILPS .= $twobytes;
 822:                         }
 823:                     }
 824:                     if (strlen($thisILPS) > 2) { // 2-byte BOM
 825:                         $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
 826:                     }
 827:                 } else {
 828:                     // ISO-8859-1 or UTF-8 or other single-byte-null character set
 829:                     $IPLS_parts_unsorted = explode("\x00", $parsedFrame['data_raw']);
 830:                 }
 831:                 if (count($IPLS_parts_unsorted) == 1) {
 832:                     // just a list of names, e.g. "Dino Baptiste, Jimmy Copley, John Gordon, Bernie Marsden, Sharon Watson"
 833:                     foreach ($IPLS_parts_unsorted as $key => $value) {
 834:                         $IPLS_parts_sorted = preg_split('#[;,\\r\\n\\t]#', $value);
 835:                         $position = '';
 836:                         foreach ($IPLS_parts_sorted as $person) {
 837:                             $IPLS_parts[] = array('position'=>$position, 'person'=>$person);
 838:                         }
 839:                     }
 840:                 } elseif ((count($IPLS_parts_unsorted) % 2) == 0) {
 841:                     $position = '';
 842:                     $person   = '';
 843:                     foreach ($IPLS_parts_unsorted as $key => $value) {
 844:                         if (($key % 2) == 0) {
 845:                             $position = $value;
 846:                         } else {
 847:                             $person   = $value;
 848:                             $IPLS_parts[] = array('position'=>$position, 'person'=>$person);
 849:                             $position = '';
 850:                             $person   = '';
 851:                         }
 852:                     }
 853:                 } else {
 854:                     foreach ($IPLS_parts_unsorted as $key => $value) {
 855:                         $IPLS_parts[] = array($value);
 856:                     }
 857:                 }
 858: 
 859:             } else {
 860:                 $IPLS_parts = preg_split('#[;,\\r\\n\\t]#', $parsedFrame['data_raw']);
 861:             }
 862:             $parsedFrame['data'] = $IPLS_parts;
 863: 
 864:             if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
 865:                 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
 866:             }
 867: 
 868: 
 869:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) || // 4.4   MCDI Music CD identifier
 870:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI'))) {     // 4.5   MCI  Music CD identifier
 871:             //   There may only be one 'MCDI' frame in each tag
 872:             // <Header for 'Music CD identifier', ID: 'MCDI'>
 873:             // CD TOC                <binary data>
 874: 
 875:             if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
 876:                 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
 877:             }
 878: 
 879: 
 880:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) || // 4.5   ETCO Event timing codes
 881:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC'))) {     // 4.6   ETC  Event timing codes
 882:             //   There may only be one 'ETCO' frame in each tag
 883:             // <Header for 'Event timing codes', ID: 'ETCO'>
 884:             // Time stamp format    $xx
 885:             //   Where time stamp format is:
 886:             // $01  (32-bit value) MPEG frames from beginning of file
 887:             // $02  (32-bit value) milliseconds from beginning of file
 888:             //   Followed by a list of key events in the following format:
 889:             // Type of event   $xx
 890:             // Time stamp      $xx (xx ...)
 891:             //   The 'Time stamp' is set to zero if directly at the beginning of the sound
 892:             //   or after the previous event. All events MUST be sorted in chronological order.
 893: 
 894:             $frame_offset = 0;
 895:             $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
 896: 
 897:             while ($frame_offset < strlen($parsedFrame['data'])) {
 898:                 $parsedFrame['typeid']    = substr($parsedFrame['data'], $frame_offset++, 1);
 899:                 $parsedFrame['type']      = $this->ETCOEventLookup($parsedFrame['typeid']);
 900:                 $parsedFrame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
 901:                 $frame_offset += 4;
 902:             }
 903:             unset($parsedFrame['data']);
 904: 
 905: 
 906:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) || // 4.6   MLLT MPEG location lookup table
 907:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL'))) {     // 4.7   MLL MPEG location lookup table
 908:             //   There may only be one 'MLLT' frame in each tag
 909:             // <Header for 'Location lookup table', ID: 'MLLT'>
 910:             // MPEG frames between reference  $xx xx
 911:             // Bytes between reference        $xx xx xx
 912:             // Milliseconds between reference $xx xx xx
 913:             // Bits for bytes deviation       $xx
 914:             // Bits for milliseconds dev.     $xx
 915:             //   Then for every reference the following data is included;
 916:             // Deviation in bytes         %xxx....
 917:             // Deviation in milliseconds  %xxx....
 918: 
 919:             $frame_offset = 0;
 920:             $parsedFrame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 2));
 921:             $parsedFrame['bytesbetweenreferences']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 2, 3));
 922:             $parsedFrame['msbetweenreferences']     = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 5, 3));
 923:             $parsedFrame['bitsforbytesdeviation']   = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1));
 924:             $parsedFrame['bitsformsdeviation']      = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1));
 925:             $parsedFrame['data'] = substr($parsedFrame['data'], 10);
 926:             while ($frame_offset < strlen($parsedFrame['data'])) {
 927:                 $deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
 928:             }
 929:             $reference_counter = 0;
 930:             while (strlen($deviationbitstream) > 0) {
 931:                 $parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation']));
 932:                 $parsedFrame[$reference_counter]['msdeviation']   = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation']));
 933:                 $deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']);
 934:                 $reference_counter++;
 935:             }
 936:             unset($parsedFrame['data']);
 937: 
 938: 
 939:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) || // 4.7   SYTC Synchronised tempo codes
 940:                   (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC'))) {  // 4.8   STC  Synchronised tempo codes
 941:             //   There may only be one 'SYTC' frame in each tag
 942:             // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
 943:             // Time stamp format   $xx
 944:             // Tempo data          <binary data>
 945:             //   Where time stamp format is:
 946:             // $01  (32-bit value) MPEG frames from beginning of file
 947:             // $02  (32-bit value) milliseconds from beginning of file
 948: 
 949:             $frame_offset = 0;
 950:             $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
 951:             $timestamp_counter = 0;
 952:             while ($frame_offset < strlen($parsedFrame['data'])) {
 953:                 $parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
 954:                 if ($parsedFrame[$timestamp_counter]['tempo'] == 255) {
 955:                     $parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset++, 1));
 956:                 }
 957:                 $parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
 958:                 $frame_offset += 4;
 959:                 $timestamp_counter++;
 960:             }
 961:             unset($parsedFrame['data']);
 962: 
 963: 
 964:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8   USLT Unsynchronised lyric/text transcription
 965:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) {     // 4.9   ULT  Unsynchronised lyric/text transcription
 966:             //   There may be more than one 'Unsynchronised lyrics/text transcription' frame
 967:             //   in each tag, but only one with the same language and content descriptor.
 968:             // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
 969:             // Text encoding        $xx
 970:             // Language             $xx xx xx
 971:             // Content descriptor   <text string according to encoding> $00 (00)
 972:             // Lyrics/text          <full text string according to encoding>
 973: 
 974:             $frame_offset = 0;
 975:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
 976:             $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
 977:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
 978:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
 979:                 $frame_textencoding_terminator = "\x00";
 980:             }
 981:             $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
 982:             $frame_offset += 3;
 983:             $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
 984:             if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
 985:                 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
 986:             }
 987:             $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
 988:             if (ord($frame_description) === 0) {
 989:                 $frame_description = '';
 990:             }
 991:             $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
 992: 
 993:             $parsedFrame['encodingid']   = $frame_textencoding;
 994:             $parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
 995: 
 996:             $parsedFrame['language']     = $frame_language;
 997:             $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
 998:             $parsedFrame['description']  = $frame_description;
 999:             if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1000:                 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1001:             }
1002:             unset($parsedFrame['data']);
1003: 
1004: 
1005:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) || // 4.9   SYLT Synchronised lyric/text
1006:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT'))) {     // 4.10  SLT  Synchronised lyric/text
1007:             //   There may be more than one 'SYLT' frame in each tag,
1008:             //   but only one with the same language and content descriptor.
1009:             // <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
1010:             // Text encoding        $xx
1011:             // Language             $xx xx xx
1012:             // Time stamp format    $xx
1013:             //   $01  (32-bit value) MPEG frames from beginning of file
1014:             //   $02  (32-bit value) milliseconds from beginning of file
1015:             // Content type         $xx
1016:             // Content descriptor   <text string according to encoding> $00 (00)
1017:             //   Terminated text to be synced (typically a syllable)
1018:             //   Sync identifier (terminator to above string)   $00 (00)
1019:             //   Time stamp                                     $xx (xx ...)
1020: 
1021:             $frame_offset = 0;
1022:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1023:             $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1024:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1025:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1026:                 $frame_textencoding_terminator = "\x00";
1027:             }
1028:             $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1029:             $frame_offset += 3;
1030:             $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1031:             $parsedFrame['contenttypeid']   = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1032:             $parsedFrame['contenttype']     = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']);
1033:             $parsedFrame['encodingid']      = $frame_textencoding;
1034:             $parsedFrame['encoding']        = $this->TextEncodingNameLookup($frame_textencoding);
1035: 
1036:             $parsedFrame['language']        = $frame_language;
1037:             $parsedFrame['languagename']    = $this->LanguageLookup($frame_language, false);
1038: 
1039:             $timestampindex = 0;
1040:             $frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
1041:             while (strlen($frame_remainingdata)) {
1042:                 $frame_offset = 0;
1043:                 $frame_terminatorpos = strpos($frame_remainingdata, $frame_textencoding_terminator);
1044:                 if ($frame_terminatorpos === false) {
1045:                     $frame_remainingdata = '';
1046:                 } else {
1047:                     if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1048:                         $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1049:                     }
1050:                     $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
1051: 
1052:                     $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator));
1053:                     if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) {
1054:                         // timestamp probably omitted for first data item
1055:                     } else {
1056:                         $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4));
1057:                         $frame_remainingdata = substr($frame_remainingdata, 4);
1058:                     }
1059:                     $timestampindex++;
1060:                 }
1061:             }
1062:             unset($parsedFrame['data']);
1063: 
1064: 
1065:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) || // 4.10  COMM Comments
1066:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM'))) {     // 4.11  COM  Comments
1067:             //   There may be more than one comment frame in each tag,
1068:             //   but only one with the same language and content descriptor.
1069:             // <Header for 'Comment', ID: 'COMM'>
1070:             // Text encoding          $xx
1071:             // Language               $xx xx xx
1072:             // Short content descrip. <text string according to encoding> $00 (00)
1073:             // The actual text        <full text string according to encoding>
1074: 
1075:             if (strlen($parsedFrame['data']) < 5) {
1076: 
1077:                 $info['warning'][] = 'Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset'];
1078: 
1079:             } else {
1080: 
1081:                 $frame_offset = 0;
1082:                 $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1083:                 $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1084:                 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1085:                     $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1086:                     $frame_textencoding_terminator = "\x00";
1087:                 }
1088:                 $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1089:                 $frame_offset += 3;
1090:                 $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1091:                 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1092:                     $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1093:                 }
1094:                 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1095:                 if (ord($frame_description) === 0) {
1096:                     $frame_description = '';
1097:                 }
1098:                 $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
1099: 
1100:                 $parsedFrame['encodingid']   = $frame_textencoding;
1101:                 $parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
1102: 
1103:                 $parsedFrame['language']     = $frame_language;
1104:                 $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1105:                 $parsedFrame['description']  = $frame_description;
1106:                 $parsedFrame['data']         = $frame_text;
1107:                 if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1108:                     $commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (!empty($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
1109:                     if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
1110:                         $info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1111:                     } else {
1112:                         $info['id3v2']['comments'][$parsedFrame['framenameshort']][]            = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1113:                     }
1114:                 }
1115: 
1116:             }
1117: 
1118:         } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2')) { // 4.11  RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
1119:             //   There may be more than one 'RVA2' frame in each tag,
1120:             //   but only one with the same identification string
1121:             // <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
1122:             // Identification          <text string> $00
1123:             //   The 'identification' string is used to identify the situation and/or
1124:             //   device where this adjustment should apply. The following is then
1125:             //   repeated for every channel:
1126:             // Type of channel         $xx
1127:             // Volume adjustment       $xx xx
1128:             // Bits representing peak  $xx
1129:             // Peak volume             $xx (xx ...)
1130: 
1131:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
1132:             $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
1133:             if (ord($frame_idstring) === 0) {
1134:                 $frame_idstring = '';
1135:             }
1136:             $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
1137:             $parsedFrame['description'] = $frame_idstring;
1138:             $RVA2channelcounter = 0;
1139:             while (strlen($frame_remainingdata) >= 5) {
1140:                 $frame_offset = 0;
1141:                 $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1));
1142:                 $parsedFrame[$RVA2channelcounter]['channeltypeid']  = $frame_channeltypeid;
1143:                 $parsedFrame[$RVA2channelcounter]['channeltype']    = $this->RVA2ChannelTypeLookup($frame_channeltypeid);
1144:                 $parsedFrame[$RVA2channelcounter]['volumeadjust']   = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed
1145:                 $frame_offset += 2;
1146:                 $parsedFrame[$RVA2channelcounter]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
1147:                 if (($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] < 1) || ($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] > 4)) {
1148:                     $info['warning'][] = 'ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value';
1149:                     break;
1150:                 }
1151:                 $frame_bytespeakvolume = ceil($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] / 8);
1152:                 $parsedFrame[$RVA2channelcounter]['peakvolume']     = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
1153:                 $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
1154:                 $RVA2channelcounter++;
1155:             }
1156:             unset($parsedFrame['data']);
1157: 
1158: 
1159:         } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) || // 4.12  RVAD Relative volume adjustment (ID3v2.3 only)
1160:                   (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA'))) {  // 4.12  RVA  Relative volume adjustment (ID3v2.2 only)
1161:             //   There may only be one 'RVA' frame in each tag
1162:             // <Header for 'Relative volume adjustment', ID: 'RVA'>
1163:             // ID3v2.2 => Increment/decrement     %000000ba
1164:             // ID3v2.3 => Increment/decrement     %00fedcba
1165:             // Bits used for volume descr.        $xx
1166:             // Relative volume change, right      $xx xx (xx ...) // a
1167:             // Relative volume change, left       $xx xx (xx ...) // b
1168:             // Peak volume right                  $xx xx (xx ...)
1169:             // Peak volume left                   $xx xx (xx ...)
1170:             //   ID3v2.3 only, optional (not present in ID3v2.2):
1171:             // Relative volume change, right back $xx xx (xx ...) // c
1172:             // Relative volume change, left back  $xx xx (xx ...) // d
1173:             // Peak volume right back             $xx xx (xx ...)
1174:             // Peak volume left back              $xx xx (xx ...)
1175:             //   ID3v2.3 only, optional (not present in ID3v2.2):
1176:             // Relative volume change, center     $xx xx (xx ...) // e
1177:             // Peak volume center                 $xx xx (xx ...)
1178:             //   ID3v2.3 only, optional (not present in ID3v2.2):
1179:             // Relative volume change, bass       $xx xx (xx ...) // f
1180:             // Peak volume bass                   $xx xx (xx ...)
1181: 
1182:             $frame_offset = 0;
1183:             $frame_incrdecrflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
1184:             $parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
1185:             $parsedFrame['incdec']['left']  = (bool) substr($frame_incrdecrflags, 7, 1);
1186:             $parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1187:             $frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8);
1188:             $parsedFrame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1189:             if ($parsedFrame['incdec']['right'] === false) {
1190:                 $parsedFrame['volumechange']['right'] *= -1;
1191:             }
1192:             $frame_offset += $frame_bytesvolume;
1193:             $parsedFrame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1194:             if ($parsedFrame['incdec']['left'] === false) {
1195:                 $parsedFrame['volumechange']['left'] *= -1;
1196:             }
1197:             $frame_offset += $frame_bytesvolume;
1198:             $parsedFrame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1199:             $frame_offset += $frame_bytesvolume;
1200:             $parsedFrame['peakvolume']['left']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1201:             $frame_offset += $frame_bytesvolume;
1202:             if ($id3v2_majorversion == 3) {
1203:                 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1204:                 if (strlen($parsedFrame['data']) > 0) {
1205:                     $parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
1206:                     $parsedFrame['incdec']['leftrear']  = (bool) substr($frame_incrdecrflags, 5, 1);
1207:                     $parsedFrame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1208:                     if ($parsedFrame['incdec']['rightrear'] === false) {
1209:                         $parsedFrame['volumechange']['rightrear'] *= -1;
1210:                     }
1211:                     $frame_offset += $frame_bytesvolume;
1212:                     $parsedFrame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1213:                     if ($parsedFrame['incdec']['leftrear'] === false) {
1214:                         $parsedFrame['volumechange']['leftrear'] *= -1;
1215:                     }
1216:                     $frame_offset += $frame_bytesvolume;
1217:                     $parsedFrame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1218:                     $frame_offset += $frame_bytesvolume;
1219:                     $parsedFrame['peakvolume']['leftrear']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1220:                     $frame_offset += $frame_bytesvolume;
1221:                 }
1222:                 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1223:                 if (strlen($parsedFrame['data']) > 0) {
1224:                     $parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
1225:                     $parsedFrame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1226:                     if ($parsedFrame['incdec']['center'] === false) {
1227:                         $parsedFrame['volumechange']['center'] *= -1;
1228:                     }
1229:                     $frame_offset += $frame_bytesvolume;
1230:                     $parsedFrame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1231:                     $frame_offset += $frame_bytesvolume;
1232:                 }
1233:                 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1234:                 if (strlen($parsedFrame['data']) > 0) {
1235:                     $parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
1236:                     $parsedFrame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1237:                     if ($parsedFrame['incdec']['bass'] === false) {
1238:                         $parsedFrame['volumechange']['bass'] *= -1;
1239:                     }
1240:                     $frame_offset += $frame_bytesvolume;
1241:                     $parsedFrame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1242:                     $frame_offset += $frame_bytesvolume;
1243:                 }
1244:             }
1245:             unset($parsedFrame['data']);
1246: 
1247: 
1248:         } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2')) { // 4.12  EQU2 Equalisation (2) (ID3v2.4+ only)
1249:             //   There may be more than one 'EQU2' frame in each tag,
1250:             //   but only one with the same identification string
1251:             // <Header of 'Equalisation (2)', ID: 'EQU2'>
1252:             // Interpolation method  $xx
1253:             //   $00  Band
1254:             //   $01  Linear
1255:             // Identification        <text string> $00
1256:             //   The following is then repeated for every adjustment point
1257:             // Frequency          $xx xx
1258:             // Volume adjustment  $xx xx
1259: 
1260:             $frame_offset = 0;
1261:             $frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1262:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1263:             $frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1264:             if (ord($frame_idstring) === 0) {
1265:                 $frame_idstring = '';
1266:             }
1267:             $parsedFrame['description'] = $frame_idstring;
1268:             $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
1269:             while (strlen($frame_remainingdata)) {
1270:                 $frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
1271:                 $parsedFrame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true);
1272:                 $frame_remainingdata = substr($frame_remainingdata, 4);
1273:             }
1274:             $parsedFrame['interpolationmethod'] = $frame_interpolationmethod;
1275:             unset($parsedFrame['data']);
1276: 
1277: 
1278:         } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) || // 4.12  EQUA Equalisation (ID3v2.3 only)
1279:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU'))) {     // 4.13  EQU  Equalisation (ID3v2.2 only)
1280:             //   There may only be one 'EQUA' frame in each tag
1281:             // <Header for 'Relative volume adjustment', ID: 'EQU'>
1282:             // Adjustment bits    $xx
1283:             //   This is followed by 2 bytes + ('adjustment bits' rounded up to the
1284:             //   nearest byte) for every equalisation band in the following format,
1285:             //   giving a frequency range of 0 - 32767Hz:
1286:             // Increment/decrement   %x (MSB of the Frequency)
1287:             // Frequency             (lower 15 bits)
1288:             // Adjustment            $xx (xx ...)
1289: 
1290:             $frame_offset = 0;
1291:             $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1);
1292:             $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8);
1293: 
1294:             $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset);
1295:             while (strlen($frame_remainingdata) > 0) {
1296:                 $frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remainingdata, 0, 2));
1297:                 $frame_incdec    = (bool) substr($frame_frequencystr, 0, 1);
1298:                 $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
1299:                 $parsedFrame[$frame_frequency]['incdec'] = $frame_incdec;
1300:                 $parsedFrame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
1301:                 if ($parsedFrame[$frame_frequency]['incdec'] === false) {
1302:                     $parsedFrame[$frame_frequency]['adjustment'] *= -1;
1303:                 }
1304:                 $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
1305:             }
1306:             unset($parsedFrame['data']);
1307: 
1308: 
1309:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) || // 4.13  RVRB Reverb
1310:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV'))) {     // 4.14  REV  Reverb
1311:             //   There may only be one 'RVRB' frame in each tag.
1312:             // <Header for 'Reverb', ID: 'RVRB'>
1313:             // Reverb left (ms)                 $xx xx
1314:             // Reverb right (ms)                $xx xx
1315:             // Reverb bounces, left             $xx
1316:             // Reverb bounces, right            $xx
1317:             // Reverb feedback, left to left    $xx
1318:             // Reverb feedback, left to right   $xx
1319:             // Reverb feedback, right to right  $xx
1320:             // Reverb feedback, right to left   $xx
1321:             // Premix left to right             $xx
1322:             // Premix right to left             $xx
1323: 
1324:             $frame_offset = 0;
1325:             $parsedFrame['left']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1326:             $frame_offset += 2;
1327:             $parsedFrame['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1328:             $frame_offset += 2;
1329:             $parsedFrame['bouncesL']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1330:             $parsedFrame['bouncesR']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1331:             $parsedFrame['feedbackLL']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1332:             $parsedFrame['feedbackLR']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1333:             $parsedFrame['feedbackRR']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1334:             $parsedFrame['feedbackRL']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1335:             $parsedFrame['premixLR']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1336:             $parsedFrame['premixRL']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1337:             unset($parsedFrame['data']);
1338: 
1339: 
1340:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) || // 4.14  APIC Attached picture
1341:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC'))) {     // 4.15  PIC  Attached picture
1342:             //   There may be several pictures attached to one file,
1343:             //   each in their individual 'APIC' frame, but only one
1344:             //   with the same content descriptor
1345:             // <Header for 'Attached picture', ID: 'APIC'>
1346:             // Text encoding      $xx
1347:             // ID3v2.3+ => MIME type          <text string> $00
1348:             // ID3v2.2  => Image format       $xx xx xx
1349:             // Picture type       $xx
1350:             // Description        <text string according to encoding> $00 (00)
1351:             // Picture data       <binary data>
1352: 
1353:             $frame_offset = 0;
1354:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1355:             $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1356:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1357:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1358:                 $frame_textencoding_terminator = "\x00";
1359:             }
1360: 
1361:             if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
1362:                 $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
1363:                 if (strtolower($frame_imagetype) == 'ima') {
1364:                     // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
1365:                     // MIME type instead of 3-char ID3v2.2-format image type  (thanks xbhoffØpacbell*net)
1366:                     $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1367:                     $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1368:                     if (ord($frame_mimetype) === 0) {
1369:                         $frame_mimetype = '';
1370:                     }
1371:                     $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
1372:                     if ($frame_imagetype == 'JPEG') {
1373:                         $frame_imagetype = 'JPG';
1374:                     }
1375:                     $frame_offset = $frame_terminatorpos + strlen("\x00");
1376:                 } else {
1377:                     $frame_offset += 3;
1378:                 }
1379:             }
1380:             if ($id3v2_majorversion > 2 && strlen($parsedFrame['data']) > $frame_offset) {
1381:                 $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1382:                 $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1383:                 if (ord($frame_mimetype) === 0) {
1384:                     $frame_mimetype = '';
1385:                 }
1386:                 $frame_offset = $frame_terminatorpos + strlen("\x00");
1387:             }
1388: 
1389:             $frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1390: 
1391:             if ($frame_offset >= $parsedFrame['datalength']) {
1392:                 $info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset);
1393:             } else {
1394:                 $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1395:                 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1396:                     $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1397:                 }
1398:                 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1399:                 if (ord($frame_description) === 0) {
1400:                     $frame_description = '';
1401:                 }
1402:                 $parsedFrame['encodingid']       = $frame_textencoding;
1403:                 $parsedFrame['encoding']         = $this->TextEncodingNameLookup($frame_textencoding);
1404: 
1405:                 if ($id3v2_majorversion == 2) {
1406:                     $parsedFrame['imagetype']    = $frame_imagetype;
1407:                 } else {
1408:                     $parsedFrame['mime']         = $frame_mimetype;
1409:                 }
1410:                 $parsedFrame['picturetypeid']    = $frame_picturetype;
1411:                 $parsedFrame['picturetype']      = $this->APICPictureTypeLookup($frame_picturetype);
1412:                 $parsedFrame['description']      = $frame_description;
1413:                 $parsedFrame['data']             = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
1414:                 $parsedFrame['datalength']       = strlen($parsedFrame['data']);
1415: 
1416:                 $parsedFrame['image_mime'] = '';
1417:                 $imageinfo = array();
1418:                 if ($imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo)) {
1419:                     if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
1420:                         $parsedFrame['image_mime']       = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]);
1421:                         if ($imagechunkcheck[0]) {
1422:                             $parsedFrame['image_width']  = $imagechunkcheck[0];
1423:                         }
1424:                         if ($imagechunkcheck[1]) {
1425:                             $parsedFrame['image_height'] = $imagechunkcheck[1];
1426:                         }
1427:                     }
1428:                 }
1429: 
1430:                 do {
1431:                     if ($this->getid3->option_save_attachments === false) {
1432:                         // skip entirely
1433:                         unset($parsedFrame['data']);
1434:                         break;
1435:                     }
1436:                     if ($this->getid3->option_save_attachments === true) {
1437:                         // great
1438: /*
1439:                     } elseif (is_int($this->getid3->option_save_attachments)) {
1440:                         if ($this->getid3->option_save_attachments < $parsedFrame['data_length']) {
1441:                             // too big, skip
1442:                             $info['warning'][] = 'attachment at '.$frame_offset.' is too large to process inline ('.number_format($parsedFrame['data_length']).' bytes)';
1443:                             unset($parsedFrame['data']);
1444:                             break;
1445:                         }
1446: */
1447:                     } elseif (is_string($this->getid3->option_save_attachments)) {
1448:                         $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
1449:                         if (!is_dir($dir) || !is_writable($dir)) {
1450:                             // cannot write, skip
1451:                             $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)';
1452:                             unset($parsedFrame['data']);
1453:                             break;
1454:                         }
1455:                     }
1456:                     // if we get this far, must be OK
1457:                     if (is_string($this->getid3->option_save_attachments)) {
1458:                         $destination_filename = $dir.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$frame_offset;
1459:                         if (!file_exists($destination_filename) || is_writable($destination_filename)) {
1460:                             file_put_contents($destination_filename, $parsedFrame['data']);
1461:                         } else {
1462:                             $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)';
1463:                         }
1464:                         $parsedFrame['data_filename'] = $destination_filename;
1465:                         unset($parsedFrame['data']);
1466:                     } else {
1467:                         if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1468:                             if (!isset($info['id3v2']['comments']['picture'])) {
1469:                                 $info['id3v2']['comments']['picture'] = array();
1470:                             }
1471:                             $comments_picture_data = array();
1472:                             foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) {
1473:                                 if (isset($parsedFrame[$picture_key])) {
1474:                                     $comments_picture_data[$picture_key] = $parsedFrame[$picture_key];
1475:                                 }
1476:                             }
1477:                             $info['id3v2']['comments']['picture'][] = $comments_picture_data;
1478:                             unset($comments_picture_data);
1479:                         }
1480:                     }
1481:                 } while (false);
1482:             }
1483: 
1484:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15  GEOB General encapsulated object
1485:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO'))) {     // 4.16  GEO  General encapsulated object
1486:             //   There may be more than one 'GEOB' frame in each tag,
1487:             //   but only one with the same content descriptor
1488:             // <Header for 'General encapsulated object', ID: 'GEOB'>
1489:             // Text encoding          $xx
1490:             // MIME type              <text string> $00
1491:             // Filename               <text string according to encoding> $00 (00)
1492:             // Content description    <text string according to encoding> $00 (00)
1493:             // Encapsulated object    <binary data>
1494: 
1495:             $frame_offset = 0;
1496:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1497:             $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1498:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1499:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1500:                 $frame_textencoding_terminator = "\x00";
1501:             }
1502:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1503:             $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1504:             if (ord($frame_mimetype) === 0) {
1505:                 $frame_mimetype = '';
1506:             }
1507:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1508: 
1509:             $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1510:             if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1511:                 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1512:             }
1513:             $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1514:             if (ord($frame_filename) === 0) {
1515:                 $frame_filename = '';
1516:             }
1517:             $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1518: 
1519:             $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1520:             if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1521:                 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1522:             }
1523:             $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1524:             if (ord($frame_description) === 0) {
1525:                 $frame_description = '';
1526:             }
1527:             $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1528: 
1529:             $parsedFrame['objectdata']  = (string) substr($parsedFrame['data'], $frame_offset);
1530:             $parsedFrame['encodingid']  = $frame_textencoding;
1531:             $parsedFrame['encoding']    = $this->TextEncodingNameLookup($frame_textencoding);
1532: 
1533:             $parsedFrame['mime']        = $frame_mimetype;
1534:             $parsedFrame['filename']    = $frame_filename;
1535:             $parsedFrame['description'] = $frame_description;
1536:             unset($parsedFrame['data']);
1537: 
1538: 
1539:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) || // 4.16  PCNT Play counter
1540:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT'))) {     // 4.17  CNT  Play counter
1541:             //   There may only be one 'PCNT' frame in each tag.
1542:             //   When the counter reaches all one's, one byte is inserted in
1543:             //   front of the counter thus making the counter eight bits bigger
1544:             // <Header for 'Play counter', ID: 'PCNT'>
1545:             // Counter        $xx xx xx xx (xx ...)
1546: 
1547:             $parsedFrame['data']          = getid3_lib::BigEndian2Int($parsedFrame['data']);
1548: 
1549: 
1550:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) || // 4.17  POPM Popularimeter
1551:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP'))) {    // 4.18  POP  Popularimeter
1552:             //   There may be more than one 'POPM' frame in each tag,
1553:             //   but only one with the same email address
1554:             // <Header for 'Popularimeter', ID: 'POPM'>
1555:             // Email to user   <text string> $00
1556:             // Rating          $xx
1557:             // Counter         $xx xx xx xx (xx ...)
1558: 
1559:             $frame_offset = 0;
1560:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1561:             $frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1562:             if (ord($frame_emailaddress) === 0) {
1563:                 $frame_emailaddress = '';
1564:             }
1565:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1566:             $frame_rating = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1567:             $parsedFrame['counter'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
1568:             $parsedFrame['email']   = $frame_emailaddress;
1569:             $parsedFrame['rating']  = $frame_rating;
1570:             unset($parsedFrame['data']);
1571: 
1572: 
1573:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) || // 4.18  RBUF Recommended buffer size
1574:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF'))) {     // 4.19  BUF  Recommended buffer size
1575:             //   There may only be one 'RBUF' frame in each tag
1576:             // <Header for 'Recommended buffer size', ID: 'RBUF'>
1577:             // Buffer size               $xx xx xx
1578:             // Embedded info flag        %0000000x
1579:             // Offset to next tag        $xx xx xx xx
1580: 
1581:             $frame_offset = 0;
1582:             $parsedFrame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3));
1583:             $frame_offset += 3;
1584: 
1585:             $frame_embeddedinfoflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
1586:             $parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
1587:             $parsedFrame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1588:             unset($parsedFrame['data']);
1589: 
1590: 
1591:         } elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM')) { // 4.20  Encrypted meta frame (ID3v2.2 only)
1592:             //   There may be more than one 'CRM' frame in a tag,
1593:             //   but only one with the same 'owner identifier'
1594:             // <Header for 'Encrypted meta frame', ID: 'CRM'>
1595:             // Owner identifier      <textstring> $00 (00)
1596:             // Content/explanation   <textstring> $00 (00)
1597:             // Encrypted datablock   <binary data>
1598: 
1599:             $frame_offset = 0;
1600:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1601:             $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1602:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1603: 
1604:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1605:             $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1606:             if (ord($frame_description) === 0) {
1607:                 $frame_description = '';
1608:             }
1609:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1610: 
1611:             $parsedFrame['ownerid']     = $frame_ownerid;
1612:             $parsedFrame['data']        = (string) substr($parsedFrame['data'], $frame_offset);
1613:             $parsedFrame['description'] = $frame_description;
1614:             unset($parsedFrame['data']);
1615: 
1616: 
1617:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) || // 4.19  AENC Audio encryption
1618:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA'))) {     // 4.21  CRA  Audio encryption
1619:             //   There may be more than one 'AENC' frames in a tag,
1620:             //   but only one with the same 'Owner identifier'
1621:             // <Header for 'Audio encryption', ID: 'AENC'>
1622:             // Owner identifier   <text string> $00
1623:             // Preview start      $xx xx
1624:             // Preview length     $xx xx
1625:             // Encryption info    <binary data>
1626: 
1627:             $frame_offset = 0;
1628:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1629:             $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1630:             if (ord($frame_ownerid) === 0) {
1631:                 $frame_ownerid = '';
1632:             }
1633:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1634:             $parsedFrame['ownerid'] = $frame_ownerid;
1635:             $parsedFrame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1636:             $frame_offset += 2;
1637:             $parsedFrame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1638:             $frame_offset += 2;
1639:             $parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset);
1640:             unset($parsedFrame['data']);
1641: 
1642: 
1643:         } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20  LINK Linked information
1644:                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) {    // 4.22  LNK  Linked information
1645:             //   There may be more than one 'LINK' frame in a tag,
1646:             //   but only one with the same contents
1647:             // <Header for 'Linked information', ID: 'LINK'>
1648:             // ID3v2.3+ => Frame identifier   $xx xx xx xx
1649:             // ID3v2.2  => Frame identifier   $xx xx xx
1650:             // URL                            <text string> $00
1651:             // ID and additional data         <text string(s)>
1652: 
1653:             $frame_offset = 0;
1654:             if ($id3v2_majorversion == 2) {
1655:                 $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3);
1656:                 $frame_offset += 3;
1657:             } else {
1658:                 $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4);
1659:                 $frame_offset += 4;
1660:             }
1661: 
1662:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1663:             $frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1664:             if (ord($frame_url) === 0) {
1665:                 $frame_url = '';
1666:             }
1667:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1668:             $parsedFrame['url'] = $frame_url;
1669: 
1670:             $parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
1671:             if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
1672:                 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback_iso88591_utf8($parsedFrame['url']);
1673:             }
1674:             unset($parsedFrame['data']);
1675: 
1676: 
1677:         } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS')) { // 4.21  POSS Position synchronisation frame (ID3v2.3+ only)
1678:             //   There may only be one 'POSS' frame in each tag
1679:             // <Head for 'Position synchronisation', ID: 'POSS'>
1680:             // Time stamp format         $xx
1681:             // Position                  $xx (xx ...)
1682: 
1683:             $frame_offset = 0;
1684:             $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1685:             $parsedFrame['position']        = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
1686:             unset($parsedFrame['data']);
1687: 
1688: 
1689:         } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER')) { // 4.22  USER Terms of use (ID3v2.3+ only)
1690:             //   There may be more than one 'Terms of use' frame in a tag,
1691:             //   but only one with the same 'Language'
1692:             // <Header for 'Terms of use frame', ID: 'USER'>
1693:             // Text encoding        $xx
1694:             // Language             $xx xx xx
1695:             // The actual text      <text string according to encoding>
1696: 
1697:             $frame_offset = 0;
1698:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1699:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1700:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1701:             }
1702:             $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1703:             $frame_offset += 3;
1704:             $parsedFrame['language']     = $frame_language;
1705:             $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1706:             $parsedFrame['encodingid']   = $frame_textencoding;
1707:             $parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
1708: 
1709:             $parsedFrame['data']         = (string) substr($parsedFrame['data'], $frame_offset);
1710:             if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1711:                 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1712:             }
1713:             unset($parsedFrame['data']);
1714: 
1715: 
1716:         } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE')) { // 4.23  OWNE Ownership frame (ID3v2.3+ only)
1717:             //   There may only be one 'OWNE' frame in a tag
1718:             // <Header for 'Ownership frame', ID: 'OWNE'>
1719:             // Text encoding     $xx
1720:             // Price paid        <text string> $00
1721:             // Date of purch.    <text string>
1722:             // Seller            <text string according to encoding>
1723: 
1724:             $frame_offset = 0;
1725:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1726:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1727:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1728:             }
1729:             $parsedFrame['encodingid'] = $frame_textencoding;
1730:             $parsedFrame['encoding']   = $this->TextEncodingNameLookup($frame_textencoding);
1731: 
1732:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1733:             $frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1734:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1735: 
1736:             $parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
1737:             $parsedFrame['pricepaid']['currency']   = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']);
1738:             $parsedFrame['pricepaid']['value']      = substr($frame_pricepaid, 3);
1739: 
1740:             $parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8);
1741:             if (!$this->IsValidDateStampString($parsedFrame['purchasedate'])) {
1742:                 $parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4));
1743:             }
1744:             $frame_offset += 8;
1745: 
1746:             $parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
1747:             unset($parsedFrame['data']);
1748: 
1749: 
1750:         } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR')) { // 4.24  COMR Commercial frame (ID3v2.3+ only)
1751:             //   There may be more than one 'commercial frame' in a tag,
1752:             //   but no two may be identical
1753:             // <Header for 'Commercial frame', ID: 'COMR'>
1754:             // Text encoding      $xx
1755:             // Price string       <text string> $00
1756:             // Valid until        <text string>
1757:             // Contact URL        <text string> $00
1758:             // Received as        $xx
1759:             // Name of seller     <text string according to encoding> $00 (00)
1760:             // Description        <text string according to encoding> $00 (00)
1761:             // Picture MIME type  <string> $00
1762:             // Seller logo        <binary data>
1763: 
1764:             $frame_offset = 0;
1765:             $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1766:             $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1767:             if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1768:                 $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1769:                 $frame_textencoding_terminator = "\x00";
1770:             }
1771: 
1772:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1773:             $frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1774:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1775:             $frame_rawpricearray = explode('/', $frame_pricestring);
1776:             foreach ($frame_rawpricearray as $key => $val) {
1777:                 $frame_currencyid = substr($val, 0, 3);
1778:                 $parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid);
1779:                 $parsedFrame['price'][$frame_currencyid]['value']    = substr($val, 3);
1780:             }
1781: 
1782:             $frame_datestring = substr($parsedFrame['data'], $frame_offset, 8);
1783:             $frame_offset += 8;
1784: 
1785:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1786:             $frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1787:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1788: 
1789:             $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1790: 
1791:             $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1792:             if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1793:                 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1794:             }
1795:             $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1796:             if (ord($frame_sellername) === 0) {
1797:                 $frame_sellername = '';
1798:             }
1799:             $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1800: 
1801:             $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1802:             if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1803:                 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1804:             }
1805:             $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1806:             if (ord($frame_description) === 0) {
1807:                 $frame_description = '';
1808:             }
1809:             $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1810: 
1811:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1812:             $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1813:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1814: 
1815:             $frame_sellerlogo = substr($parsedFrame['data'], $frame_offset);
1816: 
1817:             $parsedFrame['encodingid']        = $frame_textencoding;
1818:             $parsedFrame['encoding']          = $this->TextEncodingNameLookup($frame_textencoding);
1819: 
1820:             $parsedFrame['pricevaliduntil']   = $frame_datestring;
1821:             $parsedFrame['contacturl']        = $frame_contacturl;
1822:             $parsedFrame['receivedasid']      = $frame_receivedasid;
1823:             $parsedFrame['receivedas']        = $this->COMRReceivedAsLookup($frame_receivedasid);
1824:             $parsedFrame['sellername']        = $frame_sellername;
1825:             $parsedFrame['description']       = $frame_description;
1826:             $parsedFrame['mime']              = $frame_mimetype;
1827:             $parsedFrame['logo']              = $frame_sellerlogo;
1828:             unset($parsedFrame['data']);
1829: 
1830: 
1831:         } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR')) { // 4.25  ENCR Encryption method registration (ID3v2.3+ only)
1832:             //   There may be several 'ENCR' frames in a tag,
1833:             //   but only one containing the same symbol
1834:             //   and only one containing the same owner identifier
1835:             // <Header for 'Encryption method registration', ID: 'ENCR'>
1836:             // Owner identifier    <text string> $00
1837:             // Method symbol       $xx
1838:             // Encryption data     <binary data>
1839: 
1840:             $frame_offset = 0;
1841:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1842:             $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1843:             if (ord($frame_ownerid) === 0) {
1844:                 $frame_ownerid = '';
1845:             }
1846:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1847: 
1848:             $parsedFrame['ownerid']      = $frame_ownerid;
1849:             $parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1850:             $parsedFrame['data']         = (string) substr($parsedFrame['data'], $frame_offset);
1851: 
1852: 
1853:         } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID')) { // 4.26  GRID Group identification registration (ID3v2.3+ only)
1854: 
1855:             //   There may be several 'GRID' frames in a tag,
1856:             //   but only one containing the same symbol
1857:             //   and only one containing the same owner identifier
1858:             // <Header for 'Group ID registration', ID: 'GRID'>
1859:             // Owner identifier      <text string> $00
1860:             // Group symbol          $xx
1861:             // Group dependent data  <binary data>
1862: 
1863:             $frame_offset = 0;
1864:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1865:             $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1866:             if (ord($frame_ownerid) === 0) {
1867:                 $frame_ownerid = '';
1868:             }
1869:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1870: 
1871:             $parsedFrame['ownerid']       = $frame_ownerid;
1872:             $parsedFrame['groupsymbol']   = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1873:             $parsedFrame['data']          = (string) substr($parsedFrame['data'], $frame_offset);
1874: 
1875: 
1876:         } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV')) { // 4.27  PRIV Private frame (ID3v2.3+ only)
1877:             //   The tag may contain more than one 'PRIV' frame
1878:             //   but only with different contents
1879:             // <Header for 'Private frame', ID: 'PRIV'>
1880:             // Owner identifier      <text string> $00
1881:             // The private data      <binary data>
1882: 
1883:             $frame_offset = 0;
1884:             $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1885:             $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1886:             if (ord($frame_ownerid) === 0) {
1887:                 $frame_ownerid = '';
1888:             }
1889:             $frame_offset = $frame_terminatorpos + strlen("\x00");
1890: 
1891:             $parsedFrame['ownerid'] = $frame_ownerid;
1892:             $parsedFrame['data']    = (string) substr($parsedFrame['data'], $frame_offset);
1893: 
1894: 
1895:         } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN')) { // 4.28  SIGN Signature frame (ID3v2.4+ only)
1896:             //   There may be more than one 'signature frame' in a tag,
1897:             //   but no two may be identical
1898:             // <Header for 'Signature frame', ID: 'SIGN'>
1899:             // Group symbol      $xx
1900:             // Signature         <binary data>
1901: 
1902:             $frame_offset = 0;
1903:             $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1904:             $parsedFrame['data']        = (string) substr($parsedFrame['data'], $frame_offset);
1905: 
1906: 
1907:         } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK')) { // 4.29  SEEK Seek frame (ID3v2.4+ only)
1908:             //   There may only be one 'seek frame' in a tag
1909:             // <Header for 'Seek frame', ID: 'SEEK'>
1910:             // Minimum offset to next tag       $xx xx xx xx
1911: 
1912:             $frame_offset = 0;
1913:             $parsedFrame['data']          = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1914: 
1915: 
1916:         } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI')) { // 4.30  ASPI Audio seek point index (ID3v2.4+ only)
1917:             //   There may only be one 'audio seek point index' frame in a tag
1918:             // <Header for 'Seek Point Index', ID: 'ASPI'>
1919:             // Indexed data start (S)         $xx xx xx xx
1920:             // Indexed data length (L)        $xx xx xx xx
1921:             // Number of index points (N)     $xx xx
1922:             // Bits per index point (b)       $xx
1923:             //   Then for every index point the following data is included:
1924:             // Fraction at index (Fi)          $xx (xx)
1925: 
1926:             $frame_offset = 0;
1927:             $parsedFrame['datastart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1928:             $frame_offset += 4;
1929:             $parsedFrame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1930:             $frame_offset += 4;
1931:             $parsedFrame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1932:             $frame_offset += 2;
1933:             $parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1934:             $frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
1935:             for ($i = 0; $i < $parsedFrame['indexpoints']; $i++) {
1936:                 $parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
1937:                 $frame_offset += $frame_bytesperpoint;
1938:             }
1939:             unset($parsedFrame['data']);
1940: 
1941:         } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD')) { // Replay Gain Adjustment
1942:             // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
1943:             //   There may only be one 'RGAD' frame in a tag
1944:             // <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
1945:             // Peak Amplitude                      $xx $xx $xx $xx
1946:             // Radio Replay Gain Adjustment        %aaabbbcd %dddddddd
1947:             // Audiophile Replay Gain Adjustment   %aaabbbcd %dddddddd
1948:             //   a - name code
1949:             //   b - originator code
1950:             //   c - sign bit
1951:             //   d - replay gain adjustment
1952: 
1953:             $frame_offset = 0;
1954:             $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
1955:             $frame_offset += 4;
1956:             $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
1957:             $frame_offset += 2;
1958:             $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
1959:             $frame_offset += 2;
1960:             $parsedFrame['raw']['track']['name']       = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3));
1961:             $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3));
1962:             $parsedFrame['raw']['track']['signbit']    = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1));
1963:             $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9));
1964:             $parsedFrame['raw']['album']['name']       = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3));
1965:             $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3));
1966:             $parsedFrame['raw']['album']['signbit']    = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1));
1967:             $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9));
1968:             $parsedFrame['track']['name']       = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
1969:             $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
1970:             $parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
1971:             $parsedFrame['album']['name']       = getid3_lib::RGADnameLookup($parsedFrame['raw']['album']['name']);
1972:             $parsedFrame['album']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['album']['originator']);
1973:             $parsedFrame['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']);
1974: 
1975:             $info['replay_gain']['track']['peak']       = $parsedFrame['peakamplitude'];
1976:             $info['replay_gain']['track']['originator'] = $parsedFrame['track']['originator'];
1977:             $info['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment'];
1978:             $info['replay_gain']['album']['originator'] = $parsedFrame['album']['originator'];
1979:             $info['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment'];
1980: 
1981:             unset($parsedFrame['data']);
1982: 
1983:         } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'CHAP')) { // CHAP Chapters frame (ID3v2.3+ only)
1984:             // http://id3.org/id3v2-chapters-1.0
1985:             // <ID3v2.3 or ID3v2.4 frame header, ID: "CHAP">           (10 bytes)
1986:             // Element ID      <text string> $00
1987:             // Start time      $xx xx xx xx
1988:             // End time        $xx xx xx xx
1989:             // Start offset    $xx xx xx xx
1990:             // End offset      $xx xx xx xx
1991:             // <Optional embedded sub-frames>
1992: 
1993:             $frame_offset = 0;
1994:             @list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
1995:             $frame_offset += strlen($parsedFrame['element_id']."\x00");
1996:             $parsedFrame['time_begin'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1997:             $frame_offset += 4;
1998:             $parsedFrame['time_end']   = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1999:             $frame_offset += 4;
2000:             if (substr($parsedFrame['data'], $frame_offset, 4) != "\xFF\xFF\xFF\xFF") {
2001:                 // "If these bytes are all set to 0xFF then the value should be ignored and the start time value should be utilized."
2002:                 $parsedFrame['offset_begin'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2003:             }
2004:             $frame_offset += 4;
2005:             if (substr($parsedFrame['data'], $frame_offset, 4) != "\xFF\xFF\xFF\xFF") {
2006:                 // "If these bytes are all set to 0xFF then the value should be ignored and the start time value should be utilized."
2007:                 $parsedFrame['offset_end']   = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2008:             }
2009:             $frame_offset += 4;
2010: 
2011:             if ($frame_offset < strlen($parsedFrame['data'])) {
2012:                 $parsedFrame['subframes'] = array();
2013:                 while ($frame_offset < strlen($parsedFrame['data'])) {
2014:                     // <Optional embedded sub-frames>
2015:                     $subframe = array();
2016:                     $subframe['name']      =                           substr($parsedFrame['data'], $frame_offset, 4);
2017:                     $frame_offset += 4;
2018:                     $subframe['size']      = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2019:                     $frame_offset += 4;
2020:                     $subframe['flags_raw'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
2021:                     $frame_offset += 2;
2022:                     if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) {
2023:                         $info['warning'][] = 'CHAP subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)';
2024:                         break;
2025:                     }
2026:                     $subframe_rawdata = substr($parsedFrame['data'], $frame_offset, $subframe['size']);
2027:                     $frame_offset += $subframe['size'];
2028: 
2029:                     $subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
2030:                     $subframe['text']       =     substr($subframe_rawdata, 1);
2031:                     $subframe['encoding']   = $this->TextEncodingNameLookup($subframe['encodingid']);
2032:                     $encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
2033:                     switch (substr($encoding_converted_text, 0, 2)) {
2034:                         case "\xFF\xFE":
2035:                         case "\xFE\xFF":
2036:                             switch (strtoupper($info['id3v2']['encoding'])) {
2037:                                 case 'ISO-8859-1':
2038:                                 case 'UTF-8':
2039:                                     $encoding_converted_text = substr($encoding_converted_text, 2);
2040:                                     // remove unwanted byte-order-marks
2041:                                     break;
2042:                                 default:
2043:                                     // ignore
2044:                                     break;
2045:                             }
2046:                             break;
2047:                         default:
2048:                             // do not remove BOM
2049:                             break;
2050:                     }
2051: 
2052:                     if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
2053:                         if ($subframe['name'] == 'TIT2') {
2054:                             $parsedFrame['chapter_name']        = $encoding_converted_text;
2055:                         } elseif ($subframe['name'] == 'TIT3') {
2056:                             $parsedFrame['chapter_description'] = $encoding_converted_text;
2057:                         }
2058:                         $parsedFrame['subframes'][] = $subframe;
2059:                     } else {
2060:                         $info['warning'][] = 'ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)';
2061:                     }
2062:                 }
2063:                 unset($subframe_rawdata, $subframe, $encoding_converted_text);
2064:             }
2065: 
2066:             $id3v2_chapter_entry = array();
2067:             foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description') as $id3v2_chapter_key) {
2068:                 if (isset($parsedFrame[$id3v2_chapter_key])) {
2069:                     $id3v2_chapter_entry[$id3v2_chapter_key] = $parsedFrame[$id3v2_chapter_key];
2070:                 }
2071:             }
2072:             if (!isset($info['id3v2']['chapters'])) {
2073:                 $info['id3v2']['chapters'] = array();
2074:             }
2075:             $info['id3v2']['chapters'][] = $id3v2_chapter_entry;
2076:             unset($id3v2_chapter_entry, $id3v2_chapter_key);
2077: 
2078: 
2079:         } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'CTOC')) { // CTOC Chapters Table Of Contents frame (ID3v2.3+ only)
2080:             // http://id3.org/id3v2-chapters-1.0
2081:             // <ID3v2.3 or ID3v2.4 frame header, ID: "CTOC">           (10 bytes)
2082:             // Element ID      <text string> $00
2083:             // CTOC flags        %xx
2084:             // Entry count       $xx
2085:             // Child Element ID  <string>$00   /* zero or more child CHAP or CTOC entries */
2086:             // <Optional embedded sub-frames>
2087: 
2088:             $frame_offset = 0;
2089:             @list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
2090:             $frame_offset += strlen($parsedFrame['element_id']."\x00");
2091:             $ctoc_flags_raw = ord(substr($parsedFrame['data'], $frame_offset, 1));
2092:             $frame_offset += 1;
2093:             $parsedFrame['entry_count'] = ord(substr($parsedFrame['data'], $frame_offset, 1));
2094:             $frame_offset += 1;
2095: 
2096:             $terminator_position = null;
2097:             for ($i = 0; $i < $parsedFrame['entry_count']; $i++) {
2098:                 $terminator_position = strpos($parsedFrame['data'], "\x00", $frame_offset);
2099:                 $parsedFrame['child_element_ids'][$i] = substr($parsedFrame['data'], $frame_offset, $terminator_position - $frame_offset);
2100:                 $frame_offset = $terminator_position + 1;
2101:             }
2102: 
2103:             $parsedFrame['ctoc_flags']['ordered']   = (bool) ($ctoc_flags_raw & 0x01);
2104:             $parsedFrame['ctoc_flags']['top_level'] = (bool) ($ctoc_flags_raw & 0x03);
2105: 
2106:             unset($ctoc_flags_raw, $terminator_position);
2107: 
2108:             if ($frame_offset < strlen($parsedFrame['data'])) {
2109:                 $parsedFrame['subframes'] = array();
2110:                 while ($frame_offset < strlen($parsedFrame['data'])) {
2111:                     // <Optional embedded sub-frames>
2112:                     $subframe = array();
2113:                     $subframe['name']      =                           substr($parsedFrame['data'], $frame_offset, 4);
2114:                     $frame_offset += 4;
2115:                     $subframe['size']      = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2116:                     $frame_offset += 4;
2117:                     $subframe['flags_raw'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
2118:                     $frame_offset += 2;
2119:                     if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) {
2120:                         $info['warning'][] = 'CTOS subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)';
2121:                         break;
2122:                     }
2123:                     $subframe_rawdata = substr($parsedFrame['data'], $frame_offset, $subframe['size']);
2124:                     $frame_offset += $subframe['size'];
2125: 
2126:                     $subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
2127:                     $subframe['text']       =     substr($subframe_rawdata, 1);
2128:                     $subframe['encoding']   = $this->TextEncodingNameLookup($subframe['encodingid']);
2129:                     $encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
2130:                     switch (substr($encoding_converted_text, 0, 2)) {
2131:                         case "\xFF\xFE":
2132:                         case "\xFE\xFF":
2133:                             switch (strtoupper($info['id3v2']['encoding'])) {
2134:                                 case 'ISO-8859-1':
2135:                                 case 'UTF-8':
2136:                                     $encoding_converted_text = substr($encoding_converted_text, 2);
2137:                                     // remove unwanted byte-order-marks
2138:                                     break;
2139:                                 default:
2140:                                     // ignore
2141:                                     break;
2142:                             }
2143:                             break;
2144:                         default:
2145:                             // do not remove BOM
2146:                             break;
2147:                     }
2148: 
2149:                     if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
2150:                         if ($subframe['name'] == 'TIT2') {
2151:                             $parsedFrame['toc_name']        = $encoding_converted_text;
2152:                         } elseif ($subframe['name'] == 'TIT3') {
2153:                             $parsedFrame['toc_description'] = $encoding_converted_text;
2154:                         }
2155:                         $parsedFrame['subframes'][] = $subframe;
2156:                     } else {
2157:                         $info['warning'][] = 'ID3v2.CTOC subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)';
2158:                     }
2159:                 }
2160:                 unset($subframe_rawdata, $subframe, $encoding_converted_text);
2161:             }
2162: 
2163:         }
2164: 
2165:         return true;
2166:     }
2167: 
2168: 
2169:     public function DeUnsynchronise($data) {
2170:         return str_replace("\xFF\x00", "\xFF", $data);
2171:     }
2172: 
2173:     public function LookupExtendedHeaderRestrictionsTagSizeLimits($index) {
2174:         static $LookupExtendedHeaderRestrictionsTagSizeLimits = array(
2175:             0x00 => 'No more than 128 frames and 1 MB total tag size',
2176:             0x01 => 'No more than 64 frames and 128 KB total tag size',
2177:             0x02 => 'No more than 32 frames and 40 KB total tag size',
2178:             0x03 => 'No more than 32 frames and 4 KB total tag size',
2179:         );
2180:         return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : '');
2181:     }
2182: 
2183:     public function LookupExtendedHeaderRestrictionsTextEncodings($index) {
2184:         static $LookupExtendedHeaderRestrictionsTextEncodings = array(
2185:             0x00 => 'No restrictions',
2186:             0x01 => 'Strings are only encoded with ISO-8859-1 or UTF-8',
2187:         );
2188:         return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : '');
2189:     }
2190: 
2191:     public function LookupExtendedHeaderRestrictionsTextFieldSize($index) {
2192:         static $LookupExtendedHeaderRestrictionsTextFieldSize = array(
2193:             0x00 => 'No restrictions',
2194:             0x01 => 'No string is longer than 1024 characters',
2195:             0x02 => 'No string is longer than 128 characters',
2196:             0x03 => 'No string is longer than 30 characters',
2197:         );
2198:         return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : '');
2199:     }
2200: 
2201:     public function LookupExtendedHeaderRestrictionsImageEncoding($index) {
2202:         static $LookupExtendedHeaderRestrictionsImageEncoding = array(
2203:             0x00 => 'No restrictions',
2204:             0x01 => 'Images are encoded only with PNG or JPEG',
2205:         );
2206:         return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : '');
2207:     }
2208: 
2209:     public function LookupExtendedHeaderRestrictionsImageSizeSize($index) {
2210:         static $LookupExtendedHeaderRestrictionsImageSizeSize = array(
2211:             0x00 => 'No restrictions',
2212:             0x01 => 'All images are 256x256 pixels or smaller',
2213:             0x02 => 'All images are 64x64 pixels or smaller',
2214:             0x03 => 'All images are exactly 64x64 pixels, unless required otherwise',
2215:         );
2216:         return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : '');
2217:     }
2218: 
2219:     public function LookupCurrencyUnits($currencyid) {
2220: 
2221:         $begin = __LINE__;
2222: 
2223:         /** This is not a comment!
2224: 
2225: 
2226:             AED Dirhams
2227:             AFA Afghanis
2228:             ALL Leke
2229:             AMD Drams
2230:             ANG Guilders
2231:             AOA Kwanza
2232:             ARS Pesos
2233:             ATS Schillings
2234:             AUD Dollars
2235:             AWG Guilders
2236:             AZM Manats
2237:             BAM Convertible Marka
2238:             BBD Dollars
2239:             BDT Taka
2240:             BEF Francs
2241:             BGL Leva
2242:             BHD Dinars
2243:             BIF Francs
2244:             BMD Dollars
2245:             BND Dollars
2246:             BOB Bolivianos
2247:             BRL Brazil Real
2248:             BSD Dollars
2249:             BTN Ngultrum
2250:             BWP Pulas
2251:             BYR Rubles
2252:             BZD Dollars
2253:             CAD Dollars
2254:             CDF Congolese Francs
2255:             CHF Francs
2256:             CLP Pesos
2257:             CNY Yuan Renminbi
2258:             COP Pesos
2259:             CRC Colones
2260:             CUP Pesos
2261:             CVE Escudos
2262:             CYP Pounds
2263:             CZK Koruny
2264:             DEM Deutsche Marks
2265:             DJF Francs
2266:             DKK Kroner
2267:             DOP Pesos
2268:             DZD Algeria Dinars
2269:             EEK Krooni
2270:             EGP Pounds
2271:             ERN Nakfa
2272:             ESP Pesetas
2273:             ETB Birr
2274:             EUR Euro
2275:             FIM Markkaa
2276:             FJD Dollars
2277:             FKP Pounds
2278:             FRF Francs
2279:             GBP Pounds
2280:             GEL Lari
2281:             GGP Pounds
2282:             GHC Cedis
2283:             GIP Pounds
2284:             GMD Dalasi
2285:             GNF Francs
2286:             GRD Drachmae
2287:             GTQ Quetzales
2288:             GYD Dollars
2289:             HKD Dollars
2290:             HNL Lempiras
2291:             HRK Kuna
2292:             HTG Gourdes
2293:             HUF Forints
2294:             IDR Rupiahs
2295:             IEP Pounds
2296:             ILS New Shekels
2297:             IMP Pounds
2298:             INR Rupees
2299:             IQD Dinars
2300:             IRR Rials
2301:             ISK Kronur
2302:             ITL Lire
2303:             JEP Pounds
2304:             JMD Dollars
2305:             JOD Dinars
2306:             JPY Yen
2307:             KES Shillings
2308:             KGS Soms
2309:             KHR Riels
2310:             KMF Francs
2311:             KPW Won
2312:             KWD Dinars
2313:             KYD Dollars
2314:             KZT Tenge
2315:             LAK Kips
2316:             LBP Pounds
2317:             LKR Rupees
2318:             LRD Dollars
2319:             LSL Maloti
2320:             LTL Litai
2321:             LUF Francs
2322:             LVL Lati
2323:             LYD Dinars
2324:             MAD Dirhams
2325:             MDL Lei
2326:             MGF Malagasy Francs
2327:             MKD Denars
2328:             MMK Kyats
2329:             MNT Tugriks
2330:             MOP Patacas
2331:             MRO Ouguiyas
2332:             MTL Liri
2333:             MUR Rupees
2334:             MVR Rufiyaa
2335:             MWK Kwachas
2336:             MXN Pesos
2337:             MYR Ringgits
2338:             MZM Meticais
2339:             NAD Dollars
2340:             NGN Nairas
2341:             NIO Gold Cordobas
2342:             NLG Guilders
2343:             NOK Krone
2344:             NPR Nepal Rupees
2345:             NZD Dollars
2346:             OMR Rials
2347:             PAB Balboa
2348:             PEN Nuevos Soles
2349:             PGK Kina
2350:             PHP Pesos
2351:             PKR Rupees
2352:             PLN Zlotych
2353:             PTE Escudos
2354:             PYG Guarani
2355:             QAR Rials
2356:             ROL Lei
2357:             RUR Rubles
2358:             RWF Rwanda Francs
2359:             SAR Riyals
2360:             SBD Dollars
2361:             SCR Rupees
2362:             SDD Dinars
2363:             SEK Kronor
2364:             SGD Dollars
2365:             SHP Pounds
2366:             SIT Tolars
2367:             SKK Koruny
2368:             SLL Leones
2369:             SOS Shillings
2370:             SPL Luigini
2371:             SRG Guilders
2372:             STD Dobras
2373:             SVC Colones
2374:             SYP Pounds
2375:             SZL Emalangeni
2376:             THB Baht
2377:             TJR Rubles
2378:             TMM Manats
2379:             TND Dinars
2380:             TOP Pa'anga
2381:             TRL Liras
2382:             TTD Dollars
2383:             TVD Tuvalu Dollars
2384:             TWD New Dollars
2385:             TZS Shillings
2386:             UAH Hryvnia
2387:             UGX Shillings
2388:             USD Dollars
2389:             UYU Pesos
2390:             UZS Sums
2391:             VAL Lire
2392:             VEB Bolivares
2393:             VND Dong
2394:             VUV Vatu
2395:             WST Tala
2396:             XAF Francs
2397:             XAG Ounces
2398:             XAU Ounces
2399:             XCD Dollars
2400:             XDR Special Drawing Rights
2401:             XPD Ounces
2402:             XPF Francs
2403:             XPT Ounces
2404:             YER Rials
2405:             YUM New Dinars
2406:             ZAR Rand
2407:             ZMK Kwacha
2408:             ZWD Zimbabwe Dollars
2409: 
2410:         */
2411: 
2412:         return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units');
2413:     }
2414: 
2415: 
2416:     public function LookupCurrencyCountry($currencyid) {
2417: 
2418:         $begin = __LINE__;
2419: 
2420:         /** This is not a comment!
2421: 
2422:             AED United Arab Emirates
2423:             AFA Afghanistan
2424:             ALL Albania
2425:             AMD Armenia
2426:             ANG Netherlands Antilles
2427:             AOA Angola
2428:             ARS Argentina
2429:             ATS Austria
2430:             AUD Australia
2431:             AWG Aruba
2432:             AZM Azerbaijan
2433:             BAM Bosnia and Herzegovina
2434:             BBD Barbados
2435:             BDT Bangladesh
2436:             BEF Belgium
2437:             BGL Bulgaria
2438:             BHD Bahrain
2439:             BIF Burundi
2440:             BMD Bermuda
2441:             BND Brunei Darussalam
2442:             BOB Bolivia
2443:             BRL Brazil
2444:             BSD Bahamas
2445:             BTN Bhutan
2446:             BWP Botswana
2447:             BYR Belarus
2448:             BZD Belize
2449:             CAD Canada
2450:             CDF Congo/Kinshasa
2451:             CHF Switzerland
2452:             CLP Chile
2453:             CNY China
2454:             COP Colombia
2455:             CRC Costa Rica
2456:             CUP Cuba
2457:             CVE Cape Verde
2458:             CYP Cyprus
2459:             CZK Czech Republic
2460:             DEM Germany
2461:             DJF Djibouti
2462:             DKK Denmark
2463:             DOP Dominican Republic
2464:             DZD Algeria
2465:             EEK Estonia
2466:             EGP Egypt
2467:             ERN Eritrea
2468:             ESP Spain
2469:             ETB Ethiopia
2470:             EUR Euro Member Countries
2471:             FIM Finland
2472:             FJD Fiji
2473:             FKP Falkland Islands (Malvinas)
2474:             FRF France
2475:             GBP United Kingdom
2476:             GEL Georgia
2477:             GGP Guernsey
2478:             GHC Ghana
2479:             GIP Gibraltar
2480:             GMD Gambia
2481:             GNF Guinea
2482:             GRD Greece
2483:             GTQ Guatemala
2484:             GYD Guyana
2485:             HKD Hong Kong
2486:             HNL Honduras
2487:             HRK Croatia
2488:             HTG Haiti
2489:             HUF Hungary
2490:             IDR Indonesia
2491:             IEP Ireland (Eire)
2492:             ILS Israel
2493:             IMP Isle of Man
2494:             INR India
2495:             IQD Iraq
2496:             IRR Iran
2497:             ISK Iceland
2498:             ITL Italy
2499:             JEP Jersey
2500:             JMD Jamaica
2501:             JOD Jordan
2502:             JPY Japan
2503:             KES Kenya
2504:             KGS Kyrgyzstan
2505:             KHR Cambodia
2506:             KMF Comoros
2507:             KPW Korea
2508:             KWD Kuwait
2509:             KYD Cayman Islands
2510:             KZT Kazakstan
2511:             LAK Laos
2512:             LBP Lebanon
2513:             LKR Sri Lanka
2514:             LRD Liberia
2515:             LSL Lesotho
2516:             LTL Lithuania
2517:             LUF Luxembourg
2518:             LVL Latvia
2519:             LYD Libya
2520:             MAD Morocco
2521:             MDL Moldova
2522:             MGF Madagascar
2523:             MKD Macedonia
2524:             MMK Myanmar (Burma)
2525:             MNT Mongolia
2526:             MOP Macau
2527:             MRO Mauritania
2528:             MTL Malta
2529:             MUR Mauritius
2530:             MVR Maldives (Maldive Islands)
2531:             MWK Malawi
2532:             MXN Mexico
2533:             MYR Malaysia
2534:             MZM Mozambique
2535:             NAD Namibia
2536:             NGN Nigeria
2537:             NIO Nicaragua
2538:             NLG Netherlands (Holland)
2539:             NOK Norway
2540:             NPR Nepal
2541:             NZD New Zealand
2542:             OMR Oman
2543:             PAB Panama
2544:             PEN Peru
2545:             PGK Papua New Guinea
2546:             PHP Philippines
2547:             PKR Pakistan
2548:             PLN Poland
2549:             PTE Portugal
2550:             PYG Paraguay
2551:             QAR Qatar
2552:             ROL Romania
2553:             RUR Russia
2554:             RWF Rwanda
2555:             SAR Saudi Arabia
2556:             SBD Solomon Islands
2557:             SCR Seychelles
2558:             SDD Sudan
2559:             SEK Sweden
2560:             SGD Singapore
2561:             SHP Saint Helena
2562:             SIT Slovenia
2563:             SKK Slovakia
2564:             SLL Sierra Leone
2565:             SOS Somalia
2566:             SPL Seborga
2567:             SRG Suriname
2568:             STD São Tome and Principe
2569:             SVC El Salvador
2570:             SYP Syria
2571:             SZL Swaziland
2572:             THB Thailand
2573:             TJR Tajikistan
2574:             TMM Turkmenistan
2575:             TND Tunisia
2576:             TOP Tonga
2577:             TRL Turkey
2578:             TTD Trinidad and Tobago
2579:             TVD Tuvalu
2580:             TWD Taiwan
2581:             TZS Tanzania
2582:             UAH Ukraine
2583:             UGX Uganda
2584:             USD United States of America
2585:             UYU Uruguay
2586:             UZS Uzbekistan
2587:             VAL Vatican City
2588:             VEB Venezuela
2589:             VND Viet Nam
2590:             VUV Vanuatu
2591:             WST Samoa
2592:             XAF Communauté Financière Africaine
2593:             XAG Silver
2594:             XAU Gold
2595:             XCD East Caribbean
2596:             XDR International Monetary Fund
2597:             XPD Palladium
2598:             XPF Comptoirs Français du Pacifique
2599:             XPT Platinum
2600:             YER Yemen
2601:             YUM Yugoslavia
2602:             ZAR South Africa
2603:             ZMK Zambia
2604:             ZWD Zimbabwe
2605: 
2606:         */
2607: 
2608:         return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country');
2609:     }
2610: 
2611: 
2612: 
2613:     public static function LanguageLookup($languagecode, $casesensitive=false) {
2614: 
2615:         if (!$casesensitive) {
2616:             $languagecode = strtolower($languagecode);
2617:         }
2618: 
2619:         // http://www.id3.org/id3v2.4.0-structure.txt
2620:         // [4.   ID3v2 frame overview]
2621:         // The three byte language field, present in several frames, is used to
2622:         // describe the language of the frame's content, according to ISO-639-2
2623:         // [ISO-639-2]. The language should be represented in lower case. If the
2624:         // language is not known the string "XXX" should be used.
2625: 
2626: 
2627:         // ISO 639-2 - http://www.id3.org/iso639-2.html
2628: 
2629:         $begin = __LINE__;
2630: 
2631:         /** This is not a comment!
2632: 
2633:             XXX unknown
2634:             xxx unknown
2635:             aar Afar
2636:             abk Abkhazian
2637:             ace Achinese
2638:             ach Acoli
2639:             ada Adangme
2640:             afa Afro-Asiatic (Other)
2641:             afh Afrihili
2642:             afr Afrikaans
2643:             aka Akan
2644:             akk Akkadian
2645:             alb Albanian
2646:             ale Aleut
2647:             alg Algonquian Languages
2648:             amh Amharic
2649:             ang English, Old (ca. 450-1100)
2650:             apa Apache Languages
2651:             ara Arabic
2652:             arc Aramaic
2653:             arm Armenian
2654:             arn Araucanian
2655:             arp Arapaho
2656:             art Artificial (Other)
2657:             arw Arawak
2658:             asm Assamese
2659:             ath Athapascan Languages
2660:             ava Avaric
2661:             ave Avestan
2662:             awa Awadhi
2663:             aym Aymara
2664:             aze Azerbaijani
2665:             bad Banda
2666:             bai Bamileke Languages
2667:             bak Bashkir
2668:             bal Baluchi
2669:             bam Bambara
2670:             ban Balinese
2671:             baq Basque
2672:             bas Basa
2673:             bat Baltic (Other)
2674:             bej Beja
2675:             bel Byelorussian
2676:             bem Bemba
2677:             ben Bengali
2678:             ber Berber (Other)
2679:             bho Bhojpuri
2680:             bih Bihari
2681:             bik Bikol
2682:             bin Bini
2683:             bis Bislama
2684:             bla Siksika
2685:             bnt Bantu (Other)
2686:             bod Tibetan
2687:             bra Braj
2688:             bre Breton
2689:             bua Buriat
2690:             bug Buginese
2691:             bul Bulgarian
2692:             bur Burmese
2693:             cad Caddo
2694:             cai Central American Indian (Other)
2695:             car Carib
2696:             cat Catalan
2697:             cau Caucasian (Other)
2698:             ceb Cebuano
2699:             cel Celtic (Other)
2700:             ces Czech
2701:             cha Chamorro
2702:             chb Chibcha
2703:             che Chechen
2704:             chg Chagatai
2705:             chi Chinese
2706:             chm Mari
2707:             chn Chinook jargon
2708:             cho Choctaw
2709:             chr Cherokee
2710:             chu Church Slavic
2711:             chv Chuvash
2712:             chy Cheyenne
2713:             cop Coptic
2714:             cor Cornish
2715:             cos Corsican
2716:             cpe Creoles and Pidgins, English-based (Other)
2717:             cpf Creoles and Pidgins, French-based (Other)
2718:             cpp Creoles and Pidgins, Portuguese-based (Other)
2719:             cre Cree
2720:             crp Creoles and Pidgins (Other)
2721:             cus Cushitic (Other)
2722:             cym Welsh
2723:             cze Czech
2724:             dak Dakota
2725:             dan Danish
2726:             del Delaware
2727:             deu German
2728:             din Dinka
2729:             div Divehi
2730:             doi Dogri
2731:             dra Dravidian (Other)
2732:             dua Duala
2733:             dum Dutch, Middle (ca. 1050-1350)
2734:             dut Dutch
2735:             dyu Dyula
2736:             dzo Dzongkha
2737:             efi Efik
2738:             egy Egyptian (Ancient)
2739:             eka Ekajuk
2740:             ell Greek, Modern (1453-)
2741:             elx Elamite
2742:             eng English
2743:             enm English, Middle (ca. 1100-1500)
2744:             epo Esperanto
2745:             esk Eskimo (Other)
2746:             esl Spanish
2747:             est Estonian
2748:             eus Basque
2749:             ewe Ewe
2750:             ewo Ewondo
2751:             fan Fang
2752:             fao Faroese
2753:             fas Persian
2754:             fat Fanti
2755:             fij Fijian
2756:             fin Finnish
2757:             fiu Finno-Ugrian (Other)
2758:             fon Fon
2759:             fra French
2760:             fre French
2761:             frm French, Middle (ca. 1400-1600)
2762:             fro French, Old (842- ca. 1400)
2763:             fry Frisian
2764:             ful Fulah
2765:             gaa Ga
2766:             gae Gaelic (Scots)
2767:             gai Irish
2768:             gay Gayo
2769:             gdh Gaelic (Scots)
2770:             gem Germanic (Other)
2771:             geo Georgian
2772:             ger German
2773:             gez Geez
2774:             gil Gilbertese
2775:             glg Gallegan
2776:             gmh German, Middle High (ca. 1050-1500)
2777:             goh German, Old High (ca. 750-1050)
2778:             gon Gondi
2779:             got Gothic
2780:             grb Grebo
2781:             grc Greek, Ancient (to 1453)
2782:             gre Greek, Modern (1453-)
2783:             grn Guarani
2784:             guj Gujarati
2785:             hai Haida
2786:             hau Hausa
2787:             haw Hawaiian
2788:             heb Hebrew
2789:             her Herero
2790:             hil Hiligaynon
2791:             him Himachali
2792:             hin Hindi
2793:             hmo Hiri Motu
2794:             hun Hungarian
2795:             hup Hupa
2796:             hye Armenian
2797:             iba Iban
2798:             ibo Igbo
2799:             ice Icelandic
2800:             ijo Ijo
2801:             iku Inuktitut
2802:             ilo Iloko
2803:             ina Interlingua (International Auxiliary language Association)
2804:             inc Indic (Other)
2805:             ind Indonesian
2806:             ine Indo-European (Other)
2807:             ine Interlingue
2808:             ipk Inupiak
2809:             ira Iranian (Other)
2810:             iri Irish
2811:             iro Iroquoian uages
2812:             isl Icelandic
2813:             ita Italian
2814:             jav Javanese
2815:             jaw Javanese
2816:             jpn Japanese
2817:             jpr Judeo-Persian
2818:             jrb Judeo-Arabic
2819:             kaa Kara-Kalpak
2820:             kab Kabyle
2821:             kac Kachin
2822:             kal Greenlandic
2823:             kam Kamba
2824:             kan Kannada
2825:             kar Karen
2826:             kas Kashmiri
2827:             kat Georgian
2828:             kau Kanuri
2829:             kaw Kawi
2830:             kaz Kazakh
2831:             kha Khasi
2832:             khi Khoisan (Other)
2833:             khm Khmer
2834:             kho Khotanese
2835:             kik Kikuyu
2836:             kin Kinyarwanda
2837:             kir Kirghiz
2838:             kok Konkani
2839:             kom Komi
2840:             kon Kongo
2841:             kor Korean
2842:             kpe Kpelle
2843:             kro Kru
2844:             kru Kurukh
2845:             kua Kuanyama
2846:             kum Kumyk
2847:             kur Kurdish
2848:             kus Kusaie
2849:             kut Kutenai
2850:             lad Ladino
2851:             lah Lahnda
2852:             lam Lamba
2853:             lao Lao
2854:             lat Latin
2855:             lav Latvian
2856:             lez Lezghian
2857:             lin Lingala
2858:             lit Lithuanian
2859:             lol Mongo
2860:             loz Lozi
2861:             ltz Letzeburgesch
2862:             lub Luba-Katanga
2863:             lug Ganda
2864:             lui Luiseno
2865:             lun Lunda
2866:             luo Luo (Kenya and Tanzania)
2867:             mac Macedonian
2868:             mad Madurese
2869:             mag Magahi
2870:             mah Marshall
2871:             mai Maithili
2872:             mak Macedonian
2873:             mak Makasar
2874:             mal Malayalam
2875:             man Mandingo
2876:             mao Maori
2877:             map Austronesian (Other)
2878:             mar Marathi
2879:             mas Masai
2880:             max Manx
2881:             may Malay
2882:             men Mende
2883:             mga Irish, Middle (900 - 1200)
2884:             mic Micmac
2885:             min Minangkabau
2886:             mis Miscellaneous (Other)
2887:             mkh Mon-Kmer (Other)
2888:             mlg Malagasy
2889:             mlt Maltese
2890:             mni Manipuri
2891:             mno Manobo Languages
2892:             moh Mohawk
2893:             mol Moldavian
2894:             mon Mongolian
2895:             mos Mossi
2896:             mri Maori
2897:             msa Malay
2898:             mul Multiple Languages
2899:             mun Munda Languages
2900:             mus Creek
2901:             mwr Marwari
2902:             mya Burmese
2903:             myn Mayan Languages
2904:             nah Aztec
2905:             nai North American Indian (Other)
2906:             nau Nauru
2907:             nav Navajo
2908:             nbl Ndebele, South
2909:             nde Ndebele, North
2910:             ndo Ndongo
2911:             nep Nepali
2912:             new Newari
2913:             nic Niger-Kordofanian (Other)
2914:             niu Niuean
2915:             nla Dutch
2916:             nno Norwegian (Nynorsk)
2917:             non Norse, Old
2918:             nor Norwegian
2919:             nso Sotho, Northern
2920:             nub Nubian Languages
2921:             nya Nyanja
2922:             nym Nyamwezi
2923:             nyn Nyankole
2924:             nyo Nyoro
2925:             nzi Nzima
2926:             oci Langue d'Oc (post 1500)
2927:             oji Ojibwa
2928:             ori Oriya
2929:             orm Oromo
2930:             osa Osage
2931:             oss Ossetic
2932:             ota Turkish, Ottoman (1500 - 1928)
2933:             oto Otomian Languages
2934:             paa Papuan-Australian (Other)
2935:             pag Pangasinan
2936:             pal Pahlavi
2937:             pam Pampanga
2938:             pan Panjabi
2939:             pap Papiamento
2940:             pau Palauan
2941:             peo Persian, Old (ca 600 - 400 B.C.)
2942:             per Persian
2943:             phn Phoenician
2944:             pli Pali
2945:             pol Polish
2946:             pon Ponape
2947:             por Portuguese
2948:             pra Prakrit uages
2949:             pro Provencal, Old (to 1500)
2950:             pus Pushto
2951:             que Quechua
2952:             raj Rajasthani
2953:             rar Rarotongan
2954:             roa Romance (Other)
2955:             roh Rhaeto-Romance
2956:             rom Romany
2957:             ron Romanian
2958:             rum Romanian
2959:             run Rundi
2960:             rus Russian
2961:             sad Sandawe
2962:             sag Sango
2963:             sah Yakut
2964:             sai South American Indian (Other)
2965:             sal Salishan Languages
2966:             sam Samaritan Aramaic
2967:             san Sanskrit
2968:             sco Scots
2969:             scr Serbo-Croatian
2970:             sel Selkup
2971:             sem Semitic (Other)
2972:             sga Irish, Old (to 900)
2973:             shn Shan
2974:             sid Sidamo
2975:             sin Singhalese
2976:             sio Siouan Languages
2977:             sit Sino-Tibetan (Other)
2978:             sla Slavic (Other)
2979:             slk Slovak
2980:             slo Slovak
2981:             slv Slovenian
2982:             smi Sami Languages
2983:             smo Samoan
2984:             sna Shona
2985:             snd Sindhi
2986:             sog Sogdian
2987:             som Somali
2988:             son Songhai
2989:             sot Sotho, Southern
2990:             spa Spanish
2991:             sqi Albanian
2992:             srd Sardinian
2993:             srr Serer
2994:             ssa Nilo-Saharan (Other)
2995:             ssw Siswant
2996:             ssw Swazi
2997:             suk Sukuma
2998:             sun Sudanese
2999:             sus Susu
3000:             sux Sumerian
3001:             sve Swedish
3002:             swa Swahili
3003:             swe Swedish
3004:             syr Syriac
3005:             tah Tahitian
3006:             tam Tamil
3007:             tat Tatar
3008:             tel Telugu
3009:             tem Timne
3010:             ter Tereno
3011:             tgk Tajik
3012:             tgl Tagalog
3013:             tha Thai
3014:             tib Tibetan
3015:             tig Tigre
3016:             tir Tigrinya
3017:             tiv Tivi
3018:             tli Tlingit
3019:             tmh Tamashek
3020:             tog Tonga (Nyasa)
3021:             ton Tonga (Tonga Islands)
3022:             tru Truk
3023:             tsi Tsimshian
3024:             tsn Tswana
3025:             tso Tsonga
3026:             tuk Turkmen
3027:             tum Tumbuka
3028:             tur Turkish
3029:             tut Altaic (Other)
3030:             twi Twi
3031:             tyv Tuvinian
3032:             uga Ugaritic
3033:             uig Uighur
3034:             ukr Ukrainian
3035:             umb Umbundu
3036:             und Undetermined
3037:             urd Urdu
3038:             uzb Uzbek
3039:             vai Vai
3040:             ven Venda
3041:             vie Vietnamese
3042:             vol Volapük
3043:             vot Votic
3044:             wak Wakashan Languages
3045:             wal Walamo
3046:             war Waray
3047:             was Washo
3048:             wel Welsh
3049:             wen Sorbian Languages
3050:             wol Wolof
3051:             xho Xhosa
3052:             yao Yao
3053:             yap Yap
3054:             yid Yiddish
3055:             yor Yoruba
3056:             zap Zapotec
3057:             zen Zenaga
3058:             zha Zhuang
3059:             zho Chinese
3060:             zul Zulu
3061:             zun Zuni
3062: 
3063:         */
3064: 
3065:         return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode');
3066:     }
3067: 
3068: 
3069:     public static function ETCOEventLookup($index) {
3070:         if (($index >= 0x17) && ($index <= 0xDF)) {
3071:             return 'reserved for future use';
3072:         }
3073:         if (($index >= 0xE0) && ($index <= 0xEF)) {
3074:             return 'not predefined synch 0-F';
3075:         }
3076:         if (($index >= 0xF0) && ($index <= 0xFC)) {
3077:             return 'reserved for future use';
3078:         }
3079: 
3080:         static $EventLookup = array(
3081:             0x00 => 'padding (has no meaning)',
3082:             0x01 => 'end of initial silence',
3083:             0x02 => 'intro start',
3084:             0x03 => 'main part start',
3085:             0x04 => 'outro start',
3086:             0x05 => 'outro end',
3087:             0x06 => 'verse start',
3088:             0x07 => 'refrain start',
3089:             0x08 => 'interlude start',
3090:             0x09 => 'theme start',
3091:             0x0A => 'variation start',
3092:             0x0B => 'key change',
3093:             0x0C => 'time change',
3094:             0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)',
3095:             0x0E => 'sustained noise',
3096:             0x0F => 'sustained noise end',
3097:             0x10 => 'intro end',
3098:             0x11 => 'main part end',
3099:             0x12 => 'verse end',
3100:             0x13 => 'refrain end',
3101:             0x14 => 'theme end',
3102:             0x15 => 'profanity',
3103:             0x16 => 'profanity end',
3104:             0xFD => 'audio end (start of silence)',
3105:             0xFE => 'audio file ends',
3106:             0xFF => 'one more byte of events follows'
3107:         );
3108: 
3109:         return (isset($EventLookup[$index]) ? $EventLookup[$index] : '');
3110:     }
3111: 
3112:     public static function SYTLContentTypeLookup($index) {
3113:         static $SYTLContentTypeLookup = array(
3114:             0x00 => 'other',
3115:             0x01 => 'lyrics',
3116:             0x02 => 'text transcription',
3117:             0x03 => 'movement/part name', // (e.g. 'Adagio')
3118:             0x04 => 'events',             // (e.g. 'Don Quijote enters the stage')
3119:             0x05 => 'chord',              // (e.g. 'Bb F Fsus')
3120:             0x06 => 'trivia/\'pop up\' information',
3121:             0x07 => 'URLs to webpages',
3122:             0x08 => 'URLs to images'
3123:         );
3124: 
3125:         return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : '');
3126:     }
3127: 
3128:     public static function APICPictureTypeLookup($index, $returnarray=false) {
3129:         static $APICPictureTypeLookup = array(
3130:             0x00 => 'Other',
3131:             0x01 => '32x32 pixels \'file icon\' (PNG only)',
3132:             0x02 => 'Other file icon',
3133:             0x03 => 'Cover (front)',
3134:             0x04 => 'Cover (back)',
3135:             0x05 => 'Leaflet page',
3136:             0x06 => 'Media (e.g. label side of CD)',
3137:             0x07 => 'Lead artist/lead performer/soloist',
3138:             0x08 => 'Artist/performer',
3139:             0x09 => 'Conductor',
3140:             0x0A => 'Band/Orchestra',
3141:             0x0B => 'Composer',
3142:             0x0C => 'Lyricist/text writer',
3143:             0x0D => 'Recording Location',
3144:             0x0E => 'During recording',
3145:             0x0F => 'During performance',
3146:             0x10 => 'Movie/video screen capture',
3147:             0x11 => 'A bright coloured fish',
3148:             0x12 => 'Illustration',
3149:             0x13 => 'Band/artist logotype',
3150:             0x14 => 'Publisher/Studio logotype'
3151:         );
3152:         if ($returnarray) {
3153:             return $APICPictureTypeLookup;
3154:         }
3155:         return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : '');
3156:     }
3157: 
3158:     public static function COMRReceivedAsLookup($index) {
3159:         static $COMRReceivedAsLookup = array(
3160:             0x00 => 'Other',
3161:             0x01 => 'Standard CD album with other songs',
3162:             0x02 => 'Compressed audio on CD',
3163:             0x03 => 'File over the Internet',
3164:             0x04 => 'Stream over the Internet',
3165:             0x05 => 'As note sheets',
3166:             0x06 => 'As note sheets in a book with other sheets',
3167:             0x07 => 'Music on other media',
3168:             0x08 => 'Non-musical merchandise'
3169:         );
3170: 
3171:         return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : '');
3172:     }
3173: 
3174:     public static function RVA2ChannelTypeLookup($index) {
3175:         static $RVA2ChannelTypeLookup = array(
3176:             0x00 => 'Other',
3177:             0x01 => 'Master volume',
3178:             0x02 => 'Front right',
3179:             0x03 => 'Front left',
3180:             0x04 => 'Back right',
3181:             0x05 => 'Back left',
3182:             0x06 => 'Front centre',
3183:             0x07 => 'Back centre',
3184:             0x08 => 'Subwoofer'
3185:         );
3186: 
3187:         return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : '');
3188:     }
3189: 
3190:     public static function FrameNameLongLookup($framename) {
3191: 
3192:         $begin = __LINE__;
3193: 
3194:         /** This is not a comment!
3195: 
3196:             AENC    Audio encryption
3197:             APIC    Attached picture
3198:             ASPI    Audio seek point index
3199:             BUF Recommended buffer size
3200:             CNT Play counter
3201:             COM Comments
3202:             COMM    Comments
3203:             COMR    Commercial frame
3204:             CRA Audio encryption
3205:             CRM Encrypted meta frame
3206:             ENCR    Encryption method registration
3207:             EQU Equalisation
3208:             EQU2    Equalisation (2)
3209:             EQUA    Equalisation
3210:             ETC Event timing codes
3211:             ETCO    Event timing codes
3212:             GEO General encapsulated object
3213:             GEOB    General encapsulated object
3214:             GRID    Group identification registration
3215:             IPL Involved people list
3216:             IPLS    Involved people list
3217:             LINK    Linked information
3218:             LNK Linked information
3219:             MCDI    Music CD identifier
3220:             MCI Music CD Identifier
3221:             MLL MPEG location lookup table
3222:             MLLT    MPEG location lookup table
3223:             OWNE    Ownership frame
3224:             PCNT    Play counter
3225:             PIC Attached picture
3226:             POP Popularimeter
3227:             POPM    Popularimeter
3228:             POSS    Position synchronisation frame
3229:             PRIV    Private frame
3230:             RBUF    Recommended buffer size
3231:             REV Reverb
3232:             RVA Relative volume adjustment
3233:             RVA2    Relative volume adjustment (2)
3234:             RVAD    Relative volume adjustment
3235:             RVRB    Reverb
3236:             SEEK    Seek frame
3237:             SIGN    Signature frame
3238:             SLT Synchronised lyric/text
3239:             STC Synced tempo codes
3240:             SYLT    Synchronised lyric/text
3241:             SYTC    Synchronised tempo codes
3242:             TAL Album/Movie/Show title
3243:             TALB    Album/Movie/Show title
3244:             TBP BPM (Beats Per Minute)
3245:             TBPM    BPM (beats per minute)
3246:             TCM Composer
3247:             TCMP    Part of a compilation
3248:             TCO Content type
3249:             TCOM    Composer
3250:             TCON    Content type
3251:             TCOP    Copyright message
3252:             TCP Part of a compilation
3253:             TCR Copyright message
3254:             TDA Date
3255:             TDAT    Date
3256:             TDEN    Encoding time
3257:             TDLY    Playlist delay
3258:             TDOR    Original release time
3259:             TDRC    Recording time
3260:             TDRL    Release time
3261:             TDTG    Tagging time
3262:             TDY Playlist delay
3263:             TEN Encoded by
3264:             TENC    Encoded by
3265:             TEXT    Lyricist/Text writer
3266:             TFLT    File type
3267:             TFT File type
3268:             TIM Time
3269:             TIME    Time
3270:             TIPL    Involved people list
3271:             TIT1    Content group description
3272:             TIT2    Title/songname/content description
3273:             TIT3    Subtitle/Description refinement
3274:             TKE Initial key
3275:             TKEY    Initial key
3276:             TLA Language(s)
3277:             TLAN    Language(s)
3278:             TLE Length
3279:             TLEN    Length
3280:             TMCL    Musician credits list
3281:             TMED    Media type
3282:             TMOO    Mood
3283:             TMT Media type
3284:             TOA Original artist(s)/performer(s)
3285:             TOAL    Original album/movie/show title
3286:             TOF Original filename
3287:             TOFN    Original filename
3288:             TOL Original Lyricist(s)/text writer(s)
3289:             TOLY    Original lyricist(s)/text writer(s)
3290:             TOPE    Original artist(s)/performer(s)
3291:             TOR Original release year
3292:             TORY    Original release year
3293:             TOT Original album/Movie/Show title
3294:             TOWN    File owner/licensee
3295:             TP1 Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group
3296:             TP2 Band/Orchestra/Accompaniment
3297:             TP3 Conductor/Performer refinement
3298:             TP4 Interpreted, remixed, or otherwise modified by
3299:             TPA Part of a set
3300:             TPB Publisher
3301:             TPE1    Lead performer(s)/Soloist(s)
3302:             TPE2    Band/orchestra/accompaniment
3303:             TPE3    Conductor/performer refinement
3304:             TPE4    Interpreted, remixed, or otherwise modified by
3305:             TPOS    Part of a set
3306:             TPRO    Produced notice
3307:             TPUB    Publisher
3308:             TRC ISRC (International Standard Recording Code)
3309:             TRCK    Track number/Position in set
3310:             TRD Recording dates
3311:             TRDA    Recording dates
3312:             TRK Track number/Position in set
3313:             TRSN    Internet radio station name
3314:             TRSO    Internet radio station owner
3315:             TS2 Album-Artist sort order
3316:             TSA Album sort order
3317:             TSC Composer sort order
3318:             TSI Size
3319:             TSIZ    Size
3320:             TSO2    Album-Artist sort order
3321:             TSOA    Album sort order
3322:             TSOC    Composer sort order
3323:             TSOP    Performer sort order
3324:             TSOT    Title sort order
3325:             TSP Performer sort order
3326:             TSRC    ISRC (international standard recording code)
3327:             TSS Software/hardware and settings used for encoding
3328:             TSSE    Software/Hardware and settings used for encoding
3329:             TSST    Set subtitle
3330:             TST Title sort order
3331:             TT1 Content group description
3332:             TT2 Title/Songname/Content description
3333:             TT3 Subtitle/Description refinement
3334:             TXT Lyricist/text writer
3335:             TXX User defined text information frame
3336:             TXXX    User defined text information frame
3337:             TYE Year
3338:             TYER    Year
3339:             UFI Unique file identifier
3340:             UFID    Unique file identifier
3341:             ULT Unsychronised lyric/text transcription
3342:             USER    Terms of use
3343:             USLT    Unsynchronised lyric/text transcription
3344:             WAF Official audio file webpage
3345:             WAR Official artist/performer webpage
3346:             WAS Official audio source webpage
3347:             WCM Commercial information
3348:             WCOM    Commercial information
3349:             WCOP    Copyright/Legal information
3350:             WCP Copyright/Legal information
3351:             WOAF    Official audio file webpage
3352:             WOAR    Official artist/performer webpage
3353:             WOAS    Official audio source webpage
3354:             WORS    Official Internet radio station homepage
3355:             WPAY    Payment
3356:             WPB Publishers official webpage
3357:             WPUB    Publishers official webpage
3358:             WXX User defined URL link frame
3359:             WXXX    User defined URL link frame
3360:             TFEA    Featured Artist
3361:             TSTU    Recording Studio
3362:             rgad    Replay Gain Adjustment
3363: 
3364:         */
3365: 
3366:         return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long');
3367: 
3368:         // Last three:
3369:         // from Helium2 [www.helium2.com]
3370:         // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
3371:     }
3372: 
3373: 
3374:     public static function FrameNameShortLookup($framename) {
3375: 
3376:         $begin = __LINE__;
3377: 
3378:         /** This is not a comment!
3379: 
3380:             AENC    audio_encryption
3381:             APIC    attached_picture
3382:             ASPI    audio_seek_point_index
3383:             BUF recommended_buffer_size
3384:             CNT play_counter
3385:             COM comment
3386:             COMM    comment
3387:             COMR    commercial_frame
3388:             CRA audio_encryption
3389:             CRM encrypted_meta_frame
3390:             ENCR    encryption_method_registration
3391:             EQU equalisation
3392:             EQU2    equalisation
3393:             EQUA    equalisation
3394:             ETC event_timing_codes
3395:             ETCO    event_timing_codes
3396:             GEO general_encapsulated_object
3397:             GEOB    general_encapsulated_object
3398:             GRID    group_identification_registration
3399:             IPL involved_people_list
3400:             IPLS    involved_people_list
3401:             LINK    linked_information
3402:             LNK linked_information
3403:             MCDI    music_cd_identifier
3404:             MCI music_cd_identifier
3405:             MLL mpeg_location_lookup_table
3406:             MLLT    mpeg_location_lookup_table
3407:             OWNE    ownership_frame
3408:             PCNT    play_counter
3409:             PIC attached_picture
3410:             POP popularimeter
3411:             POPM    popularimeter
3412:             POSS    position_synchronisation_frame
3413:             PRIV    private_frame
3414:             RBUF    recommended_buffer_size
3415:             REV reverb
3416:             RVA relative_volume_adjustment
3417:             RVA2    relative_volume_adjustment
3418:             RVAD    relative_volume_adjustment
3419:             RVRB    reverb
3420:             SEEK    seek_frame
3421:             SIGN    signature_frame
3422:             SLT synchronised_lyric
3423:             STC synced_tempo_codes
3424:             SYLT    synchronised_lyric
3425:             SYTC    synchronised_tempo_codes
3426:             TAL album
3427:             TALB    album
3428:             TBP bpm
3429:             TBPM    bpm
3430:             TCM composer
3431:             TCMP    part_of_a_compilation
3432:             TCO genre
3433:             TCOM    composer
3434:             TCON    genre
3435:             TCOP    copyright_message
3436:             TCP part_of_a_compilation
3437:             TCR copyright_message
3438:             TDA date
3439:             TDAT    date
3440:             TDEN    encoding_time
3441:             TDLY    playlist_delay
3442:             TDOR    original_release_time
3443:             TDRC    recording_time
3444:             TDRL    release_time
3445:             TDTG    tagging_time
3446:             TDY playlist_delay
3447:             TEN encoded_by
3448:             TENC    encoded_by
3449:             TEXT    lyricist
3450:             TFLT    file_type
3451:             TFT file_type
3452:             TIM time
3453:             TIME    time
3454:             TIPL    involved_people_list
3455:             TIT1    content_group_description
3456:             TIT2    title
3457:             TIT3    subtitle
3458:             TKE initial_key
3459:             TKEY    initial_key
3460:             TLA language
3461:             TLAN    language
3462:             TLE length
3463:             TLEN    length
3464:             TMCL    musician_credits_list
3465:             TMED    media_type
3466:             TMOO    mood
3467:             TMT media_type
3468:             TOA original_artist
3469:             TOAL    original_album
3470:             TOF original_filename
3471:             TOFN    original_filename
3472:             TOL original_lyricist
3473:             TOLY    original_lyricist
3474:             TOPE    original_artist
3475:             TOR original_year
3476:             TORY    original_year
3477:             TOT original_album
3478:             TOWN    file_owner
3479:             TP1 artist
3480:             TP2 band
3481:             TP3 conductor
3482:             TP4 remixer
3483:             TPA part_of_a_set
3484:             TPB publisher
3485:             TPE1    artist
3486:             TPE2    band
3487:             TPE3    conductor
3488:             TPE4    remixer
3489:             TPOS    part_of_a_set
3490:             TPRO    produced_notice
3491:             TPUB    publisher
3492:             TRC isrc
3493:             TRCK    track_number
3494:             TRD recording_dates
3495:             TRDA    recording_dates
3496:             TRK track_number
3497:             TRSN    internet_radio_station_name
3498:             TRSO    internet_radio_station_owner
3499:             TS2 album_artist_sort_order
3500:             TSA album_sort_order
3501:             TSC composer_sort_order
3502:             TSI size
3503:             TSIZ    size
3504:             TSO2    album_artist_sort_order
3505:             TSOA    album_sort_order
3506:             TSOC    composer_sort_order
3507:             TSOP    performer_sort_order
3508:             TSOT    title_sort_order
3509:             TSP performer_sort_order
3510:             TSRC    isrc
3511:             TSS encoder_settings
3512:             TSSE    encoder_settings
3513:             TSST    set_subtitle
3514:             TST title_sort_order
3515:             TT1 content_group_description
3516:             TT2 title
3517:             TT3 subtitle
3518:             TXT lyricist
3519:             TXX text
3520:             TXXX    text
3521:             TYE year
3522:             TYER    year
3523:             UFI unique_file_identifier
3524:             UFID    unique_file_identifier
3525:             ULT unsychronised_lyric
3526:             USER    terms_of_use
3527:             USLT    unsynchronised_lyric
3528:             WAF url_file
3529:             WAR url_artist
3530:             WAS url_source
3531:             WCM commercial_information
3532:             WCOM    commercial_information
3533:             WCOP    copyright
3534:             WCP copyright
3535:             WOAF    url_file
3536:             WOAR    url_artist
3537:             WOAS    url_source
3538:             WORS    url_station
3539:             WPAY    url_payment
3540:             WPB url_publisher
3541:             WPUB    url_publisher
3542:             WXX url_user
3543:             WXXX    url_user
3544:             TFEA    featured_artist
3545:             TSTU    recording_studio
3546:             rgad    replay_gain_adjustment
3547: 
3548:         */
3549: 
3550:         return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
3551:     }
3552: 
3553:     public static function TextEncodingTerminatorLookup($encoding) {
3554:         // http://www.id3.org/id3v2.4.0-structure.txt
3555:         // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
3556:         static $TextEncodingTerminatorLookup = array(
3557:             0   => "\x00",     // $00  ISO-8859-1. Terminated with $00.
3558:             1   => "\x00\x00", // $01  UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
3559:             2   => "\x00\x00", // $02  UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
3560:             3   => "\x00",     // $03  UTF-8 encoded Unicode. Terminated with $00.
3561:             255 => "\x00\x00"
3562:         );
3563:         return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : "\x00");
3564:     }
3565: 
3566:     public static function TextEncodingNameLookup($encoding) {
3567:         // http://www.id3.org/id3v2.4.0-structure.txt
3568:         // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
3569:         static $TextEncodingNameLookup = array(
3570:             0   => 'ISO-8859-1', // $00  ISO-8859-1. Terminated with $00.
3571:             1   => 'UTF-16',     // $01  UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
3572:             2   => 'UTF-16BE',   // $02  UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
3573:             3   => 'UTF-8',      // $03  UTF-8 encoded Unicode. Terminated with $00.
3574:             255 => 'UTF-16BE'
3575:         );
3576:         return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1');
3577:     }
3578: 
3579:     public static function IsValidID3v2FrameName($framename, $id3v2majorversion) {
3580:         switch ($id3v2majorversion) {
3581:             case 2:
3582:                 return preg_match('#[A-Z][A-Z0-9]{2}#', $framename);
3583:                 break;
3584: 
3585:             case 3:
3586:             case 4:
3587:                 return preg_match('#[A-Z][A-Z0-9]{3}#', $framename);
3588:                 break;
3589:         }
3590:         return false;
3591:     }
3592: 
3593:     public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) {
3594:         for ($i = 0; $i < strlen($numberstring); $i++) {
3595:             if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) {
3596:                 if (($numberstring{$i} == '.') && $allowdecimal) {
3597:                     // allowed
3598:                 } elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) {
3599:                     // allowed
3600:                 } else {
3601:                     return false;
3602:                 }
3603:             }
3604:         }
3605:         return true;
3606:     }
3607: 
3608:     public static function IsValidDateStampString($datestamp) {
3609:         if (strlen($datestamp) != 8) {
3610:             return false;
3611:         }
3612:         if (!self::IsANumber($datestamp, false)) {
3613:             return false;
3614:         }
3615:         $year  = substr($datestamp, 0, 4);
3616:         $month = substr($datestamp, 4, 2);
3617:         $day   = substr($datestamp, 6, 2);
3618:         if (($year == 0) || ($month == 0) || ($day == 0)) {
3619:             return false;
3620:         }
3621:         if ($month > 12) {
3622:             return false;
3623:         }
3624:         if ($day > 31) {
3625:             return false;
3626:         }
3627:         if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) {
3628:             return false;
3629:         }
3630:         if (($day > 29) && ($month == 2)) {
3631:             return false;
3632:         }
3633:         return true;
3634:     }
3635: 
3636:     public static function ID3v2HeaderLength($majorversion) {
3637:         return (($majorversion == 2) ? 6 : 10);
3638:     }
3639: 
3640: }
3641: 
3642: 
Zenphoto doc API documentation generated by ApiGen