diff --git a/livesupport/modules/getid3/var/getid3.aiff.php b/livesupport/modules/getid3/var/getid3.aiff.php new file mode 100644 index 000000000..bcd0f2809 --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.aiff.php @@ -0,0 +1,21 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.aiff.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function getAIFFHeaderFilepointer(&$fd, &$ThisFileInfo) { + + $ThisFileInfo['fileformat'] = 'aiff'; + + $ThisFileInfo['error'] .= "\n".'AIFF parsing not enabled in this version of getID3()'; + return false; + +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.asf.php b/livesupport/modules/getid3/var/getid3.asf.php new file mode 100644 index 000000000..51b32a0a2 --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.asf.php @@ -0,0 +1,1289 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.asf.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +$GUIDarray = KnownGUIDs(); +foreach ($GUIDarray as $GUIDname => $hexstringvalue) { + // initialize all GUID constants + define($GUIDname, GUIDtoBytestring($hexstringvalue)); +} + +function getASFHeaderFilepointer(&$fd, &$ThisFileInfo) { + // ASF structure: + // * Header Object [required] + // * File Properties Object [required] (global file attributes) + // * Stream Properties Object [required] (defines media stream & characteristics) + // * Header Extension Object [required] (additional functionality) + // * Content Description Object (bibliographic information) + // * Script Command Object (commands for during playback) + // * Marker Object (named jumped points within the file) + // * Data Object [required] + // * Data Packets + // * Index Object + + // Header Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for header object - ASF_Header_Object + // Object Size QWORD 64 // size of header object, including 30 bytes of Header Object header + // Number of Header Objects DWORD 32 // number of objects in header object + // Reserved1 BYTE 8 // hardcoded: 0x01 + // Reserved2 BYTE 8 // hardcoded: 0x02 + + $ThisFileInfo['fileformat'] = 'asf'; + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + $HeaderObjectData = fread($fd, 30); + + $ThisFileInfo['asf']['header_object']['objectid'] = substr($HeaderObjectData, 0, 16); + $ThisFileInfo['asf']['header_object']['objectid_guid'] = BytestringToGUID($ThisFileInfo['asf']['header_object']['objectid']); + if ($ThisFileInfo['asf']['header_object']['objectid'] != ASF_Header_Object) { + $ThisFileInfo['warning'] .= "\n".'ASF header GUID {'.BytestringToGUID($ThisFileInfo['asf']['header_object']['objectid']).'} does not match expected "ASF_Header_Object" GUID {'.BytestringToGUID(ASF_Header_Object).'}'; + //return false; + break; + } + $ThisFileInfo['asf']['header_object']['objectsize'] = LittleEndian2Int(substr($HeaderObjectData, 16, 8)); + $ThisFileInfo['asf']['header_object']['headerobjects'] = LittleEndian2Int(substr($HeaderObjectData, 24, 4)); + $ThisFileInfo['asf']['header_object']['reserved1'] = LittleEndian2Int(substr($HeaderObjectData, 28, 1)); + $ThisFileInfo['asf']['header_object']['reserved2'] = LittleEndian2Int(substr($HeaderObjectData, 29, 1)); + + //$ASFHeaderData = $HeaderObjectData; + $ASFHeaderData = fread($fd, $ThisFileInfo['asf']['header_object']['objectsize'] - 30); + //$offset = 30; + $offset = 0; + + for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $ThisFileInfo['asf']['header_object']['headerobjects']; $HeaderObjectsCounter++) { + $NextObjectGUID = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $NextObjectGUIDtext = BytestringToGUID($NextObjectGUID); + $NextObjectSize = LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + switch ($NextObjectGUID) { + + case ASF_File_Properties_Object: + // File Properties Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for file properties object - ASF_File_Properties_Object + // Object Size QWORD 64 // size of file properties object, including 104 bytes of File Properties Object header + // File ID GUID 128 // unique ID - identical to File ID in Data Object + // File Size QWORD 64 // entire file in bytes. Invalid if Broadcast Flag == 1 + // Creation Date QWORD 64 // date & time of file creation. Maybe invalid if Broadcast Flag == 1 + // Data Packets Count QWORD 64 // number of data packets in Data Object. Invalid if Broadcast Flag == 1 + // Play Duration QWORD 64 // playtime, in 100-nanosecond units. Invalid if Broadcast Flag == 1 + // Send Duration QWORD 64 // time needed to send file, in 100-nanosecond units. Players can ignore this value. Invalid if Broadcast Flag == 1 + // Preroll QWORD 64 // time to buffer data before starting to play file, in 1-millisecond units. If <> 0, PlayDuration and PresentationTime have been offset by this amount + // Flags DWORD 32 // + // * Broadcast Flag bits 1 (0x01) // file is currently being written, some header values are invalid + // * Seekable Flag bits 1 (0x02) // is file seekable + // * Reserved bits 30 (0xFFFFFFFC) // reserved - set to zero + // Minimum Data Packet Size DWORD 32 // in bytes. should be same as Maximum Data Packet Size. Invalid if Broadcast Flag == 1 + // Maximum Data Packet Size DWORD 32 // in bytes. should be same as Minimum Data Packet Size. Invalid if Broadcast Flag == 1 + // Maximum Bitrate DWORD 32 // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead + + $ThisFileInfo['asf']['file_properties_object']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['file_properties_object']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['file_properties_object']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['file_properties_object']['fileid'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $ThisFileInfo['asf']['file_properties_object']['fileid_guid'] = BytestringToGUID($ThisFileInfo['asf']['file_properties_object']['fileid']); + $ThisFileInfo['asf']['file_properties_object']['filesize'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $ThisFileInfo['asf']['file_properties_object']['creation_date'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $ThisFileInfo['asf']['file_properties_object']['creation_date_unix'] = FILETIMEtoUNIXtime($ThisFileInfo['asf']['file_properties_object']['creation_date']); + $offset += 8; + $ThisFileInfo['asf']['file_properties_object']['data_packets'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $ThisFileInfo['asf']['file_properties_object']['play_duration'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $ThisFileInfo['asf']['file_properties_object']['send_duration'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $ThisFileInfo['asf']['file_properties_object']['preroll'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['asf']['file_properties_object']['play_duration'] / 10000000) - ($ThisFileInfo['asf']['file_properties_object']['preroll'] / 1000); + $ThisFileInfo['asf']['file_properties_object']['flags_raw'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['file_properties_object']['flags']['broadcast'] = (bool) ($ThisFileInfo['asf']['file_properties_object']['flags_raw'] & 0x0001); + $ThisFileInfo['asf']['file_properties_object']['flags']['seekable'] = (bool) ($ThisFileInfo['asf']['file_properties_object']['flags_raw'] & 0x0002); + + $ThisFileInfo['asf']['file_properties_object']['min_packet_size'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['file_properties_object']['max_packet_size'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['file_properties_object']['max_bitrate'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $ThisFileInfo['bitrate'] = $ThisFileInfo['asf']['file_properties_object']['max_bitrate']; + break; + + case ASF_Stream_Properties_Object: + // Stream Properties Object: (mandatory, one per media stream) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for stream properties object - ASF_Stream_Properties_Object + // Object Size QWORD 64 // size of stream properties object, including 78 bytes of Stream Properties Object header + // Stream Type GUID 128 // ASF_Audio_Media, ASF_Video_Media or ASF_Command_Media + // Error Correction Type GUID 128 // ASF_Audio_Spread for audio-only streams, ASF_No_Error_Correction for other stream types + // Time Offset QWORD 64 // 100-nanosecond units. typically zero. added to all timestamps of samples in the stream + // Type-Specific Data Length DWORD 32 // number of bytes for Type-Specific Data field + // Error Correction Data Length DWORD 32 // number of bytes for Error Correction Data field + // Flags WORD 16 // + // * Stream Number bits 7 (0x007F) // number of this stream. 1 <= valid <= 127 + // * Reserved bits 8 (0x7F80) // reserved - set to zero + // * Encrypted Content Flag bits 1 (0x8000) // stream contents encrypted if set + // Reserved DWORD 32 // reserved - set to zero + // Type-Specific Data BYTESTREAM variable // type-specific format data, depending on value of Stream Type + // Error Correction Data BYTESTREAM variable // error-correction-specific format data, depending on value of Error Correct Type + + // There is one ASF_Stream_Properties_Object for each stream (audio, video) but the + // stream number isn't known until halfway through decoding the structure, hence it + // it is decoded to a temporary variable and then stuck in the appropriate index later + + $StreamPropertiesObjectData['objectid'] = $NextObjectGUID; + $StreamPropertiesObjectData['objectid_guid'] = $NextObjectGUIDtext; + $StreamPropertiesObjectData['objectsize'] = $NextObjectSize; + $StreamPropertiesObjectData['stream_type'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $StreamPropertiesObjectData['stream_type_guid'] = BytestringToGUID($StreamPropertiesObjectData['stream_type']); + $StreamPropertiesObjectData['error_correct_type'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $StreamPropertiesObjectData['error_correct_guid'] = BytestringToGUID($StreamPropertiesObjectData['error_correct_type']); + $StreamPropertiesObjectData['time_offset'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $StreamPropertiesObjectData['type_data_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $StreamPropertiesObjectData['error_data_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $StreamPropertiesObjectData['flags_raw'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $StreamPropertiesObjectStreamNumber = $StreamPropertiesObjectData['flags_raw'] & 0x007F; + $StreamPropertiesObjectData['flags']['encrypted'] = (bool) ($StreamPropertiesObjectData['flags_raw'] & 0x8000); + + $offset += 4; // reserved - DWORD + $StreamPropertiesObjectData['type_specific_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['type_data_length']); + $offset += $StreamPropertiesObjectData['type_data_length']; + $StreamPropertiesObjectData['error_correct_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['error_data_length']); + $offset += $StreamPropertiesObjectData['error_data_length']; + + switch ($StreamPropertiesObjectData['stream_type']) { + + case ASF_Audio_Media: + if (empty($ThisFileInfo['audio']['bitrate_mode'])) { + $ThisFileInfo['audio']['bitrate_mode'] = 'cbr'; + } + + require_once(GETID3_INCLUDEPATH.'getid3.riff.php'); + $audiodata = RIFFparseWAVEFORMATex(substr($StreamPropertiesObjectData['type_specific_data'], 0, 16)); + unset($audiodata['raw']); + $ThisFileInfo['audio'] = array_merge_noclobber($audiodata, $ThisFileInfo['audio']); + break; + + case ASF_Video_Media: + if (empty($ThisFileInfo['video']['bitrate_mode'])) { + $ThisFileInfo['video']['bitrate_mode'] = 'cbr'; + } + break; + + case ASF_Command_Media: + default: + // do nothing + break; + + } + + $ThisFileInfo['asf']['stream_properties_object'][$StreamPropertiesObjectStreamNumber] = $StreamPropertiesObjectData; + unset($StreamPropertiesObjectData); // clear for next stream, if any + break; + + case ASF_Header_Extension_Object: + // Header Extension Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Header Extension object - ASF_Header_Extension_Object + // Object Size QWORD 64 // size of Header Extension object, including 46 bytes of Header Extension Object header + // Reserved Field 1 GUID 128 // hardcoded: ASF_Reserved_1 + // Reserved Field 2 WORD 16 // hardcoded: 0x00000006 + // Header Extension Data Size DWORD 32 // in bytes. valid: 0, or > 24. equals object size minus 46 + // Header Extension Data BYTESTREAM variable // array of zero or more extended header objects + + $ThisFileInfo['asf']['header_extension_object']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['header_extension_object']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['header_extension_object']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['header_extension_object']['reserved_1'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $ThisFileInfo['asf']['header_extension_object']['reserved_1_guid'] = BytestringToGUID($ThisFileInfo['asf']['header_extension_object']['reserved_1']); + if ($ThisFileInfo['asf']['header_extension_object']['reserved_1'] != ASF_Reserved_1) { + $ThisFileInfo['warning'] .= "\n".'header_extension_object.reserved_1 GUID ('.BytestringToGUID($ThisFileInfo['asf']['header_extension_object']['reserved_1']).') does not match expected "ASF_Reserved_1" GUID ('.BytestringToGUID(ASF_Reserved_1).')'; + //return false; + break; + } + $ThisFileInfo['asf']['header_extension_object']['reserved_2'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + if ($ThisFileInfo['asf']['header_extension_object']['reserved_2'] != 6) { + $ThisFileInfo['warning'] .= "\n".'header_extension_object.reserved_2 ('.PrintHexBytes($ThisFileInfo['asf']['header_extension_object']['reserved_2']).') does not match expected value of "6"'; + //return false; + break; + } + $ThisFileInfo['asf']['header_extension_object']['extension_data_size'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['header_extension_object']['extension_data'] = LittleEndian2Int(substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['header_extension_object']['extension_data_size'])); + $offset += $ThisFileInfo['asf']['header_extension_object']['extension_data_size']; + break; + + case ASF_Codec_List_Object: + // Codec List Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Codec List object - ASF_Codec_List_Object + // Object Size QWORD 64 // size of Codec List object, including 44 bytes of Codec List Object header + // Reserved GUID 128 // hardcoded: 86D15241-311D-11D0-A3A4-00A0C90348F6 + // Codec Entries Count DWORD 32 // number of entries in Codec Entries array + // Codec Entries array of: variable // + // * Type WORD 16 // 0x0001 = Video Codec, 0x0002 = Audio Codec, 0xFFFF = Unknown Codec + // * Codec Name Length WORD 16 // number of Unicode characters stored in the Codec Name field + // * Codec Name WCHAR variable // array of Unicode characters - name of codec used to create the content + // * Codec Description Length WORD 16 // number of Unicode characters stored in the Codec Description field + // * Codec Description WCHAR variable // array of Unicode characters - description of format used to create the content + // * Codec Information Length WORD 16 // number of Unicode characters stored in the Codec Information field + // * Codec Information BYTESTREAM variable // opaque array of information bytes about the codec used to create the content + + $ThisFileInfo['asf']['codec_list']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['codec_list']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['codec_list']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['codec_list']['reserved'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $ThisFileInfo['asf']['codec_list']['reserved_guid'] = BytestringToGUID($ThisFileInfo['asf']['codec_list']['reserved']); + if ($ThisFileInfo['asf']['codec_list']['reserved'] != GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) { + $ThisFileInfo['warning'] .= "\n".'codec_list_object.reserved GUID {'.BytestringToGUID($ThisFileInfo['asf']['codec_list']['reserved']).'} does not match expected "ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}'; + //return false; + break; + } + $ThisFileInfo['asf']['codec_list']['codec_entries_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + for ($CodecEntryCounter = 0; $CodecEntryCounter < $ThisFileInfo['asf']['codec_list']['codec_entries_count']; $CodecEntryCounter++) { + $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['type_raw'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['type'] = ASFCodecListObjectTypeLookup($ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['type_raw']); + + $CodecNameLength = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['name'] = substr($ASFHeaderData, $offset, $CodecNameLength); + $offset += $CodecNameLength; + $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['name_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['name'], 2); + + $CodecDescriptionLength = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['description'] = substr($ASFHeaderData, $offset, $CodecDescriptionLength); + $offset += $CodecDescriptionLength; + $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['description_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['description'], 2); + + $CodecInformationLength = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['information'] = substr($ASFHeaderData, $offset, $CodecInformationLength); + $offset += $CodecInformationLength; + + if ($ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['type_raw'] == 2) { + // audio codec + $ThisFileInfo['audio']['codec'] = $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['name_ascii']; + list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['description_ascii']); + + if (!isset($ThisFileInfo['audio']['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) { + $ThisFileInfo['audio']['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000); + } + if (!isset($ThisFileInfo['video']['bitrate']) && isset($ThisFileInfo['audio']['bitrate']) && isset($ThisFileInfo['asf']['file_properties_object']['max_bitrate']) && ($ThisFileInfo['asf']['codec_list']['codec_entries_count'] > 1)) { + $ThisFileInfo['video']['bitrate'] = $ThisFileInfo['asf']['file_properties_object']['max_bitrate'] - $ThisFileInfo['audio']['bitrate']; + } + + $AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency)); + switch ($AudioCodecFrequency) { + case 8: + $ThisFileInfo['audio']['sample_rate'] = 8000; + break; + + case 11: + $ThisFileInfo['audio']['sample_rate'] = 11025; + break; + + case 16: + $ThisFileInfo['audio']['sample_rate'] = 16000; + break; + + case 22: + $ThisFileInfo['audio']['sample_rate'] = 22050; + break; + + case 32: + $ThisFileInfo['audio']['sample_rate'] = 32000; + break; + + case 44: + $ThisFileInfo['audio']['sample_rate'] = 44100; + break; + + case 48: + $ThisFileInfo['audio']['sample_rate'] = 48000; + break; + + default: + $ThisFileInfo['error'] .= "\n".'unknown frequency: '.$ThisFileInfo['asf']['codec_list']['codec_entries'][$CodecEntryCounter]['description_ascii']; + return false; + break; + } + + if (!isset($ThisFileInfo['audio']['channels'])) { + if (strstr($AudioCodecChannels, 'stereo')) { + $ThisFileInfo['audio']['channels'] = 2; + } elseif (strstr($AudioCodecChannels, 'mono')) { + $ThisFileInfo['audio']['channels'] = 1; + } + } + } + } + break; + + case ASF_Script_Command_Object: + // Script Command Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Script Command object - ASF_Script_Command_Object + // Object Size QWORD 64 // size of Script Command object, including 44 bytes of Script Command Object header + // Reserved GUID 128 // hardcoded: 4B1ACBE3-100B-11D0-A39B-00A0C90348F6 + // Commands Count WORD 16 // number of Commands structures in the Script Commands Objects + // Command Types Count WORD 16 // number of Command Types structures in the Script Commands Objects + // Command Types array of: variable // + // * Command Type Name Length WORD 16 // number of Unicode characters for Command Type Name + // * Command Type Name WCHAR variable // array of Unicode characters - name of a type of command + // Commands array of: variable // + // * Presentation Time DWORD 32 // presentation time of that command, in milliseconds + // * Type Index WORD 16 // type of this command, as a zero-based index into the array of Command Types of this object + // * Command Name Length WORD 16 // number of Unicode characters for Command Name + // * Command Name WCHAR variable // array of Unicode characters - name of this command + + $ThisFileInfo['asf']['script_command_object']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['script_command_object']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['script_command_object']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['script_command_object']['reserved'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $ThisFileInfo['asf']['script_command_object']['reserved_guid'] = BytestringToGUID($ThisFileInfo['asf']['script_command_object']['reserved']); + if ($ThisFileInfo['asf']['script_command_object']['reserved'] != GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) { + $ThisFileInfo['warning'] .= "\n".'script_command_object.reserved GUID {'.BytestringToGUID($ThisFileInfo['asf']['script_command_object']['reserved']).'} does not match expected "ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}'; + //return false; + break; + } + $ThisFileInfo['asf']['script_command_object']['commands_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['script_command_object']['command_types_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + for ($CommandTypesCounter = 0; $CommandTypesCounter < $ThisFileInfo['asf']['script_command_object']['command_types_count']; $CommandTypesCounter++) { + $CommandTypeNameLength = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + $ThisFileInfo['asf']['script_command_object']['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); + $offset += $CommandTypeNameLength; + $ThisFileInfo['asf']['script_command_object']['command_types'][$CommandTypesCounter]['name_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['script_command_object']['command_types'][$CommandTypesCounter]['name'], 2); + } + for ($CommandsCounter = 0; $CommandsCounter < $ThisFileInfo['asf']['script_command_object']['commands_count']; $CommandsCounter++) { + $ThisFileInfo['asf']['script_command_object']['commands'][$CommandsCounter]['presentation_time'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['script_command_object']['commands'][$CommandsCounter]['type_index'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + + $CommandTypeNameLength = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + $ThisFileInfo['asf']['script_command_object']['commands'][$CommandsCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); + $offset += $CommandTypeNameLength; + $ThisFileInfo['asf']['script_command_object']['commands'][$CommandsCounter]['name_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['script_command_object']['commands'][$CommandsCounter]['name'], 2); + } + break; + + case ASF_Marker_Object: + // Marker Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Marker object - ASF_Marker_Object + // Object Size QWORD 64 // size of Marker object, including 48 bytes of Marker Object header + // Reserved GUID 128 // hardcoded: 4CFEDB20-75F6-11CF-9C0F-00A0C90349CB + // Markers Count DWORD 32 // number of Marker structures in Marker Object + // Reserved WORD 16 // hardcoded: 0x0000 + // Name Length WORD 16 // number of bytes in the Name field + // Name WCHAR variable // name of the Marker Object + // Markers array of: variable // + // * Offset QWORD 64 // byte offset into Data Object + // * Presentation Time QWORD 64 // in 100-nanosecond units + // * Entry Length WORD 16 // length in bytes of (Send Time + Flags + Marker Description Length + Marker Description + Padding) + // * Send Time DWORD 32 // in milliseconds + // * Flags DWORD 32 // hardcoded: 0x00000000 + // * Marker Description Length DWORD 32 // number of bytes in Marker Description field + // * Marker Description WCHAR variable // array of Unicode characters - description of marker entry + // * Padding BYTESTREAM variable // optional padding bytes + + $ThisFileInfo['asf']['marker_object']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['marker_object']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['marker_object']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['marker_object']['reserved'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $ThisFileInfo['asf']['marker_object']['reserved_guid'] = BytestringToGUID($ThisFileInfo['asf']['marker_object']['reserved']); + if ($ThisFileInfo['asf']['marker_object']['reserved'] != GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) { + $ThisFileInfo['warning'] .= "\n".'marker_object.reserved GUID {'.BytestringToGUID($ThisFileInfo['asf']['marker_object']['reserved_1']).'} does not match expected "ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}'; + //return false; + break; + } + $ThisFileInfo['asf']['marker_object']['markers_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['marker_object']['reserved_2'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + if ($ThisFileInfo['asf']['marker_object']['reserved_2'] != 0) { + $ThisFileInfo['warning'] .= "\n".'marker_object.reserved_2 ('.PrintHexBytes($ThisFileInfo['asf']['marker_object']['reserved_2']).') does not match expected value of "0"'; + //return false; + break; + } + $ThisFileInfo['asf']['marker_object']['name_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['marker_object']['name'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['marker_object']['name_length']); + $offset += $ThisFileInfo['asf']['marker_object']['name_length']; + $ThisFileInfo['asf']['marker_object']['name_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['marker_object']['name'], 2); + for ($MarkersCounter = 0; $MarkersCounter < $ThisFileInfo['asf']['marker_object']['markers_count']; $MarkersCounter++) { + $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['offset'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['presentation_time'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['entry_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['send_time'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['flags'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description_length']); + $offset += $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description_length']; + $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description'], 2); + $PaddingLength = $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['entry_length'] - 4 - 4 - 4 - $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['marker_description_length']; + if ($PaddingLength > 0) { + $ThisFileInfo['asf']['marker_object']['markers'][$MarkersCounter]['padding'] = substr($ASFHeaderData, $offset, $PaddingLength); + $offset += $PaddingLength; + } + } + break; + + case ASF_Bitrate_Mutual_Exclusion_Object: + // Bitrate Mutual Exclusion Object: (optional) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Bitrate Mutual Exclusion object - ASF_Bitrate_Mutual_Exclusion_Object + // Object Size QWORD 64 // size of Bitrate Mutual Exclusion object, including 42 bytes of Bitrate Mutual Exclusion Object header + // Exlusion Type GUID 128 // nature of mutual exclusion relationship. one of: (ASF_Mutex_Bitrate, ASF_Mutex_Unknown) + // Stream Numbers Count WORD 16 // number of video streams + // Stream Numbers WORD variable // array of mutually exclusive video stream numbers. 1 <= valid <= 127 + + $ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['reserved'] = substr($ASFHeaderData, $offset, 16); + $ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['reserved_guid'] = BytestringToGUID($ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['reserved']); + $offset += 16; + if (($ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['reserved'] != ASF_Mutex_Bitrate) && ($ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['reserved'] != ASF_Mutex_Unknown)) { + $ThisFileInfo['warning'] .= "\n".'bitrate_mutual_exclusion_object.reserved GUID {'.BytestringToGUID($ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['reserved']).'} does not match expected "ASF_Mutex_Bitrate" GUID {'.BytestringToGUID(ASF_Mutex_Bitrate).'} or "ASF_Mutex_Unknown" GUID {'.BytestringToGUID(ASF_Mutex_Unknown).'}'; + //return false; + break; + } + $ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['stream_numbers_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + for ($StreamNumberCounter = 0; $StreamNumberCounter < $ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['markers_count']; $StreamNumberCounter++) { + $ThisFileInfo['asf']['bitrate_mutual_exclusion_object']['stream_numbers'][$StreamNumberCounter] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + } + break; + + case ASF_Error_Correction_Object: + // Error Correction Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Error Correction object - ASF_Error_Correction_Object + // Object Size QWORD 64 // size of Error Correction object, including 44 bytes of Error Correction Object header + // Error Correction Type GUID 128 // type of error correction. one of: (ASF_No_Error_Correction, ASF_Audio_Spread) + // Error Correction Data Length DWORD 32 // number of bytes in Error Correction Data field + // Error Correction Data BYTESTREAM variable // structure depends on value of Error Correction Type field + + $ThisFileInfo['asf']['error_correction_object']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['error_correction_object']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['error_correction_object']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['error_correction_object']['error_correction_type'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $ThisFileInfo['asf']['error_correction_object']['error_correction_guid'] = BytestringToGUID($ThisFileInfo['asf']['error_correction_object']['error_correction_type']); + $ThisFileInfo['asf']['error_correction_object']['error_correction_data_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + switch ($ThisFileInfo['asf']['error_correction_object']['error_correction_type']) { + case ASF_No_Error_Correction: + // should be no data, but just in case there is, skip to the end of the field + $offset += $ThisFileInfo['asf']['error_correction_object']['error_correction_data_length']; + break; + + case ASF_Audio_Spread: + // Field Name Field Type Size (bits) + // Span BYTE 8 // number of packets over which audio will be spread. + // Virtual Packet Length WORD 16 // size of largest audio payload found in audio stream + // Virtual Chunk Length WORD 16 // size of largest audio payload found in audio stream + // Silence Data Length WORD 16 // number of bytes in Silence Data field + // Silence Data BYTESTREAM variable // hardcoded: 0x00 * (Silence Data Length) bytes + + $ThisFileInfo['asf']['error_correction_object']['span'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 1)); + $offset += 1; + $ThisFileInfo['asf']['error_correction_object']['virtual_packet_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['error_correction_object']['virtual_chunk_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['error_correction_object']['silence_data_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['error_correction_object']['silence_data'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['error_correction_object']['silence_data_length']); + $offset += $ThisFileInfo['asf']['error_correction_object']['silence_data_length']; + break; + + default: + $ThisFileInfo['warning'] .= "\n".'error_correction_object.error_correction_type GUID {'.BytestringToGUID($ThisFileInfo['asf']['error_correction_object']['reserved']).'} does not match expected "ASF_No_Error_Correction" GUID {'.BytestringToGUID(ASF_No_Error_Correction).'} or "ASF_Audio_Spread" GUID {'.BytestringToGUID(ASF_Audio_Spread).'}'; + //return false; + break; + } + + break; + + case ASF_Content_Description_Object: + // Content Description Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Content Description object - ASF_Content_Description_Object + // Object Size QWORD 64 // size of Content Description object, including 34 bytes of Content Description Object header + // Title Length WORD 16 // number of bytes in Title field + // Author Length WORD 16 // number of bytes in Author field + // Copyright Length WORD 16 // number of bytes in Copyright field + // Description Length WORD 16 // number of bytes in Description field + // Rating Length WORD 16 // number of bytes in Rating field + // Title WCHAR 16 // array of Unicode characters - Title + // Author WCHAR 16 // array of Unicode characters - Author + // Copyright WCHAR 16 // array of Unicode characters - Copyright + // Description WCHAR 16 // array of Unicode characters - Description + // Rating WCHAR 16 // array of Unicode characters - Rating + + $ThisFileInfo['asf']['content_description']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['content_description']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['content_description']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['content_description']['title_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['content_description']['author_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['content_description']['copyright_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['content_description']['description_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['content_description']['rating_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['content_description']['title'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['content_description']['title_length']); + $offset += $ThisFileInfo['asf']['content_description']['title_length']; + $ThisFileInfo['asf']['content_description']['title_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['content_description']['title'], 2); + $ThisFileInfo['asf']['content_description']['author'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['content_description']['author_length']); + $offset += $ThisFileInfo['asf']['content_description']['author_length']; + $ThisFileInfo['asf']['content_description']['author_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['content_description']['author'], 2); + $ThisFileInfo['asf']['content_description']['copyright'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['content_description']['copyright_length']); + $offset += $ThisFileInfo['asf']['content_description']['copyright_length']; + $ThisFileInfo['asf']['content_description']['copyright_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['content_description']['copyright'], 2); + $ThisFileInfo['asf']['content_description']['description'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['content_description']['description_length']); + $offset += $ThisFileInfo['asf']['content_description']['description_length']; + $ThisFileInfo['asf']['content_description']['description_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['content_description']['description'], 2); + $ThisFileInfo['asf']['content_description']['rating'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['content_description']['rating_length']); + $offset += $ThisFileInfo['asf']['content_description']['rating_length']; + $ThisFileInfo['asf']['content_description']['rating_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['content_description']['rating'], 2); + + foreach (array('title', 'author', 'copyright', 'description', 'rating') as $keytocopy) { + if (!empty($ThisFileInfo['asf']['content_description'][$keytocopy.'_ascii'])) { + $ThisFileInfo['asf']['comments']["$keytocopy"] = $ThisFileInfo['asf']['content_description'][$keytocopy.'_ascii']; + } + } + + // ASF tags have highest priority + if (!empty($ThisFileInfo['asf']['comments'])) { + CopyFormatCommentsToRootComments($ThisFileInfo['asf']['comments'], $ThisFileInfo, true, true, true); + } + + // add tag to array of tags + $ThisFileInfo['tags'][] = 'asf'; + + break; + + case ASF_Extended_Content_Description_Object: + // Extended Content Description Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Extended Content Description object - ASF_Extended_Content_Description_Object + // Object Size QWORD 64 // size of ExtendedContent Description object, including 26 bytes of Extended Content Description Object header + // Content Descriptors Count WORD 16 // number of entries in Content Descriptors list + // Content Descriptors array of: variable // + // * Descriptor Name Length WORD 16 // size in bytes of Descriptor Name field + // * Descriptor Name WCHAR variable // array of Unicode characters - Descriptor Name + // * Descriptor Value Data Type WORD 16 // Lookup array: + // 0x0000 = Unicode String (variable length) + // 0x0001 = BYTE array (variable length) + // 0x0002 = BOOL (DWORD, 32 bits) + // 0x0003 = DWORD (DWORD, 32 bits) + // 0x0004 = QWORD (QWORD, 64 bits) + // 0x0005 = WORD (WORD, 16 bits) + // * Descriptor Value Length WORD 16 // number of bytes stored in Descriptor Value field + // * Descriptor Value variable variable // value for Content Descriptor + + $ThisFileInfo['asf']['extended_content_description']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['extended_content_description']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['extended_content_description']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['extended_content_description']['content_descriptors_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < $ThisFileInfo['asf']['extended_content_description']['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) { + $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['name_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['name'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['name_length']); + $offset += $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['name_length']; + $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['name_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['name'], 2); + $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value_type'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value_length'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value_length']); + $offset += $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value_length']; + switch ($ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value_type']) { + case 0x0000: // Unicode string + $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value'], 2); + break; + + case 0x0001: // BYTE array + // do nothing + break; + + case 0x0002: // BOOL + $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value'] = (bool) LittleEndian2Int($ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value']); + break; + + case 0x0003: // DWORD + case 0x0004: // QWORD + case 0x0005: // WORD + $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value'] = LittleEndian2Int($ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value']); + break; + + default: + $ThisFileInfo['warning'] .= "\n".'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value_type'].')'; + //return false; + break; + } + + switch ($ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['name_ascii']) { + case 'WM/AlbumTitle': + $ThisFileInfo['asf']['comments']['album'] = $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value_ascii']; + break; + + case 'WM/Genre': + $ThisFileInfo['asf']['comments']['genre'] = $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value_ascii']; + require_once(GETID3_INCLUDEPATH.'getid3.id3.php'); + $CleanedGenre = LookupGenre(LookupGenre($ThisFileInfo['asf']['comments']['genre'], true)); // convert to standard GenreID and back to standard spelling/capitalization + if ($CleanedGenre != $ThisFileInfo['asf']['comments']['genre']) { + $ThisFileInfo['asf']['comments']['genre'] = $CleanedGenre; + } + break; + + case 'WM/TrackNumber': + $ThisFileInfo['asf']['comments']['track'] = $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value']; + break; + + case 'WM/Track': + if (empty($ThisFileInfo['asf']['comments']['track'])) { + $ThisFileInfo['asf']['comments']['track'] = 1 + $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value']; + } + break; + + case 'WM/Year': + $ThisFileInfo['asf']['comments']['year'] = $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value_ascii']; + break; + + case 'IsVBR': + if ($ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value']) { + $ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; + $ThisFileInfo['video']['bitrate_mode'] = 'vbr'; + } + break; + + case 'ID3': + if ($tempfilehandle = tmpfile()) { + require_once(GETID3_INCLUDEPATH.'getid3.id3v2.php'); + $tempThisfileInfo = array(); + fwrite($tempfilehandle, $ThisFileInfo['asf']['extended_content_description']['content_descriptors'][$ExtendedContentDescriptorsCounter]['value']); + getID3v2Filepointer($tempfilehandle, $tempThisfileInfo); + fclose($tempfilehandle); + $ThisFileInfo['id3v2'] = $tempThisfileInfo['id3v2']; + } + break; + + default: + // do nothing + break; + } + + // ASF tags have highest priority + if (!empty($ThisFileInfo['asf']['comments'])) { + CopyFormatCommentsToRootComments($ThisFileInfo['asf']['comments'], $ThisFileInfo, true, true, true); + } + + } + break; + + case ASF_Stream_Bitrate_Properties_Object: + // Stream Bitrate Properties Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Stream Bitrate Properties object - ASF_Stream_Bitrate_Properties_Object + // Object Size QWORD 64 // size of Extended Content Description object, including 26 bytes of Stream Bitrate Properties Object header + // Bitrate Records Count WORD 16 // number of records in Bitrate Records + // Bitrate Records array of: variable // + // * Flags WORD 16 // + // * * Stream Number bits 7 (0x007F) // number of this stream + // * * Reserved bits 9 (0xFF80) // hardcoded: 0 + // * Average Bitrate DWORD 32 // in bits per second + + $ThisFileInfo['asf']['stream_bitrate_properties']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['stream_bitrate_properties']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['stream_bitrate_properties']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['stream_bitrate_properties']['bitrate_records_count'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $ThisFileInfo['asf']['stream_bitrate_properties']['bitrate_records_count']; $BitrateRecordsCounter++) { + $ThisFileInfo['asf']['stream_bitrate_properties']['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['stream_bitrate_properties']['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $ThisFileInfo['asf']['stream_bitrate_properties']['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F; + $ThisFileInfo['asf']['stream_bitrate_properties']['bitrate_records'][$BitrateRecordsCounter]['bitrate'] = LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + } + break; + + case ASF_Padding_Object: + // Padding Object: (optional) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Padding object - ASF_Padding_Object + // Object Size QWORD 64 // size of Padding object, including 24 bytes of Stream Bitrate Properties Object header + // Padding Data BYTESTREAM variable // ignore + $ThisFileInfo['asf']['padding_object']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['padding_object']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['padding_object']['objectsize'] = $NextObjectSize; + $ThisFileInfo['asf']['padding_object']['padding_length'] = $ThisFileInfo['asf']['padding_object']['objectsize'] - 16 - 8; + $ThisFileInfo['asf']['padding_object']['padding'] = substr($ASFHeaderData, $offset, $ThisFileInfo['asf']['padding_object']['padding_length']); + break; + + default: + // Implementations shall ignore any standard or non-standard object that they do not know how to handle. + if (GUIDname($NextObjectGUIDtext)) { + $ThisFileInfo['warning'] .= "\n".'unhandled GUID "'.GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8); + } else { + $ThisFileInfo['warning'] .= "\n".'unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8); + } + $offset += ($NextObjectSize - 16 - 8); + break; + } + } + if (isset($ThisFileInfo['asf']['stream_bitrate_properties']['bitrate_records_count'])) { + $ASFbitrateAudio = 0; + $ASFbitrateVideo = 0; + for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $ThisFileInfo['asf']['stream_bitrate_properties']['bitrate_records_count']; $BitrateRecordsCounter++) { + if (isset($ThisFileInfo['asf']['codec_list']['codec_entries'][$BitrateRecordsCounter])) { + switch ($ThisFileInfo['asf']['codec_list']['codec_entries'][$BitrateRecordsCounter]['type_raw']) { + case 1: + $ASFbitrateVideo += $ThisFileInfo['asf']['stream_bitrate_properties']['bitrate_records'][$BitrateRecordsCounter]['bitrate']; + break; + + case 2: + $ASFbitrateAudio += $ThisFileInfo['asf']['stream_bitrate_properties']['bitrate_records'][$BitrateRecordsCounter]['bitrate']; + break; + + default: + // do nothing + break; + } + } + } + if ($ASFbitrateAudio > 0) { + $ThisFileInfo['audio']['bitrate'] = $ASFbitrateAudio; + } + if ($ASFbitrateVideo > 0) { + $ThisFileInfo['video']['bitrate'] = $ASFbitrateVideo; + } + } + if (isset($ThisFileInfo['asf']['stream_properties_object']) && is_array($ThisFileInfo['asf']['stream_properties_object'])) { + require_once(GETID3_INCLUDEPATH.'getid3.riff.php'); + foreach ($ThisFileInfo['asf']['stream_properties_object'] as $streamnumber => $streamdata) { + switch ($streamdata['stream_type']) { + case ASF_Audio_Media: + // Field Name Field Type Size (bits) + // Codec ID / Format Tag WORD 16 // unique ID of audio codec - defined as wFormatTag field of WAVEFORMATEX structure + // Number of Channels WORD 16 // number of channels of audio - defined as nChannels field of WAVEFORMATEX structure + // Samples Per Second DWORD 32 // in Hertz - defined as nSamplesPerSec field of WAVEFORMATEX structure + // Average number of Bytes/sec DWORD 32 // bytes/sec of audio stream - defined as nAvgBytesPerSec field of WAVEFORMATEX structure + // Block Alignment WORD 16 // block size in bytes of audio codec - defined as nBlockAlign field of WAVEFORMATEX structure + // Bits per sample WORD 16 // bits per sample of mono data. set to zero for variable bitrate codecs. defined as wBitsPerSample field of WAVEFORMATEX structure + // Codec Specific Data Size WORD 16 // size in bytes of Codec Specific Data buffer - defined as cbSize field of WAVEFORMATEX structure + // Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes + + + $audiomediaoffset = 0; + + require_once(GETID3_INCLUDEPATH.'getid3.riff.php'); + $ThisFileInfo['asf']['audio_media'][$streamnumber] = RIFFparseWAVEFORMATex(substr($streamdata['type_specific_data'], $audiomediaoffset, 16)); + $audiomediaoffset += 16; + + if (!isset($ThisFileInfo['audio']['bitrate'])) { + $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['asf']['audio_media'][$streamnumber]['bytes_sec'] * 8; + } + $ThisFileInfo['asf']['audio_media'][$streamnumber]['codec_data_size'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $audiomediaoffset, 2)); + $audiomediaoffset += 2; + $ThisFileInfo['asf']['audio_media'][$streamnumber]['codec_data'] = substr($streamdata['type_specific_data'], $audiomediaoffset, $ThisFileInfo['asf']['audio_media'][$streamnumber]['codec_data_size']); + $audiomediaoffset += $ThisFileInfo['asf']['audio_media'][$streamnumber]['codec_data_size']; + break; + + case ASF_Video_Media: + // Field Name Field Type Size (bits) + // Encoded Image Width DWORD 32 // width of image in pixels + // Encoded Image Height DWORD 32 // height of image in pixels + // Reserved Flags BYTE 8 // hardcoded: 0x02 + // Format Data Size WORD 16 // size of Format Data field in bytes + // Format Data array of: variable // + // * Format Data Size DWORD 32 // number of bytes in Format Data field, in bytes - defined as biSize field of BITMAPINFOHEADER structure + // * Image Width LONG 32 // width of encoded image in pixels - defined as biWidth field of BITMAPINFOHEADER structure + // * Image Height LONG 32 // height of encoded image in pixels - defined as biHeight field of BITMAPINFOHEADER structure + // * Reserved WORD 16 // hardcoded: 0x0001 - defined as biPlanes field of BITMAPINFOHEADER structure + // * Bits Per Pixel Count WORD 16 // bits per pixel - defined as biBitCount field of BITMAPINFOHEADER structure + // * Compression ID FOURCC 32 // fourcc of video codec - defined as biCompression field of BITMAPINFOHEADER structure + // * Image Size DWORD 32 // image size in bytes - defined as biSizeImage field of BITMAPINFOHEADER structure + // * Horizontal Pixels / Meter DWORD 32 // horizontal resolution of target device in pixels per meter - defined as biXPelsPerMeter field of BITMAPINFOHEADER structure + // * Vertical Pixels / Meter DWORD 32 // vertical resolution of target device in pixels per meter - defined as biYPelsPerMeter field of BITMAPINFOHEADER structure + // * Colors Used Count DWORD 32 // number of color indexes in the color table that are actually used - defined as biClrUsed field of BITMAPINFOHEADER structure + // * Important Colors Count DWORD 32 // number of color index required for displaying bitmap. if zero, all colors are required. defined as biClrImportant field of BITMAPINFOHEADER structure + // * Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes + + $videomediaoffset = 0; + $ThisFileInfo['asf']['video_media'][$streamnumber]['image_width'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['image_height'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['flags'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 1)); + $videomediaoffset += 1; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data_size'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); + $videomediaoffset += 2; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['format_data_size'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['image_width'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['image_height'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['reserved'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); + $videomediaoffset += 2; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['bits_per_pixel'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); + $videomediaoffset += 2; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['codec_fourcc'] = substr($streamdata['type_specific_data'], $videomediaoffset, 4); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['image_size'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['horizontal_pels'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['vertical_pels'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['colors_used'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['colors_important'] = LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['codec_data'] = substr($streamdata['type_specific_data'], $videomediaoffset); + + + $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['codec'] = RIFFfourccLookup($ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['codec_fourcc']); + $ThisFileInfo['video']['codec'] = $ThisFileInfo['asf']['video_media'][$streamnumber]['format_data']['codec']; + $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['asf']['video_media'][$streamnumber]['image_width']; + $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['asf']['video_media'][$streamnumber]['image_height']; + break; + + default: + break; + } + } + } + + while (ftell($fd) < $ThisFileInfo['avdataend']) { + $NextObjectDataHeader = fread($fd, 24); + $offset = 0; + $NextObjectGUID = substr($NextObjectDataHeader, 0, 16); + $offset += 16; + $NextObjectGUIDtext = BytestringToGUID($NextObjectGUID); + $NextObjectSize = LittleEndian2Int(substr($NextObjectDataHeader, $offset, 8)); + $offset += 8; + + switch ($NextObjectGUID) { + case ASF_Data_Object: + // Data Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Data object - ASF_Data_Object + // Object Size QWORD 64 // size of Data object, including 50 bytes of Data Object header. may be 0 if FilePropertiesObject.BroadcastFlag == 1 + // File ID GUID 128 // unique identifier. identical to File ID field in Header Object + // Total Data Packets QWORD 64 // number of Data Packet entries in Data Object. invalid if FilePropertiesObject.BroadcastFlag == 1 + // Reserved WORD 16 // hardcoded: 0x0101 + + $DataObjectData = $NextObjectDataHeader.fread($fd, 50 - 24); + $offset = 24; + + $ThisFileInfo['asf']['data_object']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['data_object']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['data_object']['objectsize'] = $NextObjectSize; + + $ThisFileInfo['asf']['data_object']['fileid'] = substr($DataObjectData, $offset, 16); + $offset += 16; + $ThisFileInfo['asf']['data_object']['fileid_guid'] = BytestringToGUID($ThisFileInfo['asf']['data_object']['fileid']); + $ThisFileInfo['asf']['data_object']['total_data_packets'] = LittleEndian2Int(substr($DataObjectData, $offset, 8)); + $offset += 8; + $ThisFileInfo['asf']['data_object']['reserved'] = LittleEndian2Int(substr($DataObjectData, $offset, 2)); + $offset += 2; + if ($ThisFileInfo['asf']['data_object']['reserved'] != 0x0101) { + $ThisFileInfo['warning'] .= "\n".'data_object.reserved ('.PrintHexBytes($ThisFileInfo['asf']['data_object']['reserved']).') does not match expected value of "0x0101"'; + //return false; + break; + } + + // Data Packets array of: variable // + // * Error Correction Flags BYTE 8 // + // * * Error Correction Data Length bits 4 // if Error Correction Length Type == 00, size of Error Correction Data in bytes, else hardcoded: 0000 + // * * Opaque Data Present bits 1 // + // * * Error Correction Length Type bits 2 // number of bits for size of the error correction data. hardcoded: 00 + // * * Error Correction Present bits 1 // If set, use Opaque Data Packet structure, else use Payload structure + // * Error Correction Data + + $ThisFileInfo['avdataoffset'] = ftell($fd); + fseek($fd, ($ThisFileInfo['asf']['data_object']['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data + $ThisFileInfo['avdataend'] = ftell($fd); + break; + + case ASF_Simple_Index_Object: + // Simple Index Object: (optional, recommended, one per video stream) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Simple Index object - ASF_Data_Object + // Object Size QWORD 64 // size of Simple Index object, including 56 bytes of Simple Index Object header + // File ID GUID 128 // unique identifier. may be zero or identical to File ID field in Data Object and Header Object + // Index Entry Time Interval QWORD 64 // interval between index entries in 100-nanosecond units + // Maximum Packet Count DWORD 32 // maximum packet count for all index entries + // Index Entries Count DWORD 32 // number of Index Entries structures + // Index Entries array of: variable // + // * Packet Number DWORD 32 // number of the Data Packet associated with this index entry + // * Packet Count WORD 16 // number of Data Packets to sent at this index entry + + $SimpleIndexObjectData = $NextObjectDataHeader.fread($fd, 56 - 24); + $offset = 24; + + $ThisFileInfo['asf']['simple_index_object']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['simple_index_object']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['simple_index_object']['objectsize'] = $NextObjectSize; + + $ThisFileInfo['asf']['simple_index_object']['fileid'] = substr($SimpleIndexObjectData, $offset, 16); + $offset += 16; + $ThisFileInfo['asf']['simple_index_object']['fileid_guid'] = BytestringToGUID($ThisFileInfo['asf']['simple_index_object']['fileid']); + $ThisFileInfo['asf']['simple_index_object']['index_entry_time_interval'] = LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 8)); + $offset += 8; + $ThisFileInfo['asf']['simple_index_object']['maximum_packet_count'] = LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['simple_index_object']['index_entries_count'] = LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); + $offset += 4; + + $IndexEntriesData = $SimpleIndexObjectData.fread($fd, 6 * $ThisFileInfo['asf']['simple_index_object']['index_entries_count']); + for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $ThisFileInfo['asf']['simple_index_object']['index_entries_count']; $IndexEntriesCounter++) { + $ThisFileInfo['asf']['simple_index_object']['index_entries'][$IndexEntriesCounter]['packet_number'] = LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['simple_index_object']['index_entries'][$IndexEntriesCounter]['packet_count'] = LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); + $offset += 2; + } + + break; + + case ASF_Index_Object: + // 6.2 ASF top-level Index Object (optional but recommended when appropriate, 0 or 1) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for the Index Object - ASF_Index_Object + // Object Size QWORD 64 // Specifies the size, in bytes, of the Index Object, including at least 34 bytes of Index Object header + // Index Entry Time Interval DWORD 32 // Specifies the time interval between each index entry in ms. + // Index Specifiers Count WORD 16 // Specifies the number of Index Specifiers structures in this Index Object. + // Index Blocks Count DWORD 32 // Specifies the number of Index Blocks structures in this Index Object. + + // Index Entry Time Interval DWORD 32 // Specifies the time interval between index entries in milliseconds. This value cannot be 0. + // Index Specifiers Count WORD 16 // Specifies the number of entries in the Index Specifiers list. Valid values are 1 and greater. + // Index Specifiers array of: varies // + // * Stream Number WORD 16 // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127. + // * Index Type WORD 16 // Specifies Index Type values as follows: + // 1 = Nearest Past Data Packet - indexes point to the data packet whose presentation time is closest to the index entry time. + // 2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire object or first fragment of an object. + // 3 = Nearest Past Cleanpoint. - indexes point to the closest data packet containing an entire object (or first fragment of an object) that has the Cleanpoint Flag set. + // Nearest Past Cleanpoint is the most common type of index. + // Index Entry Count DWORD 32 // Specifies the number of Index Entries in the block. + // * Block Positions QWORD varies // Specifies a list of byte offsets of the beginnings of the blocks relative to the beginning of the first Data Packet (i.e., the beginning of the Data Object + 50 bytes). The number of entries in this list is specified by the value of the Index Specifiers Count field. The order of those byte offsets is tied to the order in which Index Specifiers are listed. + // * Index Entries array of: varies // + // * * Offsets DWORD varies // An offset value of 0xffffffff indicates an invalid offset value + + $ASFIndexObjectData = $NextObjectDataHeader.fread($fd, 34 - 24); + $offset = 24; + + $ThisFileInfo['asf']['asf_index_object']['objectid'] = $NextObjectGUID; + $ThisFileInfo['asf']['asf_index_object']['objectid_guid'] = $NextObjectGUIDtext; + $ThisFileInfo['asf']['asf_index_object']['objectsize'] = $NextObjectSize; + + $ThisFileInfo['asf']['asf_index_object']['entry_time_interval'] = LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); + $offset += 4; + $ThisFileInfo['asf']['asf_index_object']['index_specifiers_count'] = LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['asf_index_object']['index_blocks_count'] = LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); + $offset += 4; + + $ASFIndexObjectData .= fread($fd, 4 * $ThisFileInfo['asf']['asf_index_object']['index_specifiers_count']); + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $ThisFileInfo['asf']['asf_index_object']['index_specifiers_count']; $IndexSpecifiersCounter++) { + $IndexSpecifierStreamNumber = LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['asf_index_object']['index_specifiers'][$IndexSpecifiersCounter]['stream_number'] = $IndexSpecifierStreamNumber; + $ThisFileInfo['asf']['asf_index_object']['index_specifiers'][$IndexSpecifiersCounter]['index_type'] = LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); + $offset += 2; + $ThisFileInfo['asf']['asf_index_object']['index_specifiers'][$IndexSpecifiersCounter]['index_type_text'] = ASFIndexObjectIndexTypeLookup($ThisFileInfo['asf']['asf_index_object']['index_specifiers'][$IndexSpecifiersCounter]['index_type']); + } + + $ASFIndexObjectData .= fread($fd, 4); + $ThisFileInfo['asf']['asf_index_object']['index_entry_count'] = LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); + $offset += 4; + + $ASFIndexObjectData .= fread($fd, 8 * $ThisFileInfo['asf']['asf_index_object']['index_specifiers_count']); + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $ThisFileInfo['asf']['asf_index_object']['index_specifiers_count']; $IndexSpecifiersCounter++) { + $ThisFileInfo['asf']['asf_index_object']['block_positions'][$IndexSpecifiersCounter] = LittleEndian2Int(substr($ASFIndexObjectData, $offset, 8)); + $offset += 8; + } + + $ASFIndexObjectData .= fread($fd, 4 * $ThisFileInfo['asf']['asf_index_object']['index_specifiers_count'] * $ThisFileInfo['asf']['asf_index_object']['index_entry_count']); + for ($IndexEntryCounter = 0; $IndexEntryCounter < $ThisFileInfo['asf']['asf_index_object']['index_entry_count']; $IndexEntryCounter++) { + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $ThisFileInfo['asf']['asf_index_object']['index_specifiers_count']; $IndexSpecifiersCounter++) { + $ThisFileInfo['asf']['asf_index_object']['offsets'][$IndexSpecifiersCounter][$IndexEntryCounter] = LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); + $offset += 4; + } + } + break; + + + default: + // Implementations shall ignore any standard or non-standard object that they do not know how to handle. + if (GUIDname($NextObjectGUIDtext)) { + $ThisFileInfo['warning'] .= "\n".'unhandled GUID "'.GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8); + } else { + $ThisFileInfo['warning'] .= "\n".'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.(ftell($fd) - 16 - 8); + } + fseek($fd, ($NextObjectSize - 16 - 8), SEEK_CUR); + break; + } + } + + if (isset($ThisFileInfo['asf']['codec_list']['codec_entries']) && is_array($ThisFileInfo['asf']['codec_list']['codec_entries'])) { + foreach ($ThisFileInfo['asf']['codec_list']['codec_entries'] as $streamnumber => $streamdata) { + switch ($streamdata['information']) { + case 'WMV1': + case 'WMV2': + case 'WMV3': + $ThisFileInfo['video']['dataformat'] = 'wmv'; + $ThisFileInfo['mime_type'] = 'video/x-ms-wmv'; + break; + + case 'MP42': + case 'MP43': + case 'MP4S': + case 'mp4s': + $ThisFileInfo['video']['dataformat'] = 'asf'; + $ThisFileInfo['mime_type'] = 'video/x-ms-asf'; + break; + + default: + switch ($streamdata['type_raw']) { + case 1: + if (strstr($streamdata['name_ascii'], 'Windows Media')) { + $ThisFileInfo['video']['dataformat'] = 'wmv'; + if ($ThisFileInfo['mime_type'] == 'video/x-ms-asf') { + $ThisFileInfo['mime_type'] = 'video/x-ms-wmv'; + } + } + break; + + case 2: + if (strstr($streamdata['name_ascii'], 'Windows Media')) { + $ThisFileInfo['audio']['dataformat'] = 'wma'; + if ($ThisFileInfo['mime_type'] == 'video/x-ms-asf') { + $ThisFileInfo['mime_type'] = 'audio/x-ms-wma'; + } + } + break; + + } + break; + } + } + } + + if (!empty($ThisFileInfo['audio']) && empty($ThisFileInfo['audio']['dataformat'])) { + $ThisFileInfo['audio']['dataformat'] = 'asf'; + } + if (!empty($ThisFileInfo['video']) && empty($ThisFileInfo['video']['dataformat'])) { + $ThisFileInfo['video']['dataformat'] = 'asf'; + } + + if (isset($ThisFileInfo['asf']['codec_list']['codec_entries'])) { + foreach ($ThisFileInfo['asf']['codec_list']['codec_entries'] as $streamnumber => $streamdata) { + switch ($streamdata['type_raw']) { + + case 1: // video + $ThisFileInfo['video']['encoder'] = $ThisFileInfo['asf']['codec_list']['codec_entries'][$streamnumber]['name_ascii']; + break; + + case 2: // audio + $ThisFileInfo['audio']['encoder'] = $ThisFileInfo['asf']['codec_list']['codec_entries'][$streamnumber]['name_ascii']; + $ThisFileInfo['audio']['codec'] = $ThisFileInfo['audio']['encoder']; + break; + + default: + $ThisFileInfo['warning'] .= "\n".'Unknown streamtype: [codec_list][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw']; + break; + + } + } + } + + return true; +} + +function ASFCodecListObjectTypeLookup($CodecListType) { + static $ASFCodecListObjectTypeLookup = array(); + if (empty($ASFCodecListObjectTypeLookup)) { + $ASFCodecListObjectTypeLookup[0x0001] = 'Video Codec'; + $ASFCodecListObjectTypeLookup[0x0002] = 'Audio Codec'; + $ASFCodecListObjectTypeLookup[0xFFFF] = 'Unknown Codec'; + } + + return (isset($ASFCodecListObjectTypeLookup[$CodecListType]) ? $ASFCodecListObjectTypeLookup[$CodecListType] : 'Invalid Codec Type'); +} + +function KnownGUIDs() { + static $GUIDarray = array(); + if (empty($GUIDarray)) { + $GUIDarray['ASF_Extended_Stream_Properties_Object'] = '14E6A5CB-C672-4332-8399-A96952065B5A'; + $GUIDarray['ASF_Padding_Object'] = '1806D474-CADF-4509-A4BA-9AABCB96AAE8'; + $GUIDarray['ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio'] = '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8'; + $GUIDarray['ASF_Script_Command_Object'] = '1EFB1A30-0B62-11D0-A39B-00A0C90348F6'; + $GUIDarray['ASF_No_Error_Correction'] = '20FB5700-5B55-11CF-A8FD-00805F5C442B'; + $GUIDarray['ASF_Content_Branding_Object'] = '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E'; + $GUIDarray['ASF_Content_Encryption_Object'] = '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E'; + $GUIDarray['ASF_Digital_Signature_Object'] = '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E'; + $GUIDarray['ASF_Extended_Content_Encryption_Object'] = '298AE614-2622-4C17-B935-DAE07EE9289C'; + $GUIDarray['ASF_Simple_Index_Object'] = '33000890-E5B1-11CF-89F4-00A0C90349CB'; + $GUIDarray['ASF_Degradable_JPEG_Media'] = '35907DE0-E415-11CF-A917-00805F5C442B'; + $GUIDarray['ASF_Payload_Extension_System_Timecode'] = '399595EC-8667-4E2D-8FDB-98814CE76C1E'; + $GUIDarray['ASF_Binary_Media'] = '3AFB65E2-47EF-40F2-AC2C-70A90D71D343'; + $GUIDarray['ASF_Timecode_Index_Object'] = '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C'; + $GUIDarray['ASF_Metadata_Library_Object'] = '44231C94-9498-49D1-A141-1D134E457054'; + $GUIDarray['ASF_Reserved_3'] = '4B1ACBE3-100B-11D0-A39B-00A0C90348F6'; + $GUIDarray['ASF_Reserved_4'] = '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB'; + $GUIDarray['ASF_Command_Media'] = '59DACFC0-59E6-11D0-A3AC-00A0C90348F6'; + $GUIDarray['ASF_Header_Extension_Object'] = '5FBF03B5-A92E-11CF-8EE3-00C00C205365'; + $GUIDarray['ASF_Media_Object_Index_Parameters_Obj'] = '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7'; + $GUIDarray['ASF_Header_Object'] = '75B22630-668E-11CF-A6D9-00AA0062CE6C'; + $GUIDarray['ASF_Content_Description_Object'] = '75B22633-668E-11CF-A6D9-00AA0062CE6C'; + $GUIDarray['ASF_Error_Correction_Object'] = '75B22635-668E-11CF-A6D9-00AA0062CE6C'; + $GUIDarray['ASF_Data_Object'] = '75B22636-668E-11CF-A6D9-00AA0062CE6C'; + $GUIDarray['ASF_Web_Stream_Media_Subtype'] = '776257D4-C627-41CB-8F81-7AC7FF1C40CC'; + $GUIDarray['ASF_Stream_Bitrate_Properties_Object'] = '7BF875CE-468D-11D1-8D82-006097C9A2B2'; + $GUIDarray['ASF_Language_List_Object'] = '7C4346A9-EFE0-4BFC-B229-393EDE415C85'; + $GUIDarray['ASF_Codec_List_Object'] = '86D15240-311D-11D0-A3A4-00A0C90348F6'; + $GUIDarray['ASF_Reserved_2'] = '86D15241-311D-11D0-A3A4-00A0C90348F6'; + $GUIDarray['ASF_File_Properties_Object'] = '8CABDCA1-A947-11CF-8EE4-00C00C205365'; + $GUIDarray['ASF_File_Transfer_Media'] = '91BD222C-F21C-497A-8B6D-5AA86BFC0185'; + $GUIDarray['ASF_Old_RTP_Extension_Data'] = '96800C63-4C94-11D1-837B-0080C7A37F95'; + $GUIDarray['ASF_Advanced_Mutual_Exclusion_Object'] = 'A08649CF-4775-4670-8A16-6E35357566CD'; + $GUIDarray['ASF_Bandwidth_Sharing_Object'] = 'A69609E6-517B-11D2-B6AF-00C04FD908E9'; + $GUIDarray['ASF_Reserved_1'] = 'ABD3D211-A9BA-11cf-8EE6-00C00C205365'; + $GUIDarray['ASF_Bandwidth_Sharing_Exclusive'] = 'AF6060AA-5197-11D2-B6AF-00C04FD908E9'; + $GUIDarray['ASF_Bandwidth_Sharing_Partial'] = 'AF6060AB-5197-11D2-B6AF-00C04FD908E9'; + $GUIDarray['ASF_JFIF_Media'] = 'B61BE100-5B4E-11CF-A8FD-00805F5C442B'; + $GUIDarray['ASF_Stream_Properties_Object'] = 'B7DC0791-A9B7-11CF-8EE6-00C00C205365'; + $GUIDarray['ASF_Video_Media'] = 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B'; + $GUIDarray['ASF_Audio_Spread'] = 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220'; + $GUIDarray['ASF_Metadata_Object'] = 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA'; + $GUIDarray['ASF_Payload_Ext_Syst_Sample_Duration'] = 'C6BD9450-867F-4907-83A3-C77921B733AD'; + $GUIDarray['ASF_Group_Mutual_Exclusion_Object'] = 'D1465A40-5A79-4338-B71B-E36B8FD6C249'; + $GUIDarray['ASF_Extended_Content_Description_Object'] = 'D2D0A440-E307-11D2-97F0-00A0C95EA850'; + $GUIDarray['ASF_Stream_Prioritization_Object'] = 'D4FED15B-88D3-454F-81F0-ED5C45999E24'; + $GUIDarray['ASF_Payload_Ext_System_Content_Type'] = 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC'; + $GUIDarray['ASF_Old_File_Properties_Object'] = 'D6E229D0-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_ASF_Header_Object'] = 'D6E229D1-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_ASF_Data_Object'] = 'D6E229D2-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Index_Object'] = 'D6E229D3-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Stream_Properties_Object'] = 'D6E229D4-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Content_Description_Object'] = 'D6E229D5-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Script_Command_Object'] = 'D6E229D6-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Marker_Object'] = 'D6E229D7-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Component_Download_Object'] = 'D6E229D8-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Stream_Group_Object'] = 'D6E229D9-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Scalable_Object'] = 'D6E229DA-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Prioritization_Object'] = 'D6E229DB-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Bitrate_Mutual_Exclusion_Object'] = 'D6E229DC-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Inter_Media_Dependency_Object'] = 'D6E229DD-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Rating_Object'] = 'D6E229DE-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Index_Parameters_Object'] = 'D6E229DF-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Color_Table_Object'] = 'D6E229E0-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Language_List_Object'] = 'D6E229E1-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Audio_Media'] = 'D6E229E2-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Video_Media'] = 'D6E229E3-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Image_Media'] = 'D6E229E4-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Timecode_Media'] = 'D6E229E5-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Text_Media'] = 'D6E229E6-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_MIDI_Media'] = 'D6E229E7-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Command_Media'] = 'D6E229E8-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_No_Error_Concealment'] = 'D6E229EA-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Scrambled_Audio'] = 'D6E229EB-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_No_Color_Table'] = 'D6E229EC-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_SMPTE_Time'] = 'D6E229ED-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_ASCII_Text'] = 'D6E229EE-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Unicode_Text'] = 'D6E229EF-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_HTML_Text'] = 'D6E229F0-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_URL_Command'] = 'D6E229F1-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Filename_Command'] = 'D6E229F2-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_ACM_Codec'] = 'D6E229F3-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_VCM_Codec'] = 'D6E229F4-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_QuickTime_Codec'] = 'D6E229F5-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_DirectShow_Transform_Filter'] = 'D6E229F6-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_DirectShow_Rendering_Filter'] = 'D6E229F7-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_No_Enhancement'] = 'D6E229F8-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Unknown_Enhancement_Type'] = 'D6E229F9-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Temporal_Enhancement'] = 'D6E229FA-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Spatial_Enhancement'] = 'D6E229FB-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Quality_Enhancement'] = 'D6E229FC-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Number_of_Channels_Enhancement'] = 'D6E229FD-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Frequency_Response_Enhancement'] = 'D6E229FE-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Media_Object'] = 'D6E229FF-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Mutex_Language'] = 'D6E22A00-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Mutex_Bitrate'] = 'D6E22A01-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Mutex_Unknown'] = 'D6E22A02-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_ASF_Placeholder_Object'] = 'D6E22A0E-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Old_Data_Unit_Extension_Object'] = 'D6E22A0F-35DA-11D1-9034-00A0C90349BE'; + $GUIDarray['ASF_Web_Stream_Format'] = 'DA1E6B13-8359-4050-B398-388E965BF00C'; + $GUIDarray['ASF_Payload_Ext_System_File_Name'] = 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B'; + $GUIDarray['ASF_Marker_Object'] = 'F487CD01-A951-11CF-8EE6-00C00C205365'; + $GUIDarray['ASF_Timecode_Index_Parameters_Object'] = 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24'; + $GUIDarray['ASF_Audio_Media'] = 'F8699E40-5B4D-11CF-A8FD-00805F5C442B'; + $GUIDarray['ASF_Media_Object_Index_Object'] = 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C'; + $GUIDarray['ASF_Alt_Extended_Content_Encryption_Obj'] = 'FF889EF1-ADEE-40DA-9E71-98704BB928CE'; + } + return $GUIDarray; +} + +function GUIDname($GUIDstring) { + static $GUIDarray = array(); + if (empty($GUIDarray)) { + $GUIDarray = KnownGUIDs(); + } + return array_search($GUIDstring, $GUIDarray); +} + +function ASFIndexObjectIndexTypeLookup($id) { + static $ASFIndexObjectIndexTypeLookup = array(); + if (empty($ASFIndexObjectIndexTypeLookup)) { + $ASFIndexObjectIndexTypeLookup[1] = 'Nearest Past Data Packet'; + $ASFIndexObjectIndexTypeLookup[2] = 'Nearest Past Media Object'; + $ASFIndexObjectIndexTypeLookup[3] = 'Nearest Past Cleanpoint'; + } + return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid'); +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.bmp.php b/livesupport/modules/getid3/var/getid3.bmp.php new file mode 100644 index 000000000..723a68366 --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.bmp.php @@ -0,0 +1,644 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.bmp.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function getBMPHeaderFilepointer(&$fd, &$ThisFileInfo, $ExtractPalette=false, $ExtractData=false) { + $ThisFileInfo['fileformat'] = 'bmp'; + $ThisFileInfo['video']['dataformat'] = 'bmp'; + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + $offset = 0; + + $BMPheader = fread($fd, 14 + 40); + + // check if the hardcoded-to-1 "planes" is at offset 22 or 26 + $planes22 = LittleEndian2Int(substr($BMPheader, 22, 2)); + $planes26 = LittleEndian2Int(substr($BMPheader, 26, 2)); + if (($planes22 == 1) && ($planes26 != 1)) { + $ThisFileInfo['bmp']['type_os'] = 'OS/2'; + $ThisFileInfo['bmp']['type_version'] = 1; + } elseif (($planes26 == 1) && ($planes22 != 1)) { + $ThisFileInfo['bmp']['type_os'] = 'Windows'; + $ThisFileInfo['bmp']['type_version'] = 1; + } elseif ($ThisFileInfo['bmp']['header']['raw']['header_size'] == 12) { + $ThisFileInfo['bmp']['type_os'] = 'OS/2'; + $ThisFileInfo['bmp']['type_version'] = 1; + } elseif ($ThisFileInfo['bmp']['header']['raw']['header_size'] == 40) { + $ThisFileInfo['bmp']['type_os'] = 'Windows'; + $ThisFileInfo['bmp']['type_version'] = 1; + } elseif ($ThisFileInfo['bmp']['header']['raw']['header_size'] == 84) { + $ThisFileInfo['bmp']['type_os'] = 'Windows'; + $ThisFileInfo['bmp']['type_version'] = 4; + } elseif ($ThisFileInfo['bmp']['header']['raw']['header_size'] == 100) { + $ThisFileInfo['bmp']['type_os'] = 'Windows'; + $ThisFileInfo['bmp']['type_version'] = 5; + } + + + // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp + // all versions + // WORD bfType; + // DWORD bfSize; + // WORD bfReserved1; + // WORD bfReserved2; + // DWORD bfOffBits; + $ThisFileInfo['bmp']['header']['raw']['identifier'] = substr($BMPheader, $offset, 2); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['filesize'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['reserved1'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['reserved2'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['data_offset'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + + if ($ThisFileInfo['bmp']['type_os'] == 'OS/2') { + + // OS/2-format BMP + // http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm + + // DWORD Size; /* Size of this structure in bytes */ + // DWORD Width; /* Bitmap width in pixels */ + // DWORD Height; /* Bitmap height in pixel */ + // WORD NumPlanes; /* Number of bit planes (color depth) */ + // WORD BitsPerPixel; /* Number of bits per pixel per plane */ + + $ThisFileInfo['bmp']['header']['raw']['header_size'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['width'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['height'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['planes'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + + $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['bmp']['header']['raw']['width']; + $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['bmp']['header']['raw']['height']; + $ThisFileInfo['video']['codec'] = 'BI_RGB '.$ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'].'-bit'; + + if ($ThisFileInfo['bmp']['type_version'] >= 2) { + // DWORD Compression; /* Bitmap compression scheme */ + // DWORD ImageDataSize; /* Size of bitmap data in bytes */ + // DWORD XResolution; /* X resolution of display device */ + // DWORD YResolution; /* Y resolution of display device */ + // DWORD ColorsUsed; /* Number of color table indices used */ + // DWORD ColorsImportant; /* Number of important color indices */ + // WORD Units; /* Type of units used to measure resolution */ + // WORD Reserved; /* Pad structure to 4-byte boundary */ + // WORD Recording; /* Recording algorithm */ + // WORD Rendering; /* Halftoning algorithm used */ + // DWORD Size1; /* Reserved for halftoning algorithm use */ + // DWORD Size2; /* Reserved for halftoning algorithm use */ + // DWORD ColorEncoding; /* Color model used in bitmap */ + // DWORD Identifier; /* Reserved for application use */ + + $ThisFileInfo['bmp']['header']['raw']['compression'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['bmp_data_size'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['resolution_h'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['resolution_v'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['colors_used'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['colors_important'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['resolution_units'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['reserved1'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['recording'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['rendering'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['size1'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['size2'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['color_encoding'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['identifier'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + + $ThisFileInfo['bmp']['header']['compression'] = BMPcompressionOS2Lookup($ThisFileInfo['bmp']['header']['raw']['compression']); + + $ThisFileInfo['video']['codec'] = $ThisFileInfo['bmp']['header']['compression'].' '.$ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'].'-bit'; + } + + } elseif ($ThisFileInfo['bmp']['type_os'] == 'Windows') { + + // Windows-format BMP + + // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp + // all versions + // DWORD biSize; + // LONG biWidth; + // LONG biHeight; + // WORD biPlanes; + // WORD biBitCount; + // DWORD biCompression; + // DWORD biSizeImage; + // LONG biXPelsPerMeter; + // LONG biYPelsPerMeter; + // DWORD biClrUsed; + // DWORD biClrImportant; + + $ThisFileInfo['bmp']['header']['raw']['header_size'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['width'] = LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['height'] = LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['planes'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] = LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $ThisFileInfo['bmp']['header']['raw']['compression'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['bmp_data_size'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['resolution_h'] = LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['resolution_v'] = LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['colors_used'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['colors_important'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + + $ThisFileInfo['bmp']['header']['compression'] = BMPcompressionWindowsLookup($ThisFileInfo['bmp']['header']['raw']['compression']); + $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['bmp']['header']['raw']['width']; + $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['bmp']['header']['raw']['height']; + $ThisFileInfo['video']['codec'] = $ThisFileInfo['bmp']['header']['compression'].' '.$ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'].'-bit'; + + if ($ThisFileInfo['bmp']['type_version'] >= 4) { + $BMPheader .= fread($fd, 44); + + // BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp + // Win95+, WinNT4.0+ + // DWORD bV4RedMask; + // DWORD bV4GreenMask; + // DWORD bV4BlueMask; + // DWORD bV4AlphaMask; + // DWORD bV4CSType; + // CIEXYZTRIPLE bV4Endpoints; + // DWORD bV4GammaRed; + // DWORD bV4GammaGreen; + // DWORD bV4GammaBlue; + $ThisFileInfo['bmp']['header']['raw']['red_mask'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['green_mask'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['blue_mask'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['alpha_mask'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['cs_type'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['ciexyz_red'] = substr($BMPheader, $offset, 4); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['ciexyz_green'] = substr($BMPheader, $offset, 4); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['ciexyz_blue'] = substr($BMPheader, $offset, 4); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['gamma_red'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['gamma_green'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['gamma_blue'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + + $ThisFileInfo['bmp']['header']['ciexyz_red'] = FixedPoint2_30(strrev($ThisFileInfo['bmp']['header']['raw']['ciexyz_red'])); + $ThisFileInfo['bmp']['header']['ciexyz_green'] = FixedPoint2_30(strrev($ThisFileInfo['bmp']['header']['raw']['ciexyz_green'])); + $ThisFileInfo['bmp']['header']['ciexyz_blue'] = FixedPoint2_30(strrev($ThisFileInfo['bmp']['header']['raw']['ciexyz_blue'])); + } + + if ($ThisFileInfo['bmp']['type_version'] >= 5) { + $BMPheader .= fread($fd, 16); + + // BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp + // Win98+, Win2000+ + // DWORD bV5Intent; + // DWORD bV5ProfileData; + // DWORD bV5ProfileSize; + // DWORD bV5Reserved; + $ThisFileInfo['bmp']['header']['raw']['intent'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['profile_data_offset'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['profile_data_size'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $ThisFileInfo['bmp']['header']['raw']['reserved3'] = LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + } + + } else { + + $ThisFileInfo['error'] .= "\n".'Unknown BMP format in header.'; + return false; + + } + + + if ($ExtractPalette || $ExtractData) { + $PaletteEntries = 0; + if ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] < 16) { + $PaletteEntries = pow(2, $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel']); + } elseif (isset($ThisFileInfo['bmp']['header']['raw']['colors_used']) && ($ThisFileInfo['bmp']['header']['raw']['colors_used'] > 0) && ($ThisFileInfo['bmp']['header']['raw']['colors_used'] <= 256)) { + $PaletteEntries = $ThisFileInfo['bmp']['header']['raw']['colors_used']; + } + if ($PaletteEntries > 0) { + $BMPpalette = fread($fd, 4 * $PaletteEntries); + $paletteoffset = 0; + for ($i = 0; $i < $PaletteEntries; $i++) { + // RGBQUAD - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp + // BYTE rgbBlue; + // BYTE rgbGreen; + // BYTE rgbRed; + // BYTE rgbReserved; + //$ThisFileInfo['bmp']['palette']['blue'][$i] = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); + //$ThisFileInfo['bmp']['palette']['green'][$i] = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); + //$ThisFileInfo['bmp']['palette']['red'][$i] = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); + $blue = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); + $green = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); + $red = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); + if (($ThisFileInfo['bmp']['type_os'] == 'OS/2') && ($ThisFileInfo['bmp']['type_version'] == 1)) { + // no padding byte + } else { + $paletteoffset++; // padding byte + } + $ThisFileInfo['bmp']['palette'][$i] = (($red << 16) | ($green << 8) | ($blue)); + } + } + } + + if ($ExtractData) { + fseek($fd, $ThisFileInfo['bmp']['header']['raw']['data_offset'], SEEK_SET); + $RowByteLength = ceil(($ThisFileInfo['bmp']['header']['raw']['width'] * ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry + $BMPpixelData = fread($fd, $ThisFileInfo['bmp']['header']['raw']['height'] * $RowByteLength); + $pixeldataoffset = 0; + switch ($ThisFileInfo['bmp']['header']['raw']['compression']) { + + case 0: // BI_RGB + switch ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel']) { + case 1: + for ($row = ($ThisFileInfo['bmp']['header']['raw']['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $ThisFileInfo['bmp']['header']['raw']['width']; $col = $col) { + $paletteindexbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + for ($i = 7; $i >= 0; $i--) { + $paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i; + $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindex]; + $col++; + } + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + case 4: + for ($row = ($ThisFileInfo['bmp']['header']['raw']['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $ThisFileInfo['bmp']['header']['raw']['width']; $col = $col) { + $paletteindexbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + for ($i = 1; $i >= 0; $i--) { + $paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i); + $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindex]; + $col++; + } + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + case 8: + for ($row = ($ThisFileInfo['bmp']['header']['raw']['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $ThisFileInfo['bmp']['header']['raw']['width']; $col++) { + $paletteindex = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindex]; + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + case 24: + case 32: + for ($row = ($ThisFileInfo['bmp']['header']['raw']['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $ThisFileInfo['bmp']['header']['raw']['width']; $col++) { + $blue = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $green = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $red = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + if ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] == 32) { + $paletteoffset++; // filler byte + } + $ThisFileInfo['bmp']['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue)); + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + case 16: + + default: + $ThisFileInfo['error'] .= "\n".'Unknown bits-per-pixel value ('.$ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'].') - cannot read pixel data'; + break; + } + break; + + + case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp + switch ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel']) { + case 8: + $pixelcounter = 0; + while ($pixeldataoffset < strlen($BMPpixelData)) { + $firstbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $secondbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + if ($firstbyte == 0) { + + // escaped/absolute mode - the first byte of the pair can be set to zero to + // indicate an escape character that denotes the end of a line, the end of + // a bitmap, or a delta, depending on the value of the second byte. + switch ($secondbyte) { + case 0: + // end of line + // no need for special processing, just ignore + break; + + case 1: + // end of bitmap + $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case + break; + + case 2: + // delta - The 2 bytes following the escape contain unsigned values + // indicating the horizontal and vertical offsets of the next pixel + // from the current position. + $colincrement = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $rowincrement = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = ($pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width']) + $colincrement; + $row = ($ThisFileInfo['bmp']['header']['raw']['height'] - 1 - (($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width'])) - $rowincrement; + $pixelcounter = ($row * $ThisFileInfo['bmp']['header']['raw']['width']) + $col; + break; + + default: + // In absolute mode, the first byte is zero and the second byte is a + // value in the range 03H through FFH. The second byte represents the + // number of bytes that follow, each of which contains the color index + // of a single pixel. Each run must be aligned on a word boundary. + for ($i = 0; $i < $secondbyte; $i++) { + $paletteindex = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = $pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width']; + $row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1 - (($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width']); + $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindex]; + $pixelcounter++; + } + while (($pixeldataoffset % 2) != 0) { + // Each run must be aligned on a word boundary. + $pixeldataoffset++; + } + break; + } + + } else { + + // encoded mode - the first byte specifies the number of consecutive pixels + // to be drawn using the color index contained in the second byte. + for ($i = 0; $i < $firstbyte; $i++) { + $col = $pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width']; + $row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1 - (($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width']); + $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$secondbyte]; + $pixelcounter++; + } + + } + } + break; + + default: + $ThisFileInfo['error'] .= "\n".'Unknown bits-per-pixel value ('.$ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'].') - cannot read pixel data'; + break; + } + break; + + + + case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp + switch ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel']) { + case 4: + $pixelcounter = 0; + while ($pixeldataoffset < strlen($BMPpixelData)) { + $firstbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $secondbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + if ($firstbyte == 0) { + + // escaped/absolute mode - the first byte of the pair can be set to zero to + // indicate an escape character that denotes the end of a line, the end of + // a bitmap, or a delta, depending on the value of the second byte. + switch ($secondbyte) { + case 0: + // end of line + // no need for special processing, just ignore + break; + + case 1: + // end of bitmap + $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case + break; + + case 2: + // delta - The 2 bytes following the escape contain unsigned values + // indicating the horizontal and vertical offsets of the next pixel + // from the current position. + $colincrement = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $rowincrement = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = ($pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width']) + $colincrement; + $row = ($ThisFileInfo['bmp']['header']['raw']['height'] - 1 - (($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width'])) - $rowincrement; + $pixelcounter = ($row * $ThisFileInfo['bmp']['header']['raw']['width']) + $col; + break; + + default: + // In absolute mode, the first byte is zero. The second byte contains the number + // of color indexes that follow. Subsequent bytes contain color indexes in their + // high- and low-order 4 bits, one color index for each pixel. In absolute mode, + // each run must be aligned on a word boundary. + unset($paletteindexes); + for ($i = 0; $i < ceil($secondbyte / 2); $i++) { + $paletteindexbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4; + $paletteindexes[] = ($paletteindexbyte & 0x0F); + } + while (($pixeldataoffset % 2) != 0) { + // Each run must be aligned on a word boundary. + $pixeldataoffset++; + } + + foreach ($paletteindexes as $paletteindex) { + $col = $pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width']; + $row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1 - (($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width']); + $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindex]; + $pixelcounter++; + } + break; + } + + } else { + + // encoded mode - the first byte of the pair contains the number of pixels to be + // drawn using the color indexes in the second byte. The second byte contains two + // color indexes, one in its high-order 4 bits and one in its low-order 4 bits. + // The first of the pixels is drawn using the color specified by the high-order + // 4 bits, the second is drawn using the color in the low-order 4 bits, the third + // is drawn using the color in the high-order 4 bits, and so on, until all the + // pixels specified by the first byte have been drawn. + $paletteindexes[0] = ($secondbyte & 0xF0) >> 4; + $paletteindexes[1] = ($secondbyte & 0x0F); + for ($i = 0; $i < $firstbyte; $i++) { + $col = $pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width']; + $row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1 - (($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width']); + $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindexes[($i % 2)]]; + $pixelcounter++; + } + + } + } + break; + + default: + $ThisFileInfo['error'] .= "\n".'Unknown bits-per-pixel value ('.$ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'].') - cannot read pixel data'; + break; + } + break; + + + case 3: // BI_BITFIELDS + switch ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel']) { + case 16: + case 32: + $redshift = 0; + $greenshift = 0; + $blueshift = 0; + while ((($ThisFileInfo['bmp']['header']['raw']['red_mask'] >> $redshift) & 0x01) == 0) { + $redshift++; + } + while ((($ThisFileInfo['bmp']['header']['raw']['green_mask'] >> $greenshift) & 0x01) == 0) { + $greenshift++; + } + while ((($ThisFileInfo['bmp']['header']['raw']['blue_mask'] >> $blueshift) & 0x01) == 0) { + $blueshift++; + } + for ($row = ($ThisFileInfo['bmp']['header']['raw']['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $ThisFileInfo['bmp']['header']['raw']['width']; $col++) { + $pixelvalue = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] / 8)); + $pixeldataoffset += $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] / 8; + + $red = round(((($pixelvalue & $ThisFileInfo['bmp']['header']['raw']['red_mask']) >> $redshift) / ($ThisFileInfo['bmp']['header']['raw']['red_mask'] >> $redshift)) * 255); + $green = round(((($pixelvalue & $ThisFileInfo['bmp']['header']['raw']['green_mask']) >> $greenshift) / ($ThisFileInfo['bmp']['header']['raw']['green_mask'] >> $greenshift)) * 255); + $blue = round(((($pixelvalue & $ThisFileInfo['bmp']['header']['raw']['blue_mask']) >> $blueshift) / ($ThisFileInfo['bmp']['header']['raw']['blue_mask'] >> $blueshift)) * 255); + $ThisFileInfo['bmp']['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue)); + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + default: + $ThisFileInfo['error'] .= "\n".'Unknown bits-per-pixel value ('.$ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'].') - cannot read pixel data'; + break; + } + break; + + + default: // unhandled compression type + $ThisFileInfo['error'] .= "\n".'Unknown/unhandled compression type value ('.$ThisFileInfo['bmp']['header']['raw']['compression'].') - cannot decompress pixel data'; + break; + } + } + + return true; +} + +function PlotBMP(&$BMPinfo) { + $starttime = time(); + if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) { + echo 'ERROR: no pixel data
'; + return false; + } + set_time_limit(round($BMPinfo['resolution_x'] * $BMPinfo['resolution_y'] / 10000)); + if ($im = ImageCreateTrueColor($BMPinfo['resolution_x'], $BMPinfo['resolution_y'])) { + for ($row = 0; $row < $BMPinfo['resolution_y']; $row++) { + for ($col = 0; $col < $BMPinfo['resolution_x']; $col++) { + if (isset($BMPinfo['bmp']['data'][$row][$col])) { + $red = ($BMPinfo['bmp']['data'][$row][$col] & 0x00FF0000) >> 16; + $green = ($BMPinfo['bmp']['data'][$row][$col] & 0x0000FF00) >> 8; + $blue = ($BMPinfo['bmp']['data'][$row][$col] & 0x000000FF); + $pixelcolor = ImageColorAllocate($im, $red, $green, $blue); + ImageSetPixel($im, $col, $row, $pixelcolor); + } else { + //echo 'ERROR: no data for pixel '.$row.' x '.$col.'
'; + //return false; + } + } + } + if (headers_sent()) { + echo 'plotted '.($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']).' pixels in '.(time() - $starttime).' seconds
'; + ImageDestroy($im); + exit; + } else { + header('Content-type: image/png'); + ImagePNG($im); + ImageDestroy($im); + return true; + } + } + return false; +} + +function BMPcompressionWindowsLookup($compressionid) { + static $BMPcompressionWindowsLookup = array(); + if (empty($BMPcompressionWindowsLookup)) { + $BMPcompressionWindowsLookup[0] = 'BI_RGB'; + $BMPcompressionWindowsLookup[1] = 'BI_RLE8'; + $BMPcompressionWindowsLookup[2] = 'BI_RLE4'; + $BMPcompressionWindowsLookup[3] = 'BI_BITFIELDS'; + $BMPcompressionWindowsLookup[4] = 'BI_JPEG'; + $BMPcompressionWindowsLookup[5] = 'BI_PNG'; + } + return (isset($BMPcompressionWindowsLookup[$compressionid]) ? $BMPcompressionWindowsLookup[$compressionid] : 'invalid'); +} + +function BMPcompressionOS2Lookup($compressionid) { + static $BMPcompressionOS2Lookup = array(); + if (empty($BMPcompressionOS2Lookup)) { + $BMPcompressionOS2Lookup[0] = 'BI_RGB'; + $BMPcompressionOS2Lookup[1] = 'BI_RLE8'; + $BMPcompressionOS2Lookup[2] = 'BI_RLE4'; + $BMPcompressionOS2Lookup[3] = 'Huffman 1D'; + $BMPcompressionOS2Lookup[4] = 'BI_RLE24'; + } + return (isset($BMPcompressionOS2Lookup[$compressionid]) ? $BMPcompressionOS2Lookup[$compressionid] : 'invalid'); +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.frames.php b/livesupport/modules/getid3/var/getid3.frames.php new file mode 100644 index 000000000..8fa6b4b16 --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.frames.php @@ -0,0 +1,2763 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.frames.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function ID3v2FrameProcessing($frame_name, $frame_flags, &$ThisFileInfo) { + + // define $frame_arrayindex once here (used for many frames), override or ignore as neccesary + $frame_arrayindex = count($ThisFileInfo['id3v2']["$frame_name"]); // 'data', 'datalength' + if (isset($ThisFileInfo['id3v2']["$frame_name"]['data'])) { + $frame_arrayindex--; + } + if (isset($ThisFileInfo['id3v2']["$frame_name"]['datalength'])) { + $frame_arrayindex--; + } + if (isset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset'])) { + $frame_arrayindex--; + } + if (isset($ThisFileInfo['id3v2']["$frame_name"]['flags'])) { + $frame_arrayindex--; + } + if (isset($ThisFileInfo['id3v2']["$frame_name"]['timestampformat'])) { + $frame_arrayindex--; + } + + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { // frame flags are not part of the ID3v2.2 standard + if ($ThisFileInfo['id3v2']['majorversion'] == 3) { + // Frame Header Flags + // %abc00000 %ijk00000 + $ThisFileInfo['id3v2']["$frame_name"]['flags']['TagAlterPreservation'] = (bool) substr($frame_flags, 0, 1); // a - Tag alter preservation + $ThisFileInfo['id3v2']["$frame_name"]['flags']['FileAlterPreservation'] = (bool) substr($frame_flags, 1, 1); // b - File alter preservation + $ThisFileInfo['id3v2']["$frame_name"]['flags']['ReadOnly'] = (bool) substr($frame_flags, 2, 1); // c - Read only + $ThisFileInfo['id3v2']["$frame_name"]['flags']['compression'] = (bool) substr($frame_flags, 8, 1); // i - Compression + $ThisFileInfo['id3v2']["$frame_name"]['flags']['Encryption'] = (bool) substr($frame_flags, 9, 1); // j - Encryption + $ThisFileInfo['id3v2']["$frame_name"]['flags']['GroupingIdentity'] = (bool) substr($frame_flags, 10, 1); // k - Grouping identity + } elseif ($ThisFileInfo['id3v2']['majorversion'] == 4) { + // Frame Header Flags + // %0abc0000 %0h00kmnp + $ThisFileInfo['id3v2']["$frame_name"]['flags']['TagAlterPreservation'] = (bool) substr($frame_flags, 1, 1); // a - Tag alter preservation + $ThisFileInfo['id3v2']["$frame_name"]['flags']['FileAlterPreservation'] = (bool) substr($frame_flags, 2, 1); // b - File alter preservation + $ThisFileInfo['id3v2']["$frame_name"]['flags']['ReadOnly'] = (bool) substr($frame_flags, 3, 1); // c - Read only + $ThisFileInfo['id3v2']["$frame_name"]['flags']['GroupingIdentity'] = (bool) substr($frame_flags, 9, 1); // h - Grouping identity + $ThisFileInfo['id3v2']["$frame_name"]['flags']['compression'] = (bool) substr($frame_flags, 12, 1); // k - Compression + $ThisFileInfo['id3v2']["$frame_name"]['flags']['Encryption'] = (bool) substr($frame_flags, 13, 1); // m - Encryption + $ThisFileInfo['id3v2']["$frame_name"]['flags']['Unsynchronisation'] = (bool) substr($frame_flags, 14, 1); // n - Unsynchronisation + $ThisFileInfo['id3v2']["$frame_name"]['flags']['DataLengthIndicator'] = (bool) substr($frame_flags, 15, 1); // p - Data length indicator + } + + // Frame-level de-unsynchronization - ID3v2.4 + if (isset($ThisFileInfo['id3v2']["$frame_name"]['flags']['Unsynchronisation'])) { + $ThisFileInfo['id3v2']["$frame_name"]['data'] = DeUnSynchronise($ThisFileInfo['id3v2']["$frame_name"]['data']); + } + + // Frame-level de-compression + if (isset($ThisFileInfo['id3v2']["$frame_name"]['flags']['compression'])) { + // it's on the wishlist :) + } + + } + + if ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'UFID')) || // 4.1 UFID Unique file identifier + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'UFI'))) { // 4.1 UFI Unique file identifier + // There may be more than one 'UFID' frame in a tag, + // but only one with the same 'Owner identifier'. + //
+ // Owner identifier $00 + // Identifier + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0)); + $frame_idstring = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], 0, $frame_terminatorpos); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['ownerid'] = $frame_idstring; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(chr(0))); + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'TXXX')) || // 4.2.2 TXXX User defined text information frame + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'TXX'))) { // 4.2.2 TXX User defined text information frame + // There may be more than one 'TXXX' frame in each tag, + // but only one with the same description. + //
+ // Text encoding $xx + // Description $00 (00) + // Value + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'] = $frame_description; + if (!isset($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression']) || ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression'] === false)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding))); + if (!isset($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression']) || ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression'] === false)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'], $frame_textencoding); + } + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidata']) { + $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidata']; + } + + + } elseif ($frame_name{0} == 'T') { // 4.2. T??[?] Text information frame + // There may only be one text information frame of its kind in an tag. + //
+ // Text encoding $xx + // Information + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + + // $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + // this one-line method should work, but as a safeguard against null-padded data, do it the safe way + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + if ($frame_terminatorpos) { + // there are null bytes after the data - this is not according to spec + // only use data up to first null byte + $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + } else { + // no null bytes following data, just use all data + $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + } + + if (!isset($ThisFileInfo['id3v2']["$frame_name"]['flags']['compression']) || !$ThisFileInfo['id3v2']["$frame_name"]['flags']['compression']) { + $ThisFileInfo['id3v2']["$frame_name"]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_textencoding); + } + $ThisFileInfo['id3v2']["$frame_name"]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["$frame_name"]['asciidata']) { + $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["$frame_name"]['asciidata']; + } + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'WXX'))) { // 4.3.2 WXX User defined URL link frame + // There may be more than one 'WXXX' frame in each tag, + // but only one with the same description + //
+ // Text encoding $xx + // Description $00 (00) + // URL + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding))); + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding)); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + if ($frame_terminatorpos) { + // there are null bytes after the data - this is not according to spec + // only use data up to first null byte + $frame_urldata = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], 0, $frame_terminatorpos); + } else { + // no null bytes following data, just use all data + $frame_urldata = $ThisFileInfo['id3v2']["$frame_name"]['data']; + } + + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['url'] = $frame_urldata; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'] = $frame_description; + if (!isset($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression']) || ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression'] === false)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['url']) { + $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['url']; + } + + + } elseif ($frame_name{0} == 'W') { // 4.3. W??? URL link frames + // There may only be one URL link frame of its kind in a tag, + // except when stated otherwise in the frame description + //
+ // URL + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['url'] = trim($ThisFileInfo['id3v2']["$frame_name"]['data']); + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['url']) { + $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['url']; + } + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] == 3) && ($frame_name == 'IPLS')) || // 4.4 IPLS Involved people list (ID3v2.3 only) + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'IPL'))) { // 4.4 IPL Involved people list (ID3v2.2 only) + // There may only be one 'IPL' frame in each tag + //
+ // Text encoding $xx + // People list strings + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + $ThisFileInfo['id3v2']["$frame_name"]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"]['encoding'] = TextEncodingLookup('encoding', $ThisFileInfo['id3v2']["$frame_name"]['encodingid']); + $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + $ThisFileInfo['id3v2']["$frame_name"]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["$frame_name"]['asciidata']) { + $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["$frame_name"]['asciidata']; + } + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'MCDI')) || // 4.4 MCDI Music CD identifier + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'MCI'))) { // 4.5 MCI Music CD identifier + // There may only be one 'MCDI' frame in each tag + //
+ // CD TOC + + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["$frame_name"]['data']) { + $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["$frame_name"]['data']; + } + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'ETCO')) || // 4.5 ETCO Event timing codes + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'ETC'))) { // 4.6 ETC Event timing codes + // There may only be one 'ETCO' frame in each tag + //
+ // Time stamp format $xx + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Followed by a list of key events in the following format: + // Type of event $xx + // Time stamp $xx (xx ...) + // The 'Time stamp' is set to zero if directly at the beginning of the sound + // or after the previous event. All events MUST be sorted in chronological order. + + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"]['timestampformat'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + + while ($frame_offset < strlen($ThisFileInfo['id3v2']["$frame_name"]['data'])) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['typeid'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['type'] = ETCOEventLookup($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['typeid']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['timestamp'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 4)); + $frame_offset += 4; + } + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'MLLT')) || // 4.6 MLLT MPEG location lookup table + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'MLL'))) { // 4.7 MLL MPEG location lookup table + // There may only be one 'MLLT' frame in each tag + //
+ // MPEG frames between reference $xx xx + // Bytes between reference $xx xx xx + // Milliseconds between reference $xx xx xx + // Bits for bytes deviation $xx + // Bits for milliseconds dev. $xx + // Then for every reference the following data is included; + // Deviation in bytes %xxx.... + // Deviation in milliseconds %xxx.... + + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"]['framesbetweenreferences'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], 0, 2)); + $ThisFileInfo['id3v2']["$frame_name"]['bytesbetweenreferences'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], 2, 3)); + $ThisFileInfo['id3v2']["$frame_name"]['msbetweenreferences'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], 5, 3)); + $ThisFileInfo['id3v2']["$frame_name"]['bitsforbytesdeviation'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], 8, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['bitsformsdeviation'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], 9, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], 10); + while ($frame_offset < strlen($ThisFileInfo['id3v2']["$frame_name"]['data'])) { + $deviationbitstream .= BigEndian2Bin(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + } + while (strlen($deviationbitstream)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $ThisFileInfo['id3v2']["$frame_name"]['bitsforbytesdeviation'])); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['msdeviation'] = bindec(substr($deviationbitstream, $ThisFileInfo['id3v2']["$frame_name"]['bitsforbytesdeviation'], $ThisFileInfo['id3v2']["$frame_name"]['bitsformsdeviation'])); + $deviationbitstream = substr($deviationbitstream, $ThisFileInfo['id3v2']["$frame_name"]['bitsforbytesdeviation'] + $ThisFileInfo['id3v2']["$frame_name"]['bitsformsdeviation']); + $frame_arrayindex++; + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'SYTC')) || // 4.7 SYTC Synchronised tempo codes + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'STC'))) { // 4.8 STC Synchronised tempo codes + // There may only be one 'SYTC' frame in each tag + //
+ // Time stamp format $xx + // Tempo data + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"]['timestampformat'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + while ($frame_offset < strlen($ThisFileInfo['id3v2']["$frame_name"]['data'])) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['tempo'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + if ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['tempo'] == 255) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['tempo'] += ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['timestamp'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 4)); + $frame_offset += 4; + $frame_arrayindex++; + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription + // There may be more than one 'Unsynchronised lyrics/text transcription' frame + // in each tag, but only one with the same language and content descriptor. + //
+ // Text encoding $xx + // Language $xx xx xx + // Content descriptor $00 (00) + // Lyrics/text + + require_once(GETID3_INCLUDEPATH.'getid3.frames.php'); + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + $frame_language = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 3); + $frame_offset += 3; + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding))); + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'] = $ThisFileInfo['id3v2']["$frame_name"]['data']; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['language'] = $frame_language; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['languagename'] = LanguageLookup($frame_language, false); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'] = $frame_description; + if (!isset($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression']) || ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression'] === false)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'], $frame_textencoding); + } + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + if (!isset($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression']) || ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression'] === false)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'], $frame_textencoding); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidata']) { + $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidata']; + } + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'SYLT')) || // 4.9 SYLT Synchronised lyric/text + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'SLT'))) { // 4.10 SLT Synchronised lyric/text + // There may be more than one 'SYLT' frame in each tag, + // but only one with the same language and content descriptor. + //
+ // Text encoding $xx + // Language $xx xx xx + // Time stamp format $xx + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Content type $xx + // Content descriptor $00 (00) + // Terminated text to be synced (typically a syllable) + // Sync identifier (terminator to above string) $00 (00) + // Time stamp $xx (xx ...) + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + $frame_language = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 3); + $frame_offset += 3; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['timestampformat'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['contenttypeid'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['contenttype'] = SYTLContentTypeLookup($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['contenttypeid']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['language'] = $frame_language; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['languagename'] = LanguageLookup($frame_language, false); + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + + $timestampindex = 0; + $frame_remainingdata = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + while (strlen($frame_remainingdata)) { + $frame_offset = 0; + $frame_terminatorpos = strpos($frame_remainingdata, TextEncodingLookup('terminator', $frame_textencoding)); + if ($frame_terminatorpos === false) { + $frame_remainingdata = ''; + } else { + if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset); + if (!isset($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression']) || ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression'] === false)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'][$timestampindex]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'][$timestampindex]['data'], $frame_textencoding); + } + + $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding))); + if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) { + // timestamp probably omitted for first data item + } else { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'][$timestampindex]['timestamp'] = BigEndian2Int(substr($frame_remainingdata, 0, 4)); + $frame_remainingdata = substr($frame_remainingdata, 4); + } + $timestampindex++; + } + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'COMM')) || // 4.10 COMM Comments + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'COM'))) { // 4.11 COM Comments + // There may be more than one comment frame in each tag, + // but only one with the same language and content descriptor. + //
+ // Text encoding $xx + // Language $xx xx xx + // Short content descrip. $00 (00) + // The actual text + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + $frame_language = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 3); + $frame_offset += 3; + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_text = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding))); + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['language'] = $frame_language; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['languagename'] = LanguageLookup($frame_language, false); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'] = $frame_description; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'] = $frame_text; + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + if (!isset($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression']) || ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression'] === false)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding); + } + if (!isset($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression']) || ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression'] === false)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidata'] = RoughTranslateUnicodeToASCII($frame_text, $frame_textencoding); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidata']) { + $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidata']; + } + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 4) && ($frame_name == 'RVA2')) { // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only) + // There may be more than one 'RVA2' frame in each tag, + // but only one with the same identification string + //
+ // Identification $00 + // The 'identification' string is used to identify the situation and/or + // device where this adjustment should apply. The following is then + // repeated for every channel: + // Type of channel $xx + // Volume adjustment $xx xx + // Bits representing peak $xx + // Peak volume $xx (xx ...) + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0)); + $frame_idstring = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], 0, $frame_terminatorpos); + if (ord($frame_idstring) === 0) { + $frame_idstring = ''; + } + $frame_remainingdata = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(chr(0))); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'] = $frame_idstring; + while (strlen($frame_remainingdata)) { + $frame_offset = 0; + $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex][$frame_channeltypeid]['channeltypeid'] = $frame_channeltypeid; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex][$frame_channeltypeid]['channeltype'] = RVA2ChannelTypeLookup($frame_channeltypeid); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex][$frame_channeltypeid]['volumeadjust'] = BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed + $frame_offset += 2; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex][$frame_channeltypeid]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1)); + $frame_bytespeakvolume = ceil($ThisFileInfo['id3v2']["$frame_name"][$frame_channeltypeid]['bitspeakvolume'] / 8); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex][$frame_channeltypeid]['peakvolume'] = BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume)); + $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex][$frame_channeltypeid]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] == 3) && ($frame_name == 'RVAD')) || // 4.12 RVAD Relative volume adjustment (ID3v2.3 only) + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'RVA'))) { // 4.12 RVA Relative volume adjustment (ID3v2.2 only) + // There may only be one 'RVA' frame in each tag + //
+ // ID3v2.2 => Increment/decrement %000000ba + // ID3v2.3 => Increment/decrement %00fedcba + // Bits used for volume descr. $xx + // Relative volume change, right $xx xx (xx ...) // a + // Relative volume change, left $xx xx (xx ...) // b + // Peak volume right $xx xx (xx ...) + // Peak volume left $xx xx (xx ...) + // ID3v2.3 only, optional (not present in ID3v2.2): + // Relative volume change, right back $xx xx (xx ...) // c + // Relative volume change, left back $xx xx (xx ...) // d + // Peak volume right back $xx xx (xx ...) + // Peak volume left back $xx xx (xx ...) + // ID3v2.3 only, optional (not present in ID3v2.2): + // Relative volume change, center $xx xx (xx ...) // e + // Peak volume center $xx xx (xx ...) + // ID3v2.3 only, optional (not present in ID3v2.2): + // Relative volume change, bass $xx xx (xx ...) // f + // Peak volume bass $xx xx (xx ...) + + $frame_offset = 0; + $frame_incrdecrflags = BigEndian2Bin(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1); + $ThisFileInfo['id3v2']["$frame_name"]['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1); + $ThisFileInfo['id3v2']["$frame_name"]['bitsvolume'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $frame_bytesvolume = ceil($ThisFileInfo['id3v2']["$frame_name"]['bitsvolume'] / 8); + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['right'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + if ($ThisFileInfo['id3v2']["$frame_name"]['incdec']['right'] === false) { + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['right'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['left'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + if ($ThisFileInfo['id3v2']["$frame_name"]['incdec']['left'] === false) { + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['left'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $ThisFileInfo['id3v2']["$frame_name"]['peakvolume']['right'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + $ThisFileInfo['id3v2']["$frame_name"]['peakvolume']['left'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + if ($ThisFileInfo['id3v2']['majorversion'] == 3) { + $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + if (strlen($ThisFileInfo['id3v2']["$frame_name"]['data']) > 0) { + $ThisFileInfo['id3v2']["$frame_name"]['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1); + $ThisFileInfo['id3v2']["$frame_name"]['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1); + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['rightrear'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + if ($ThisFileInfo['id3v2']["$frame_name"]['incdec']['rightrear'] === false) { + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['rightrear'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['leftrear'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + if ($ThisFileInfo['id3v2']["$frame_name"]['incdec']['leftrear'] === false) { + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['leftrear'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $ThisFileInfo['id3v2']["$frame_name"]['peakvolume']['rightrear'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + $ThisFileInfo['id3v2']["$frame_name"]['peakvolume']['leftrear'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + } + $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + if (strlen($ThisFileInfo['id3v2']["$frame_name"]['data']) > 0) { + $ThisFileInfo['id3v2']["$frame_name"]['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1); + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['center'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + if ($ThisFileInfo['id3v2']["$frame_name"]['incdec']['center'] === false) { + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['center'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $ThisFileInfo['id3v2']["$frame_name"]['peakvolume']['center'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + } + $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + if (strlen($ThisFileInfo['id3v2']["$frame_name"]['data']) > 0) { + $ThisFileInfo['id3v2']["$frame_name"]['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1); + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['bass'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + if ($ThisFileInfo['id3v2']["$frame_name"]['incdec']['bass'] === false) { + $ThisFileInfo['id3v2']["$frame_name"]['volumechange']['bass'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $ThisFileInfo['id3v2']["$frame_name"]['peakvolume']['bass'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + } + } + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 4) && ($frame_name == 'EQU2')) { // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only) + // There may be more than one 'EQU2' frame in each tag, + // but only one with the same identification string + //
+ // Interpolation method $xx + // $00 Band + // $01 Linear + // Identification $00 + // The following is then repeated for every adjustment point + // Frequency $xx xx + // Volume adjustment $xx xx + + $frame_offset = 0; + $frame_interpolationmethod = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_idstring = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_idstring) === 0) { + $frame_idstring = ''; + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'] = $frame_idstring; + $frame_remainingdata = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(chr(0))); + while (strlen($frame_remainingdata)) { + $frame_frequency = BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'][$frame_frequency] = BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true); + $frame_remainingdata = substr($frame_remainingdata, 4); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['interpolationmethod'] = $frame_interpolationmethod; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] == 3) && ($frame_name == 'EQUA')) || // 4.12 EQUA Equalisation (ID3v2.3 only) + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'EQU'))) { // 4.13 EQU Equalisation (ID3v2.2 only) + // There may only be one 'EQUA' frame in each tag + //
+ // Adjustment bits $xx + // This is followed by 2 bytes + ('adjustment bits' rounded up to the + // nearest byte) for every equalisation band in the following format, + // giving a frequency range of 0 - 32767Hz: + // Increment/decrement %x (MSB of the Frequency) + // Frequency (lower 15 bits) + // Adjustment $xx (xx ...) + + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"]['adjustmentbits'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1); + $frame_adjustmentbytes = ceil($ThisFileInfo['id3v2']["$frame_name"]['adjustmentbits'] / 8); + + $frame_remainingdata = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + while (strlen($frame_remainingdata)) { + $frame_frequencystr = BigEndian2Bin(substr($frame_remainingdata, 0, 2)); + $frame_incdec = (bool) substr($frame_frequencystr, 0, 1); + $frame_frequency = bindec(substr($frame_frequencystr, 1, 15)); + $ThisFileInfo['id3v2']["$frame_name"][$frame_frequency]['incdec'] = $frame_incdec; + $ThisFileInfo['id3v2']["$frame_name"][$frame_frequency]['adjustment'] = BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes)); + if ($ThisFileInfo['id3v2']["$frame_name"][$frame_frequency]['incdec'] === false) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_frequency]['adjustment'] *= -1; + } + $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes); + } + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'RVRB')) || // 4.13 RVRB Reverb + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'REV'))) { // 4.14 REV Reverb + // There may only be one 'RVRB' frame in each tag. + //
+ // Reverb left (ms) $xx xx + // Reverb right (ms) $xx xx + // Reverb bounces, left $xx + // Reverb bounces, right $xx + // Reverb feedback, left to left $xx + // Reverb feedback, left to right $xx + // Reverb feedback, right to right $xx + // Reverb feedback, right to left $xx + // Premix left to right $xx + // Premix right to left $xx + + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"]['left'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 2)); + $frame_offset += 2; + $ThisFileInfo['id3v2']["$frame_name"]['right'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 2)); + $frame_offset += 2; + $ThisFileInfo['id3v2']["$frame_name"]['bouncesL'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['bouncesR'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['feedbackLL'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['feedbackLR'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['feedbackRR'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['feedbackRL'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['premixLR'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['premixRL'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'APIC')) || // 4.14 APIC Attached picture + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'PIC'))) { // 4.15 PIC Attached picture + // There may be several pictures attached to one file, + // each in their individual 'APIC' frame, but only one + // with the same content descriptor + //
+ // Text encoding $xx + // ID3v2.3+ => MIME type $00 + // ID3v2.2 => Image format $xx xx xx + // Picture type $xx + // Description $00 (00) + // Picture data + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + + if ($ThisFileInfo['id3v2']['majorversion'] == 2) { + $frame_imagetype = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 3); + if (strtolower($frame_imagetype) == 'ima') { + // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted + // MIME type instead of 3-char ID3v2.2-format image type (thanks xbhoff@pacbell.net) + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_mimetype = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_mimetype) === 0) { + $frame_mimetype = ''; + } + $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype))); + if ($frame_imagetype == 'JPEG') { + $frame_imagetype = 'JPG'; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + } else { + $frame_offset += 3; + } + } + if ($ThisFileInfo['id3v2']['majorversion'] > 2) { + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_mimetype = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_mimetype) === 0) { + $frame_mimetype = ''; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + } + + $frame_picturetype = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + if ($ThisFileInfo['id3v2']['majorversion'] == 2) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['imagetype'] = $frame_imagetype; + } else { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['mime'] = $frame_mimetype; + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['picturetypeid'] = $frame_picturetype; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['picturetype'] = APICPictureTypeLookup($frame_picturetype); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'] = $frame_description; + if (!isset($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression']) || ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression'] === false)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding))); + + require_once(GETID3_INCLUDEPATH.'getid3.getimagesize.php'); + $imagechunkcheck = GetDataImageSize($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data']); + if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['image_mime'] = ImageTypesLookup($imagechunkcheck[2]); + if ($imagechunkcheck[0]) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['image_width'] = $imagechunkcheck[0]; + } + if ($imagechunkcheck[1]) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['image_height'] = $imagechunkcheck[1]; + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['image_bytes'] = strlen($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data']); + } + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + if (isset($ThisFileInfo['id3v2']["$frame_name"]['datalength'])) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + } + if (isset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset'])) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + } + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'GEOB')) || // 4.15 GEOB General encapsulated object + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'GEO'))) { // 4.16 GEO General encapsulated object + // There may be more than one 'GEOB' frame in each tag, + // but only one with the same content descriptor + //
+ // Text encoding $xx + // MIME type $00 + // Filename $00 (00) + // Content description $00 (00) + // Encapsulated object + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_mimetype = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_mimetype) === 0) { + $frame_mimetype = ''; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_filename = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_filename) === 0) { + $frame_filename = ''; + } + $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)); + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)); + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['objectdata'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['mime'] = $frame_mimetype; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['filename'] = $frame_filename; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'] = $frame_description; + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + if (!isset($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression']) || ($ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags']['compression'] === false)) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding); + } + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'PCNT')) || // 4.16 PCNT Play counter + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'CNT'))) { // 4.17 CNT Play counter + // There may only be one 'PCNT' frame in each tag. + // When the counter reaches all one's, one byte is inserted in + // front of the counter thus making the counter eight bits bigger + //
+ // Counter $xx xx xx xx (xx ...) + + $ThisFileInfo['id3v2']["$frame_name"]['data'] = BigEndian2Int($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'POPM')) || // 4.17 POPM Popularimeter + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'POP'))) { // 4.18 POP Popularimeter + // There may be more than one 'POPM' frame in each tag, + // but only one with the same email address + //
+ // Email to user $00 + // Rating $xx + // Counter $xx xx xx xx (xx ...) + + $frame_offset = 0; + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_emailaddress = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_emailaddress) === 0) { + $frame_emailaddress = ''; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + $frame_rating = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['data'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset)); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['email'] = $frame_emailaddress; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['rating'] = $frame_rating; + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'RBUF')) || // 4.18 RBUF Recommended buffer size + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'BUF'))) { // 4.19 BUF Recommended buffer size + // There may only be one 'RBUF' frame in each tag + //
+ // Buffer size $xx xx xx + // Embedded info flag %0000000x + // Offset to next tag $xx xx xx xx + + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"]['buffersize'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 3)); + $frame_offset += 3; + + $frame_embeddedinfoflags = BigEndian2Bin(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1); + $ThisFileInfo['id3v2']["$frame_name"]['nexttagoffset'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 4)); + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'CRM')) { // 4.20 Encrypted meta frame (ID3v2.2 only) + // There may be more than one 'CRM' frame in a tag, + // but only one with the same 'owner identifier' + //
+ // Owner identifier $00 (00) + // Content/explanation $00 (00) + // Encrypted datablock + + $frame_offset = 0; + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_ownerid = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_ownerid) === 0) { + $frame_ownerid = count($ThisFileInfo['id3v2']["$frame_name"]) - 1; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_description = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['ownerid'] = $frame_ownerid; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'] = $frame_description; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'AENC')) || // 4.19 AENC Audio encryption + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'CRA'))) { // 4.21 CRA Audio encryption + // There may be more than one 'AENC' frames in a tag, + // but only one with the same 'Owner identifier' + //
+ // Owner identifier $00 + // Preview start $xx xx + // Preview length $xx xx + // Encryption info + + $frame_offset = 0; + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_ownerid = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_ownerid) === 0) { + $frame_ownerid == ''; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['ownerid'] = $frame_ownerid; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['previewstart'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 2)); + $frame_offset += 2; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['previewlength'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 2)); + $frame_offset += 2; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encryptioninfo'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"]["$frame_ownerid"]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif ((($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'LINK')) || // 4.20 LINK Linked information + (($ThisFileInfo['id3v2']['majorversion'] == 2) && ($frame_name == 'LNK'))) { // 4.22 LNK Linked information + // There may be more than one 'LINK' frame in a tag, + // but only one with the same contents + //
+ // ID3v2.3+ => Frame identifier $xx xx xx xx + // ID3v2.2 => Frame identifier $xx xx xx + // URL $00 + // ID and additional data + + $frame_offset = 0; + if ($ThisFileInfo['id3v2']['majorversion'] == 2) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['frameid'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 3); + $frame_offset += 3; + } else { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['frameid'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 4); + $frame_offset += 4; + } + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_url = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_url) === 0) { + $frame_url = ''; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['url'] = $frame_url; + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['additionaldata'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + if ($ThisFileInfo['id3v2']['majorversion'] >= 3) { + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + } + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['url']) { + $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['url']; + } + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'POSS')) { // 4.21 POSS Position synchronisation frame (ID3v2.3+ only) + // There may only be one 'POSS' frame in each tag + // + // Time stamp format $xx + // Position $xx (xx ...) + + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"]['timestampformat'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['position'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset)); + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'USER')) { // 4.22 USER Terms of use (ID3v2.3+ only) + // There may be more than one 'Terms of use' frame in a tag, + // but only one with the same 'Language' + //
+ // Text encoding $xx + // Language $xx xx xx + // The actual text + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + $frame_language = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 3); + $frame_offset += 3; + $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['language'] = $frame_language; + $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['languagename'] = LanguageLookup($frame_language, false); + $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + if (!$ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['flags']['compression']) { + $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['data'], $frame_textencoding); + } + $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['asciidata']) { + $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["$frame_name"]["$frame_language"]['asciidata']; + } + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'OWNE')) { // 4.23 OWNE Ownership frame (ID3v2.3+ only) + // There may only be one 'OWNE' frame in a tag + //
+ // Text encoding $xx + // Price paid $00 + // Date of purch. + // Seller + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + $ThisFileInfo['id3v2']["$frame_name"]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_pricepaid = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + + $ThisFileInfo['id3v2']["$frame_name"]['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3); + $ThisFileInfo['id3v2']["$frame_name"]['pricepaid']['currency'] = LookupCurrency($ThisFileInfo['id3v2']["$frame_name"]['pricepaid']['currencyid'], 'units'); + $ThisFileInfo['id3v2']["$frame_name"]['pricepaid']['value'] = substr($frame_pricepaid, 3); + + $ThisFileInfo['id3v2']["$frame_name"]['purchasedate'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 8); + if (!IsValidDateStampString($ThisFileInfo['id3v2']["$frame_name"]['purchasedate'])) { + $ThisFileInfo['id3v2']["$frame_name"]['purchasedateunix'] = mktime (0, 0, 0, substr($ThisFileInfo['id3v2']["$frame_name"]['purchasedate'], 4, 2), substr($ThisFileInfo['id3v2']["$frame_name"]['purchasedate'], 6, 2), substr($ThisFileInfo['id3v2']["$frame_name"]['purchasedate'], 0, 4)); + } + $frame_offset += 8; + + $ThisFileInfo['id3v2']["$frame_name"]['seller'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'COMR')) { // 4.24 COMR Commercial frame (ID3v2.3+ only) + // There may be more than one 'commercial frame' in a tag, + // but no two may be identical + //
+ // Text encoding $xx + // Price string $00 + // Valid until + // Contact URL $00 + // Received as $xx + // Name of seller $00 (00) + // Description $00 (00) + // Picture MIME type $00 + // Seller logo + + $frame_offset = 0; + $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name); + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_pricestring = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + $frame_rawpricearray = explode('/', $frame_pricestring); + foreach ($frame_rawpricearray as $key => $val) { + $frame_currencyid = substr($val, 0, 3); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['price']["$frame_currencyid"]['currency'] = LookupCurrency($frame_currencyid, 'units'); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['price']["$frame_currencyid"]['value'] = substr($val, 3); + } + + $frame_datestring = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 8); + $frame_offset += 8; + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_contacturl = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + + $frame_receivedasid = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_sellername = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_sellername) === 0) { + $frame_sellername = ''; + } + $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)); + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset); + if (ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)); + + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_mimetype = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + + $frame_sellerlogo = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encodingid'] = $frame_textencoding; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['pricevaliduntil'] = $frame_datestring; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['contacturl'] = $frame_contacturl; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['receivedasid'] = $frame_receivedasid; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['receivedas'] = COMRReceivedAsLookup($frame_receivedasid); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['sellername'] = $frame_sellername; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciisellername'] = RoughTranslateUnicodeToASCII($frame_sellername, $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['description'] = $frame_description; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['mime'] = $frame_mimetype; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['logo'] = $frame_sellerlogo; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'ENCR')) { // 4.25 ENCR Encryption method registration (ID3v2.3+ only) + // There may be several 'ENCR' frames in a tag, + // but only one containing the same symbol + // and only one containing the same owner identifier + //
+ // Owner identifier $00 + // Method symbol $xx + // Encryption data + + $frame_offset = 0; + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_ownerid = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_ownerid) === 0) { + $frame_ownerid = ''; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['ownerid'] = $frame_ownerid; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['methodsymbol'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'GRID')) { // 4.26 GRID Group identification registration (ID3v2.3+ only) + + // There may be several 'GRID' frames in a tag, + // but only one containing the same symbol + // and only one containing the same owner identifier + //
+ // Owner identifier $00 + // Group symbol $xx + // Group dependent data + + $frame_offset = 0; + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_ownerid = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_ownerid) === 0) { + $frame_ownerid = ''; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['ownerid'] = $frame_ownerid; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['groupsymbol'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'PRIV')) { // 4.27 PRIV Private frame (ID3v2.3+ only) + // The tag may contain more than one 'PRIV' frame + // but only with different contents + //
+ // Owner identifier $00 + // The private data + + $frame_offset = 0; + $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["$frame_name"]['data'], chr(0), $frame_offset); + $frame_ownerid = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_ownerid) === 0) { + $frame_ownerid = ''; + } + $frame_offset = $frame_terminatorpos + strlen(chr(0)); + + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['ownerid'] = $frame_ownerid; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 4) && ($frame_name == 'SIGN')) { // 4.28 SIGN Signature frame (ID3v2.4+ only) + // There may be more than one 'signature frame' in a tag, + // but no two may be identical + //
+ // Group symbol $xx + // Signature + + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['groupsymbol'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["$frame_name"]['flags']; + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['flags']); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["$frame_name"]['datalength']; + unset($ThisFileInfo['id3v2']["$frame_name"]['datalength']); + $ThisFileInfo['id3v2']["$frame_name"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["$frame_name"]['dataoffset']; + unset($ThisFileInfo['id3v2']["$frame_name"]['dataoffset']); + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 4) && ($frame_name == 'SEEK')) { // 4.29 SEEK Seek frame (ID3v2.4+ only) + // There may only be one 'seek frame' in a tag + //
+ // Minimum offset to next tag $xx xx xx xx + + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"]['data'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 4)); + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 4) && ($frame_name == 'ASPI')) { // 4.30 ASPI Audio seek point index (ID3v2.4+ only) + // There may only be one 'audio seek point index' frame in a tag + //
+ // Indexed data start (S) $xx xx xx xx + // Indexed data length (L) $xx xx xx xx + // Number of index points (N) $xx xx + // Bits per index point (b) $xx + // Then for every index point the following data is included: + // Fraction at index (Fi) $xx (xx) + + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"]['datastart'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 4)); + $frame_offset += 4; + $ThisFileInfo['id3v2']["$frame_name"]['indexeddatalength'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 4)); + $frame_offset += 4; + $ThisFileInfo['id3v2']["$frame_name"]['indexpoints'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 2)); + $frame_offset += 2; + $ThisFileInfo['id3v2']["$frame_name"]['bitsperpoint'] = ord(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset++, 1)); + $frame_bytesperpoint = ceil($ThisFileInfo['id3v2']["$frame_name"]['bitsperpoint'] / 8); + for ($i = 0; $i < $frame_indexpoints; $i++) { + $ThisFileInfo['id3v2']["$frame_name"]['indexes'][$i] = BigEndian2Int(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, $frame_bytesperpoint)); + $frame_offset += $frame_bytesperpoint; + } + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + + } elseif (($ThisFileInfo['id3v2']['majorversion'] >= 3) && ($frame_name == 'RGAD')) { // Replay Gain Adjustment + // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html + // There may only be one 'RGAD' frame in a tag + //
+ // Peak Amplitude $xx $xx $xx $xx + // Radio Replay Gain Adjustment %aaabbbcd %dddddddd + // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd + // a - name code + // b - originator code + // c - sign bit + // d - replay gain adjustment + + require_once(GETID3_INCLUDEPATH.'getid3.rgad.php'); + $frame_offset = 0; + $ThisFileInfo['id3v2']["$frame_name"]['peakamplitude'] = BigEndian2Float(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 4)); + $frame_offset += 4; + $radioadjustment = Dec2Bin(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 2)); + $frame_offset += 2; + $audiophileadjustment = Dec2Bin(substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset, 2)); + $frame_offset += 2; + $ThisFileInfo['id3v2']["$frame_name"]['raw']['radio']['name'] = Bin2Dec(substr($radioadjustment, 0, 3)); + $ThisFileInfo['id3v2']["$frame_name"]['raw']['radio']['originator'] = Bin2Dec(substr($radioadjustment, 3, 3)); + $ThisFileInfo['id3v2']["$frame_name"]['raw']['radio']['signbit'] = Bin2Dec(substr($radioadjustment, 6, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['raw']['radio']['adjustment'] = Bin2Dec(substr($radioadjustment, 7, 9)); + $ThisFileInfo['id3v2']["$frame_name"]['raw']['audiophile']['name'] = Bin2Dec(substr($audiophileadjustment, 0, 3)); + $ThisFileInfo['id3v2']["$frame_name"]['raw']['audiophile']['originator'] = Bin2Dec(substr($audiophileadjustment, 3, 3)); + $ThisFileInfo['id3v2']["$frame_name"]['raw']['audiophile']['signbit'] = Bin2Dec(substr($audiophileadjustment, 6, 1)); + $ThisFileInfo['id3v2']["$frame_name"]['raw']['audiophile']['adjustment'] = Bin2Dec(substr($audiophileadjustment, 7, 9)); + $ThisFileInfo['id3v2']["$frame_name"]['radio']['name'] = RGADnameLookup($ThisFileInfo['id3v2']["$frame_name"]['raw']['radio']['name']); + $ThisFileInfo['id3v2']["$frame_name"]['radio']['originator'] = RGADoriginatorLookup($ThisFileInfo['id3v2']["$frame_name"]['raw']['radio']['originator']); + $ThisFileInfo['id3v2']["$frame_name"]['radio']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['id3v2']["$frame_name"]['raw']['radio']['adjustment'], $ThisFileInfo['id3v2']["$frame_name"]['raw']['radio']['signbit']); + $ThisFileInfo['id3v2']["$frame_name"]['audiophile']['name'] = RGADnameLookup($ThisFileInfo['id3v2']["$frame_name"]['raw']['audiophile']['name']); + $ThisFileInfo['id3v2']["$frame_name"]['audiophile']['originator'] = RGADoriginatorLookup($ThisFileInfo['id3v2']["$frame_name"]['raw']['audiophile']['originator']); + $ThisFileInfo['id3v2']["$frame_name"]['audiophile']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['id3v2']["$frame_name"]['raw']['audiophile']['adjustment'], $ThisFileInfo['id3v2']["$frame_name"]['raw']['audiophile']['signbit']); + + $ThisFileInfo['replay_gain']['radio']['peak'] = $ThisFileInfo['id3v2']["$frame_name"]['peakamplitude']; + $ThisFileInfo['replay_gain']['radio']['originator'] = $ThisFileInfo['id3v2']["$frame_name"]['radio']['originator']; + $ThisFileInfo['replay_gain']['radio']['adjustment'] = $ThisFileInfo['id3v2']["$frame_name"]['radio']['adjustment']; + $ThisFileInfo['replay_gain']['audiophile']['originator'] = $ThisFileInfo['id3v2']["$frame_name"]['audiophile']['originator']; + $ThisFileInfo['replay_gain']['audiophile']['adjustment'] = $ThisFileInfo['id3v2']["$frame_name"]['audiophile']['adjustment']; + + $ThisFileInfo['id3v2']["$frame_name"]['framenamelong'] = FrameNameLongLookup($frame_name); + unset($ThisFileInfo['id3v2']["$frame_name"]['data']); + + } + + return true; +} + +function LookupCurrency($currencyid, $item) { + static $CurrencyLookup = array(); + if (empty($CurrencyLookup)) { + $CurrencyLookup['AED']['country'] = 'United Arab Emirates'; + $CurrencyLookup['AFA']['country'] = 'Afghanistan'; + $CurrencyLookup['ALL']['country'] = 'Albania'; + $CurrencyLookup['AMD']['country'] = 'Armenia'; + $CurrencyLookup['ANG']['country'] = 'Netherlands Antilles'; + $CurrencyLookup['AOA']['country'] = 'Angola'; + $CurrencyLookup['ARS']['country'] = 'Argentina'; + $CurrencyLookup['ATS']['country'] = 'Austria'; + $CurrencyLookup['AUD']['country'] = 'Australia'; + $CurrencyLookup['AWG']['country'] = 'Aruba'; + $CurrencyLookup['AZM']['country'] = 'Azerbaijan'; + $CurrencyLookup['BAM']['country'] = 'Bosnia and Herzegovina'; + $CurrencyLookup['BBD']['country'] = 'Barbados'; + $CurrencyLookup['BDT']['country'] = 'Bangladesh'; + $CurrencyLookup['BEF']['country'] = 'Belgium'; + $CurrencyLookup['BGL']['country'] = 'Bulgaria'; + $CurrencyLookup['BHD']['country'] = 'Bahrain'; + $CurrencyLookup['BIF']['country'] = 'Burundi'; + $CurrencyLookup['BMD']['country'] = 'Bermuda'; + $CurrencyLookup['BND']['country'] = 'Brunei Darussalam'; + $CurrencyLookup['BOB']['country'] = 'Bolivia'; + $CurrencyLookup['BRL']['country'] = 'Brazil'; + $CurrencyLookup['BSD']['country'] = 'Bahamas'; + $CurrencyLookup['BTN']['country'] = 'Bhutan'; + $CurrencyLookup['BWP']['country'] = 'Botswana'; + $CurrencyLookup['BYR']['country'] = 'Belarus'; + $CurrencyLookup['BZD']['country'] = 'Belize'; + $CurrencyLookup['CAD']['country'] = 'Canada'; + $CurrencyLookup['CDF']['country'] = 'Congo/Kinshasa'; + $CurrencyLookup['CHF']['country'] = 'Switzerland'; + $CurrencyLookup['CLP']['country'] = 'Chile'; + $CurrencyLookup['CNY']['country'] = 'China'; + $CurrencyLookup['COP']['country'] = 'Colombia'; + $CurrencyLookup['CRC']['country'] = 'Costa Rica'; + $CurrencyLookup['CUP']['country'] = 'Cuba'; + $CurrencyLookup['CVE']['country'] = 'Cape Verde'; + $CurrencyLookup['CYP']['country'] = 'Cyprus'; + $CurrencyLookup['CZK']['country'] = 'Czech Republic'; + $CurrencyLookup['DEM']['country'] = 'Germany'; + $CurrencyLookup['DJF']['country'] = 'Djibouti'; + $CurrencyLookup['DKK']['country'] = 'Denmark'; + $CurrencyLookup['DOP']['country'] = 'Dominican Republic'; + $CurrencyLookup['DZD']['country'] = 'Algeria'; + $CurrencyLookup['EEK']['country'] = 'Estonia'; + $CurrencyLookup['EGP']['country'] = 'Egypt'; + $CurrencyLookup['ERN']['country'] = 'Eritrea'; + $CurrencyLookup['ESP']['country'] = 'Spain'; + $CurrencyLookup['ETB']['country'] = 'Ethiopia'; + $CurrencyLookup['EUR']['country'] = 'Euro Member Countries'; + $CurrencyLookup['FIM']['country'] = 'Finland'; + $CurrencyLookup['FJD']['country'] = 'Fiji'; + $CurrencyLookup['FKP']['country'] = 'Falkland Islands (Malvinas)'; + $CurrencyLookup['FRF']['country'] = 'France'; + $CurrencyLookup['GBP']['country'] = 'United Kingdom'; + $CurrencyLookup['GEL']['country'] = 'Georgia'; + $CurrencyLookup['GGP']['country'] = 'Guernsey'; + $CurrencyLookup['GHC']['country'] = 'Ghana'; + $CurrencyLookup['GIP']['country'] = 'Gibraltar'; + $CurrencyLookup['GMD']['country'] = 'Gambia'; + $CurrencyLookup['GNF']['country'] = 'Guinea'; + $CurrencyLookup['GRD']['country'] = 'Greece'; + $CurrencyLookup['GTQ']['country'] = 'Guatemala'; + $CurrencyLookup['GYD']['country'] = 'Guyana'; + $CurrencyLookup['HKD']['country'] = 'Hong Kong'; + $CurrencyLookup['HNL']['country'] = 'Honduras'; + $CurrencyLookup['HRK']['country'] = 'Croatia'; + $CurrencyLookup['HTG']['country'] = 'Haiti'; + $CurrencyLookup['HUF']['country'] = 'Hungary'; + $CurrencyLookup['IDR']['country'] = 'Indonesia'; + $CurrencyLookup['IEP']['country'] = 'Ireland (Eire)'; + $CurrencyLookup['ILS']['country'] = 'Israel'; + $CurrencyLookup['IMP']['country'] = 'Isle of Man'; + $CurrencyLookup['INR']['country'] = 'India'; + $CurrencyLookup['IQD']['country'] = 'Iraq'; + $CurrencyLookup['IRR']['country'] = 'Iran'; + $CurrencyLookup['ISK']['country'] = 'Iceland'; + $CurrencyLookup['ITL']['country'] = 'Italy'; + $CurrencyLookup['JEP']['country'] = 'Jersey'; + $CurrencyLookup['JMD']['country'] = 'Jamaica'; + $CurrencyLookup['JOD']['country'] = 'Jordan'; + $CurrencyLookup['JPY']['country'] = 'Japan'; + $CurrencyLookup['KES']['country'] = 'Kenya'; + $CurrencyLookup['KGS']['country'] = 'Kyrgyzstan'; + $CurrencyLookup['KHR']['country'] = 'Cambodia'; + $CurrencyLookup['KMF']['country'] = 'Comoros'; + $CurrencyLookup['KPW']['country'] = 'Korea'; + $CurrencyLookup['KWD']['country'] = 'Kuwait'; + $CurrencyLookup['KYD']['country'] = 'Cayman Islands'; + $CurrencyLookup['KZT']['country'] = 'Kazakstan'; + $CurrencyLookup['LAK']['country'] = 'Laos'; + $CurrencyLookup['LBP']['country'] = 'Lebanon'; + $CurrencyLookup['LKR']['country'] = 'Sri Lanka'; + $CurrencyLookup['LRD']['country'] = 'Liberia'; + $CurrencyLookup['LSL']['country'] = 'Lesotho'; + $CurrencyLookup['LTL']['country'] = 'Lithuania'; + $CurrencyLookup['LUF']['country'] = 'Luxembourg'; + $CurrencyLookup['LVL']['country'] = 'Latvia'; + $CurrencyLookup['LYD']['country'] = 'Libya'; + $CurrencyLookup['MAD']['country'] = 'Morocco'; + $CurrencyLookup['MDL']['country'] = 'Moldova'; + $CurrencyLookup['MGF']['country'] = 'Madagascar'; + $CurrencyLookup['MKD']['country'] = 'Macedonia'; + $CurrencyLookup['MMK']['country'] = 'Myanmar (Burma)'; + $CurrencyLookup['MNT']['country'] = 'Mongolia'; + $CurrencyLookup['MOP']['country'] = 'Macau'; + $CurrencyLookup['MRO']['country'] = 'Mauritania'; + $CurrencyLookup['MTL']['country'] = 'Malta'; + $CurrencyLookup['MUR']['country'] = 'Mauritius'; + $CurrencyLookup['MVR']['country'] = 'Maldives (Maldive Islands)'; + $CurrencyLookup['MWK']['country'] = 'Malawi'; + $CurrencyLookup['MXN']['country'] = 'Mexico'; + $CurrencyLookup['MYR']['country'] = 'Malaysia'; + $CurrencyLookup['MZM']['country'] = 'Mozambique'; + $CurrencyLookup['NAD']['country'] = 'Namibia'; + $CurrencyLookup['NGN']['country'] = 'Nigeria'; + $CurrencyLookup['NIO']['country'] = 'Nicaragua'; + $CurrencyLookup['NLG']['country'] = 'Netherlands (Holland)'; + $CurrencyLookup['NOK']['country'] = 'Norway'; + $CurrencyLookup['NPR']['country'] = 'Nepal'; + $CurrencyLookup['NZD']['country'] = 'New Zealand'; + $CurrencyLookup['OMR']['country'] = 'Oman'; + $CurrencyLookup['PAB']['country'] = 'Panama'; + $CurrencyLookup['PEN']['country'] = 'Peru'; + $CurrencyLookup['PGK']['country'] = 'Papua New Guinea'; + $CurrencyLookup['PHP']['country'] = 'Philippines'; + $CurrencyLookup['PKR']['country'] = 'Pakistan'; + $CurrencyLookup['PLN']['country'] = 'Poland'; + $CurrencyLookup['PTE']['country'] = 'Portugal'; + $CurrencyLookup['PYG']['country'] = 'Paraguay'; + $CurrencyLookup['QAR']['country'] = 'Qatar'; + $CurrencyLookup['ROL']['country'] = 'Romania'; + $CurrencyLookup['RUR']['country'] = 'Russia'; + $CurrencyLookup['RWF']['country'] = 'Rwanda'; + $CurrencyLookup['SAR']['country'] = 'Saudi Arabia'; + $CurrencyLookup['SBD']['country'] = 'Solomon Islands'; + $CurrencyLookup['SCR']['country'] = 'Seychelles'; + $CurrencyLookup['SDD']['country'] = 'Sudan'; + $CurrencyLookup['SEK']['country'] = 'Sweden'; + $CurrencyLookup['SGD']['country'] = 'Singapore'; + $CurrencyLookup['SHP']['country'] = 'Saint Helena'; + $CurrencyLookup['SIT']['country'] = 'Slovenia'; + $CurrencyLookup['SKK']['country'] = 'Slovakia'; + $CurrencyLookup['SLL']['country'] = 'Sierra Leone'; + $CurrencyLookup['SOS']['country'] = 'Somalia'; + $CurrencyLookup['SPL']['country'] = 'Seborga'; + $CurrencyLookup['SRG']['country'] = 'Suriname'; + $CurrencyLookup['STD']['country'] = 'São Tome and Principe'; + $CurrencyLookup['SVC']['country'] = 'El Salvador'; + $CurrencyLookup['SYP']['country'] = 'Syria'; + $CurrencyLookup['SZL']['country'] = 'Swaziland'; + $CurrencyLookup['THB']['country'] = 'Thailand'; + $CurrencyLookup['TJR']['country'] = 'Tajikistan'; + $CurrencyLookup['TMM']['country'] = 'Turkmenistan'; + $CurrencyLookup['TND']['country'] = 'Tunisia'; + $CurrencyLookup['TOP']['country'] = 'Tonga'; + $CurrencyLookup['TRL']['country'] = 'Turkey'; + $CurrencyLookup['TTD']['country'] = 'Trinidad and Tobago'; + $CurrencyLookup['TVD']['country'] = 'Tuvalu'; + $CurrencyLookup['TWD']['country'] = 'Taiwan'; + $CurrencyLookup['TZS']['country'] = 'Tanzania'; + $CurrencyLookup['UAH']['country'] = 'Ukraine'; + $CurrencyLookup['UGX']['country'] = 'Uganda'; + $CurrencyLookup['USD']['country'] = 'United States of America'; + $CurrencyLookup['UYU']['country'] = 'Uruguay'; + $CurrencyLookup['UZS']['country'] = 'Uzbekistan'; + $CurrencyLookup['VAL']['country'] = 'Vatican City'; + $CurrencyLookup['VEB']['country'] = 'Venezuela'; + $CurrencyLookup['VND']['country'] = 'Viet Nam'; + $CurrencyLookup['VUV']['country'] = 'Vanuatu'; + $CurrencyLookup['WST']['country'] = 'Samoa'; + $CurrencyLookup['XAF']['country'] = 'Communauté Financière Africaine'; + $CurrencyLookup['XAG']['country'] = 'Silver'; + $CurrencyLookup['XAU']['country'] = 'Gold'; + $CurrencyLookup['XCD']['country'] = 'East Caribbean'; + $CurrencyLookup['XDR']['country'] = 'International Monetary Fund'; + $CurrencyLookup['XPD']['country'] = 'Palladium'; + $CurrencyLookup['XPF']['country'] = 'Comptoirs Français du Pacifique'; + $CurrencyLookup['XPT']['country'] = 'Platinum'; + $CurrencyLookup['YER']['country'] = 'Yemen'; + $CurrencyLookup['YUM']['country'] = 'Yugoslavia'; + $CurrencyLookup['ZAR']['country'] = 'South Africa'; + $CurrencyLookup['ZMK']['country'] = 'Zambia'; + $CurrencyLookup['ZWD']['country'] = 'Zimbabwe'; + $CurrencyLookup['AED']['units'] = 'Dirhams'; + $CurrencyLookup['AFA']['units'] = 'Afghanis'; + $CurrencyLookup['ALL']['units'] = 'Leke'; + $CurrencyLookup['AMD']['units'] = 'Drams'; + $CurrencyLookup['ANG']['units'] = 'Guilders'; + $CurrencyLookup['AOA']['units'] = 'Kwanza'; + $CurrencyLookup['ARS']['units'] = 'Pesos'; + $CurrencyLookup['ATS']['units'] = 'Schillings'; + $CurrencyLookup['AUD']['units'] = 'Dollars'; + $CurrencyLookup['AWG']['units'] = 'Guilders'; + $CurrencyLookup['AZM']['units'] = 'Manats'; + $CurrencyLookup['BAM']['units'] = 'Convertible Marka'; + $CurrencyLookup['BBD']['units'] = 'Dollars'; + $CurrencyLookup['BDT']['units'] = 'Taka'; + $CurrencyLookup['BEF']['units'] = 'Francs'; + $CurrencyLookup['BGL']['units'] = 'Leva'; + $CurrencyLookup['BHD']['units'] = 'Dinars'; + $CurrencyLookup['BIF']['units'] = 'Francs'; + $CurrencyLookup['BMD']['units'] = 'Dollars'; + $CurrencyLookup['BND']['units'] = 'Dollars'; + $CurrencyLookup['BOB']['units'] = 'Bolivianos'; + $CurrencyLookup['BRL']['units'] = 'Brazil Real'; + $CurrencyLookup['BSD']['units'] = 'Dollars'; + $CurrencyLookup['BTN']['units'] = 'Ngultrum'; + $CurrencyLookup['BWP']['units'] = 'Pulas'; + $CurrencyLookup['BYR']['units'] = 'Rubles'; + $CurrencyLookup['BZD']['units'] = 'Dollars'; + $CurrencyLookup['CAD']['units'] = 'Dollars'; + $CurrencyLookup['CDF']['units'] = 'Congolese Francs'; + $CurrencyLookup['CHF']['units'] = 'Francs'; + $CurrencyLookup['CLP']['units'] = 'Pesos'; + $CurrencyLookup['CNY']['units'] = 'Yuan Renminbi'; + $CurrencyLookup['COP']['units'] = 'Pesos'; + $CurrencyLookup['CRC']['units'] = 'Colones'; + $CurrencyLookup['CUP']['units'] = 'Pesos'; + $CurrencyLookup['CVE']['units'] = 'Escudos'; + $CurrencyLookup['CYP']['units'] = 'Pounds'; + $CurrencyLookup['CZK']['units'] = 'Koruny'; + $CurrencyLookup['DEM']['units'] = 'Deutsche Marks'; + $CurrencyLookup['DJF']['units'] = 'Francs'; + $CurrencyLookup['DKK']['units'] = 'Kroner'; + $CurrencyLookup['DOP']['units'] = 'Pesos'; + $CurrencyLookup['DZD']['units'] = 'Algeria Dinars'; + $CurrencyLookup['EEK']['units'] = 'Krooni'; + $CurrencyLookup['EGP']['units'] = 'Pounds'; + $CurrencyLookup['ERN']['units'] = 'Nakfa'; + $CurrencyLookup['ESP']['units'] = 'Pesetas'; + $CurrencyLookup['ETB']['units'] = 'Birr'; + $CurrencyLookup['EUR']['units'] = 'Euro'; + $CurrencyLookup['FIM']['units'] = 'Markkaa'; + $CurrencyLookup['FJD']['units'] = 'Dollars'; + $CurrencyLookup['FKP']['units'] = 'Pounds'; + $CurrencyLookup['FRF']['units'] = 'Francs'; + $CurrencyLookup['GBP']['units'] = 'Pounds'; + $CurrencyLookup['GEL']['units'] = 'Lari'; + $CurrencyLookup['GGP']['units'] = 'Pounds'; + $CurrencyLookup['GHC']['units'] = 'Cedis'; + $CurrencyLookup['GIP']['units'] = 'Pounds'; + $CurrencyLookup['GMD']['units'] = 'Dalasi'; + $CurrencyLookup['GNF']['units'] = 'Francs'; + $CurrencyLookup['GRD']['units'] = 'Drachmae'; + $CurrencyLookup['GTQ']['units'] = 'Quetzales'; + $CurrencyLookup['GYD']['units'] = 'Dollars'; + $CurrencyLookup['HKD']['units'] = 'Dollars'; + $CurrencyLookup['HNL']['units'] = 'Lempiras'; + $CurrencyLookup['HRK']['units'] = 'Kuna'; + $CurrencyLookup['HTG']['units'] = 'Gourdes'; + $CurrencyLookup['HUF']['units'] = 'Forints'; + $CurrencyLookup['IDR']['units'] = 'Rupiahs'; + $CurrencyLookup['IEP']['units'] = 'Pounds'; + $CurrencyLookup['ILS']['units'] = 'New Shekels'; + $CurrencyLookup['IMP']['units'] = 'Pounds'; + $CurrencyLookup['INR']['units'] = 'Rupees'; + $CurrencyLookup['IQD']['units'] = 'Dinars'; + $CurrencyLookup['IRR']['units'] = 'Rials'; + $CurrencyLookup['ISK']['units'] = 'Kronur'; + $CurrencyLookup['ITL']['units'] = 'Lire'; + $CurrencyLookup['JEP']['units'] = 'Pounds'; + $CurrencyLookup['JMD']['units'] = 'Dollars'; + $CurrencyLookup['JOD']['units'] = 'Dinars'; + $CurrencyLookup['JPY']['units'] = 'Yen'; + $CurrencyLookup['KES']['units'] = 'Shillings'; + $CurrencyLookup['KGS']['units'] = 'Soms'; + $CurrencyLookup['KHR']['units'] = 'Riels'; + $CurrencyLookup['KMF']['units'] = 'Francs'; + $CurrencyLookup['KPW']['units'] = 'Won'; + $CurrencyLookup['KWD']['units'] = 'Dinars'; + $CurrencyLookup['KYD']['units'] = 'Dollars'; + $CurrencyLookup['KZT']['units'] = 'Tenge'; + $CurrencyLookup['LAK']['units'] = 'Kips'; + $CurrencyLookup['LBP']['units'] = 'Pounds'; + $CurrencyLookup['LKR']['units'] = 'Rupees'; + $CurrencyLookup['LRD']['units'] = 'Dollars'; + $CurrencyLookup['LSL']['units'] = 'Maloti'; + $CurrencyLookup['LTL']['units'] = 'Litai'; + $CurrencyLookup['LUF']['units'] = 'Francs'; + $CurrencyLookup['LVL']['units'] = 'Lati'; + $CurrencyLookup['LYD']['units'] = 'Dinars'; + $CurrencyLookup['MAD']['units'] = 'Dirhams'; + $CurrencyLookup['MDL']['units'] = 'Lei'; + $CurrencyLookup['MGF']['units'] = 'Malagasy Francs'; + $CurrencyLookup['MKD']['units'] = 'Denars'; + $CurrencyLookup['MMK']['units'] = 'Kyats'; + $CurrencyLookup['MNT']['units'] = 'Tugriks'; + $CurrencyLookup['MOP']['units'] = 'Patacas'; + $CurrencyLookup['MRO']['units'] = 'Ouguiyas'; + $CurrencyLookup['MTL']['units'] = 'Liri'; + $CurrencyLookup['MUR']['units'] = 'Rupees'; + $CurrencyLookup['MVR']['units'] = 'Rufiyaa'; + $CurrencyLookup['MWK']['units'] = 'Kwachas'; + $CurrencyLookup['MXN']['units'] = 'Pesos'; + $CurrencyLookup['MYR']['units'] = 'Ringgits'; + $CurrencyLookup['MZM']['units'] = 'Meticais'; + $CurrencyLookup['NAD']['units'] = 'Dollars'; + $CurrencyLookup['NGN']['units'] = 'Nairas'; + $CurrencyLookup['NIO']['units'] = 'Gold Cordobas'; + $CurrencyLookup['NLG']['units'] = 'Guilders'; + $CurrencyLookup['NOK']['units'] = 'Krone'; + $CurrencyLookup['NPR']['units'] = 'Nepal Rupees'; + $CurrencyLookup['NZD']['units'] = 'Dollars'; + $CurrencyLookup['OMR']['units'] = 'Rials'; + $CurrencyLookup['PAB']['units'] = 'Balboa'; + $CurrencyLookup['PEN']['units'] = 'Nuevos Soles'; + $CurrencyLookup['PGK']['units'] = 'Kina'; + $CurrencyLookup['PHP']['units'] = 'Pesos'; + $CurrencyLookup['PKR']['units'] = 'Rupees'; + $CurrencyLookup['PLN']['units'] = 'Zlotych'; + $CurrencyLookup['PTE']['units'] = 'Escudos'; + $CurrencyLookup['PYG']['units'] = 'Guarani'; + $CurrencyLookup['QAR']['units'] = 'Rials'; + $CurrencyLookup['ROL']['units'] = 'Lei'; + $CurrencyLookup['RUR']['units'] = 'Rubles'; + $CurrencyLookup['RWF']['units'] = 'Rwanda Francs'; + $CurrencyLookup['SAR']['units'] = 'Riyals'; + $CurrencyLookup['SBD']['units'] = 'Dollars'; + $CurrencyLookup['SCR']['units'] = 'Rupees'; + $CurrencyLookup['SDD']['units'] = 'Dinars'; + $CurrencyLookup['SEK']['units'] = 'Kronor'; + $CurrencyLookup['SGD']['units'] = 'Dollars'; + $CurrencyLookup['SHP']['units'] = 'Pounds'; + $CurrencyLookup['SIT']['units'] = 'Tolars'; + $CurrencyLookup['SKK']['units'] = 'Koruny'; + $CurrencyLookup['SLL']['units'] = 'Leones'; + $CurrencyLookup['SOS']['units'] = 'Shillings'; + $CurrencyLookup['SPL']['units'] = 'Luigini'; + $CurrencyLookup['SRG']['units'] = 'Guilders'; + $CurrencyLookup['STD']['units'] = 'Dobras'; + $CurrencyLookup['SVC']['units'] = 'Colones'; + $CurrencyLookup['SYP']['units'] = 'Pounds'; + $CurrencyLookup['SZL']['units'] = 'Emalangeni'; + $CurrencyLookup['THB']['units'] = 'Baht'; + $CurrencyLookup['TJR']['units'] = 'Rubles'; + $CurrencyLookup['TMM']['units'] = 'Manats'; + $CurrencyLookup['TND']['units'] = 'Dinars'; + $CurrencyLookup['TOP']['units'] = 'Pa\'anga'; + $CurrencyLookup['TRL']['units'] = 'Liras'; + $CurrencyLookup['TTD']['units'] = 'Dollars'; + $CurrencyLookup['TVD']['units'] = 'Tuvalu Dollars'; + $CurrencyLookup['TWD']['units'] = 'New Dollars'; + $CurrencyLookup['TZS']['units'] = 'Shillings'; + $CurrencyLookup['UAH']['units'] = 'Hryvnia'; + $CurrencyLookup['UGX']['units'] = 'Shillings'; + $CurrencyLookup['USD']['units'] = 'Dollars'; + $CurrencyLookup['UYU']['units'] = 'Pesos'; + $CurrencyLookup['UZS']['units'] = 'Sums'; + $CurrencyLookup['VAL']['units'] = 'Lire'; + $CurrencyLookup['VEB']['units'] = 'Bolivares'; + $CurrencyLookup['VND']['units'] = 'Dong'; + $CurrencyLookup['VUV']['units'] = 'Vatu'; + $CurrencyLookup['WST']['units'] = 'Tala'; + $CurrencyLookup['XAF']['units'] = 'Francs'; + $CurrencyLookup['XAG']['units'] = 'Ounces'; + $CurrencyLookup['XAU']['units'] = 'Ounces'; + $CurrencyLookup['XCD']['units'] = 'Dollars'; + $CurrencyLookup['XDR']['units'] = 'Special Drawing Rights'; + $CurrencyLookup['XPD']['units'] = 'Ounces'; + $CurrencyLookup['XPF']['units'] = 'Francs'; + $CurrencyLookup['XPT']['units'] = 'Ounces'; + $CurrencyLookup['YER']['units'] = 'Rials'; + $CurrencyLookup['YUM']['units'] = 'New Dinars'; + $CurrencyLookup['ZAR']['units'] = 'Rand'; + $CurrencyLookup['ZMK']['units'] = 'Kwacha'; + $CurrencyLookup['ZWD']['units'] = 'Zimbabwe Dollars'; + } + + return (isset($CurrencyLookup["$currencyid"]["$item"]) ? $CurrencyLookup["$currencyid"]["$item"] : ''); +} + +function LanguageLookup($languagecode, $casesensitive=false) { + // ISO 639-2 - http://www.id3.org/iso639-2.html + if ($languagecode == 'XXX') { + return 'unknown'; + } + if (!$casesensitive) { + $languagecode = strtolower($languagecode); + } + + static $LanguageLookup = array(); + if (empty($LanguageLookup)) { + $LanguageLookup['aar'] = 'Afar'; + $LanguageLookup['abk'] = 'Abkhazian'; + $LanguageLookup['ace'] = 'Achinese'; + $LanguageLookup['ach'] = 'Acoli'; + $LanguageLookup['ada'] = 'Adangme'; + $LanguageLookup['afa'] = 'Afro-Asiatic (Other)'; + $LanguageLookup['afh'] = 'Afrihili'; + $LanguageLookup['afr'] = 'Afrikaans'; + $LanguageLookup['aka'] = 'Akan'; + $LanguageLookup['akk'] = 'Akkadian'; + $LanguageLookup['alb'] = 'Albanian'; + $LanguageLookup['ale'] = 'Aleut'; + $LanguageLookup['alg'] = 'Algonquian Languages'; + $LanguageLookup['amh'] = 'Amharic'; + $LanguageLookup['ang'] = 'English, Old (ca. 450-1100)'; + $LanguageLookup['apa'] = 'Apache Languages'; + $LanguageLookup['ara'] = 'Arabic'; + $LanguageLookup['arc'] = 'Aramaic'; + $LanguageLookup['arm'] = 'Armenian'; + $LanguageLookup['arn'] = 'Araucanian'; + $LanguageLookup['arp'] = 'Arapaho'; + $LanguageLookup['art'] = 'Artificial (Other)'; + $LanguageLookup['arw'] = 'Arawak'; + $LanguageLookup['asm'] = 'Assamese'; + $LanguageLookup['ath'] = 'Athapascan Languages'; + $LanguageLookup['ava'] = 'Avaric'; + $LanguageLookup['ave'] = 'Avestan'; + $LanguageLookup['awa'] = 'Awadhi'; + $LanguageLookup['aym'] = 'Aymara'; + $LanguageLookup['aze'] = 'Azerbaijani'; + $LanguageLookup['bad'] = 'Banda'; + $LanguageLookup['bai'] = 'Bamileke Languages'; + $LanguageLookup['bak'] = 'Bashkir'; + $LanguageLookup['bal'] = 'Baluchi'; + $LanguageLookup['bam'] = 'Bambara'; + $LanguageLookup['ban'] = 'Balinese'; + $LanguageLookup['baq'] = 'Basque'; + $LanguageLookup['bas'] = 'Basa'; + $LanguageLookup['bat'] = 'Baltic (Other)'; + $LanguageLookup['bej'] = 'Beja'; + $LanguageLookup['bel'] = 'Byelorussian'; + $LanguageLookup['bem'] = 'Bemba'; + $LanguageLookup['ben'] = 'Bengali'; + $LanguageLookup['ber'] = 'Berber (Other)'; + $LanguageLookup['bho'] = 'Bhojpuri'; + $LanguageLookup['bih'] = 'Bihari'; + $LanguageLookup['bik'] = 'Bikol'; + $LanguageLookup['bin'] = 'Bini'; + $LanguageLookup['bis'] = 'Bislama'; + $LanguageLookup['bla'] = 'Siksika'; + $LanguageLookup['bnt'] = 'Bantu (Other)'; + $LanguageLookup['bod'] = 'Tibetan'; + $LanguageLookup['bra'] = 'Braj'; + $LanguageLookup['bre'] = 'Breton'; + $LanguageLookup['bua'] = 'Buriat'; + $LanguageLookup['bug'] = 'Buginese'; + $LanguageLookup['bul'] = 'Bulgarian'; + $LanguageLookup['bur'] = 'Burmese'; + $LanguageLookup['cad'] = 'Caddo'; + $LanguageLookup['cai'] = 'Central American Indian (Other)'; + $LanguageLookup['car'] = 'Carib'; + $LanguageLookup['cat'] = 'Catalan'; + $LanguageLookup['cau'] = 'Caucasian (Other)'; + $LanguageLookup['ceb'] = 'Cebuano'; + $LanguageLookup['cel'] = 'Celtic (Other)'; + $LanguageLookup['ces'] = 'Czech'; + $LanguageLookup['cha'] = 'Chamorro'; + $LanguageLookup['chb'] = 'Chibcha'; + $LanguageLookup['che'] = 'Chechen'; + $LanguageLookup['chg'] = 'Chagatai'; + $LanguageLookup['chi'] = 'Chinese'; + $LanguageLookup['chm'] = 'Mari'; + $LanguageLookup['chn'] = 'Chinook jargon'; + $LanguageLookup['cho'] = 'Choctaw'; + $LanguageLookup['chr'] = 'Cherokee'; + $LanguageLookup['chu'] = 'Church Slavic'; + $LanguageLookup['chv'] = 'Chuvash'; + $LanguageLookup['chy'] = 'Cheyenne'; + $LanguageLookup['cop'] = 'Coptic'; + $LanguageLookup['cor'] = 'Cornish'; + $LanguageLookup['cos'] = 'Corsican'; + $LanguageLookup['cpe'] = 'Creoles and Pidgins, English-based (Other)'; + $LanguageLookup['cpf'] = 'Creoles and Pidgins, French-based (Other)'; + $LanguageLookup['cpp'] = 'Creoles and Pidgins, Portuguese-based (Other)'; + $LanguageLookup['cre'] = 'Cree'; + $LanguageLookup['crp'] = 'Creoles and Pidgins (Other)'; + $LanguageLookup['cus'] = 'Cushitic (Other)'; + $LanguageLookup['cym'] = 'Welsh'; + $LanguageLookup['cze'] = 'Czech'; + $LanguageLookup['dak'] = 'Dakota'; + $LanguageLookup['dan'] = 'Danish'; + $LanguageLookup['del'] = 'Delaware'; + $LanguageLookup['deu'] = 'German'; + $LanguageLookup['din'] = 'Dinka'; + $LanguageLookup['div'] = 'Divehi'; + $LanguageLookup['doi'] = 'Dogri'; + $LanguageLookup['dra'] = 'Dravidian (Other)'; + $LanguageLookup['dua'] = 'Duala'; + $LanguageLookup['dum'] = 'Dutch, Middle (ca. 1050-1350)'; + $LanguageLookup['dut'] = 'Dutch'; + $LanguageLookup['dyu'] = 'Dyula'; + $LanguageLookup['dzo'] = 'Dzongkha'; + $LanguageLookup['efi'] = 'Efik'; + $LanguageLookup['egy'] = 'Egyptian (Ancient)'; + $LanguageLookup['eka'] = 'Ekajuk'; + $LanguageLookup['ell'] = 'Greek, Modern (1453-)'; + $LanguageLookup['elx'] = 'Elamite'; + $LanguageLookup['eng'] = 'English'; + $LanguageLookup['enm'] = 'English, Middle (ca. 1100-1500)'; + $LanguageLookup['epo'] = 'Esperanto'; + $LanguageLookup['esk'] = 'Eskimo (Other)'; + $LanguageLookup['esl'] = 'Spanish'; + $LanguageLookup['est'] = 'Estonian'; + $LanguageLookup['eus'] = 'Basque'; + $LanguageLookup['ewe'] = 'Ewe'; + $LanguageLookup['ewo'] = 'Ewondo'; + $LanguageLookup['fan'] = 'Fang'; + $LanguageLookup['fao'] = 'Faroese'; + $LanguageLookup['fas'] = 'Persian'; + $LanguageLookup['fat'] = 'Fanti'; + $LanguageLookup['fij'] = 'Fijian'; + $LanguageLookup['fin'] = 'Finnish'; + $LanguageLookup['fiu'] = 'Finno-Ugrian (Other)'; + $LanguageLookup['fon'] = 'Fon'; + $LanguageLookup['fra'] = 'French'; + $LanguageLookup['fre'] = 'French'; + $LanguageLookup['frm'] = 'French, Middle (ca. 1400-1600)'; + $LanguageLookup['fro'] = 'French, Old (842- ca. 1400)'; + $LanguageLookup['fry'] = 'Frisian'; + $LanguageLookup['ful'] = 'Fulah'; + $LanguageLookup['gaa'] = 'Ga'; + $LanguageLookup['gae'] = 'Gaelic (Scots)'; + $LanguageLookup['gai'] = 'Irish'; + $LanguageLookup['gay'] = 'Gayo'; + $LanguageLookup['gdh'] = 'Gaelic (Scots)'; + $LanguageLookup['gem'] = 'Germanic (Other)'; + $LanguageLookup['geo'] = 'Georgian'; + $LanguageLookup['ger'] = 'German'; + $LanguageLookup['gez'] = 'Geez'; + $LanguageLookup['gil'] = 'Gilbertese'; + $LanguageLookup['glg'] = 'Gallegan'; + $LanguageLookup['gmh'] = 'German, Middle High (ca. 1050-1500)'; + $LanguageLookup['goh'] = 'German, Old High (ca. 750-1050)'; + $LanguageLookup['gon'] = 'Gondi'; + $LanguageLookup['got'] = 'Gothic'; + $LanguageLookup['grb'] = 'Grebo'; + $LanguageLookup['grc'] = 'Greek, Ancient (to 1453)'; + $LanguageLookup['gre'] = 'Greek, Modern (1453-)'; + $LanguageLookup['grn'] = 'Guarani'; + $LanguageLookup['guj'] = 'Gujarati'; + $LanguageLookup['hai'] = 'Haida'; + $LanguageLookup['hau'] = 'Hausa'; + $LanguageLookup['haw'] = 'Hawaiian'; + $LanguageLookup['heb'] = 'Hebrew'; + $LanguageLookup['her'] = 'Herero'; + $LanguageLookup['hil'] = 'Hiligaynon'; + $LanguageLookup['him'] = 'Himachali'; + $LanguageLookup['hin'] = 'Hindi'; + $LanguageLookup['hmo'] = 'Hiri Motu'; + $LanguageLookup['hun'] = 'Hungarian'; + $LanguageLookup['hup'] = 'Hupa'; + $LanguageLookup['hye'] = 'Armenian'; + $LanguageLookup['iba'] = 'Iban'; + $LanguageLookup['ibo'] = 'Igbo'; + $LanguageLookup['ice'] = 'Icelandic'; + $LanguageLookup['ijo'] = 'Ijo'; + $LanguageLookup['iku'] = 'Inuktitut'; + $LanguageLookup['ilo'] = 'Iloko'; + $LanguageLookup['ina'] = 'Interlingua (International Auxiliary language Association)'; + $LanguageLookup['inc'] = 'Indic (Other)'; + $LanguageLookup['ind'] = 'Indonesian'; + $LanguageLookup['ine'] = 'Indo-European (Other)'; + $LanguageLookup['ine'] = 'Interlingue'; + $LanguageLookup['ipk'] = 'Inupiak'; + $LanguageLookup['ira'] = 'Iranian (Other)'; + $LanguageLookup['iri'] = 'Irish'; + $LanguageLookup['iro'] = 'Iroquoian uages'; + $LanguageLookup['isl'] = 'Icelandic'; + $LanguageLookup['ita'] = 'Italian'; + $LanguageLookup['jav'] = 'Javanese'; + $LanguageLookup['jaw'] = 'Javanese'; + $LanguageLookup['jpn'] = 'Japanese'; + $LanguageLookup['jpr'] = 'Judeo-Persian'; + $LanguageLookup['jrb'] = 'Judeo-Arabic'; + $LanguageLookup['kaa'] = 'Kara-Kalpak'; + $LanguageLookup['kab'] = 'Kabyle'; + $LanguageLookup['kac'] = 'Kachin'; + $LanguageLookup['kal'] = 'Greenlandic'; + $LanguageLookup['kam'] = 'Kamba'; + $LanguageLookup['kan'] = 'Kannada'; + $LanguageLookup['kar'] = 'Karen'; + $LanguageLookup['kas'] = 'Kashmiri'; + $LanguageLookup['kat'] = 'Georgian'; + $LanguageLookup['kau'] = 'Kanuri'; + $LanguageLookup['kaw'] = 'Kawi'; + $LanguageLookup['kaz'] = 'Kazakh'; + $LanguageLookup['kha'] = 'Khasi'; + $LanguageLookup['khi'] = 'Khoisan (Other)'; + $LanguageLookup['khm'] = 'Khmer'; + $LanguageLookup['kho'] = 'Khotanese'; + $LanguageLookup['kik'] = 'Kikuyu'; + $LanguageLookup['kin'] = 'Kinyarwanda'; + $LanguageLookup['kir'] = 'Kirghiz'; + $LanguageLookup['kok'] = 'Konkani'; + $LanguageLookup['kom'] = 'Komi'; + $LanguageLookup['kon'] = 'Kongo'; + $LanguageLookup['kor'] = 'Korean'; + $LanguageLookup['kpe'] = 'Kpelle'; + $LanguageLookup['kro'] = 'Kru'; + $LanguageLookup['kru'] = 'Kurukh'; + $LanguageLookup['kua'] = 'Kuanyama'; + $LanguageLookup['kum'] = 'Kumyk'; + $LanguageLookup['kur'] = 'Kurdish'; + $LanguageLookup['kus'] = 'Kusaie'; + $LanguageLookup['kut'] = 'Kutenai'; + $LanguageLookup['lad'] = 'Ladino'; + $LanguageLookup['lah'] = 'Lahnda'; + $LanguageLookup['lam'] = 'Lamba'; + $LanguageLookup['lao'] = 'Lao'; + $LanguageLookup['lat'] = 'Latin'; + $LanguageLookup['lav'] = 'Latvian'; + $LanguageLookup['lez'] = 'Lezghian'; + $LanguageLookup['lin'] = 'Lingala'; + $LanguageLookup['lit'] = 'Lithuanian'; + $LanguageLookup['lol'] = 'Mongo'; + $LanguageLookup['loz'] = 'Lozi'; + $LanguageLookup['ltz'] = 'Letzeburgesch'; + $LanguageLookup['lub'] = 'Luba-Katanga'; + $LanguageLookup['lug'] = 'Ganda'; + $LanguageLookup['lui'] = 'Luiseno'; + $LanguageLookup['lun'] = 'Lunda'; + $LanguageLookup['luo'] = 'Luo (Kenya and Tanzania)'; + $LanguageLookup['mac'] = 'Macedonian'; + $LanguageLookup['mad'] = 'Madurese'; + $LanguageLookup['mag'] = 'Magahi'; + $LanguageLookup['mah'] = 'Marshall'; + $LanguageLookup['mai'] = 'Maithili'; + $LanguageLookup['mak'] = 'Macedonian'; + $LanguageLookup['mak'] = 'Makasar'; + $LanguageLookup['mal'] = 'Malayalam'; + $LanguageLookup['man'] = 'Mandingo'; + $LanguageLookup['mao'] = 'Maori'; + $LanguageLookup['map'] = 'Austronesian (Other)'; + $LanguageLookup['mar'] = 'Marathi'; + $LanguageLookup['mas'] = 'Masai'; + $LanguageLookup['max'] = 'Manx'; + $LanguageLookup['may'] = 'Malay'; + $LanguageLookup['men'] = 'Mende'; + $LanguageLookup['mga'] = 'Irish, Middle (900 - 1200)'; + $LanguageLookup['mic'] = 'Micmac'; + $LanguageLookup['min'] = 'Minangkabau'; + $LanguageLookup['mis'] = 'Miscellaneous (Other)'; + $LanguageLookup['mkh'] = 'Mon-Kmer (Other)'; + $LanguageLookup['mlg'] = 'Malagasy'; + $LanguageLookup['mlt'] = 'Maltese'; + $LanguageLookup['mni'] = 'Manipuri'; + $LanguageLookup['mno'] = 'Manobo Languages'; + $LanguageLookup['moh'] = 'Mohawk'; + $LanguageLookup['mol'] = 'Moldavian'; + $LanguageLookup['mon'] = 'Mongolian'; + $LanguageLookup['mos'] = 'Mossi'; + $LanguageLookup['mri'] = 'Maori'; + $LanguageLookup['msa'] = 'Malay'; + $LanguageLookup['mul'] = 'Multiple Languages'; + $LanguageLookup['mun'] = 'Munda Languages'; + $LanguageLookup['mus'] = 'Creek'; + $LanguageLookup['mwr'] = 'Marwari'; + $LanguageLookup['mya'] = 'Burmese'; + $LanguageLookup['myn'] = 'Mayan Languages'; + $LanguageLookup['nah'] = 'Aztec'; + $LanguageLookup['nai'] = 'North American Indian (Other)'; + $LanguageLookup['nau'] = 'Nauru'; + $LanguageLookup['nav'] = 'Navajo'; + $LanguageLookup['nbl'] = 'Ndebele, South'; + $LanguageLookup['nde'] = 'Ndebele, North'; + $LanguageLookup['ndo'] = 'Ndongo'; + $LanguageLookup['nep'] = 'Nepali'; + $LanguageLookup['new'] = 'Newari'; + $LanguageLookup['nic'] = 'Niger-Kordofanian (Other)'; + $LanguageLookup['niu'] = 'Niuean'; + $LanguageLookup['nla'] = 'Dutch'; + $LanguageLookup['nno'] = 'Norwegian (Nynorsk)'; + $LanguageLookup['non'] = 'Norse, Old'; + $LanguageLookup['nor'] = 'Norwegian'; + $LanguageLookup['nso'] = 'Sotho, Northern'; + $LanguageLookup['nub'] = 'Nubian Languages'; + $LanguageLookup['nya'] = 'Nyanja'; + $LanguageLookup['nym'] = 'Nyamwezi'; + $LanguageLookup['nyn'] = 'Nyankole'; + $LanguageLookup['nyo'] = 'Nyoro'; + $LanguageLookup['nzi'] = 'Nzima'; + $LanguageLookup['oci'] = 'Langue d\'Oc (post 1500)'; + $LanguageLookup['oji'] = 'Ojibwa'; + $LanguageLookup['ori'] = 'Oriya'; + $LanguageLookup['orm'] = 'Oromo'; + $LanguageLookup['osa'] = 'Osage'; + $LanguageLookup['oss'] = 'Ossetic'; + $LanguageLookup['ota'] = 'Turkish, Ottoman (1500 - 1928)'; + $LanguageLookup['oto'] = 'Otomian Languages'; + $LanguageLookup['paa'] = 'Papuan-Australian (Other)'; + $LanguageLookup['pag'] = 'Pangasinan'; + $LanguageLookup['pal'] = 'Pahlavi'; + $LanguageLookup['pam'] = 'Pampanga'; + $LanguageLookup['pan'] = 'Panjabi'; + $LanguageLookup['pap'] = 'Papiamento'; + $LanguageLookup['pau'] = 'Palauan'; + $LanguageLookup['peo'] = 'Persian, Old (ca 600 - 400 B.C.)'; + $LanguageLookup['per'] = 'Persian'; + $LanguageLookup['phn'] = 'Phoenician'; + $LanguageLookup['pli'] = 'Pali'; + $LanguageLookup['pol'] = 'Polish'; + $LanguageLookup['pon'] = 'Ponape'; + $LanguageLookup['por'] = 'Portuguese'; + $LanguageLookup['pra'] = 'Prakrit uages'; + $LanguageLookup['pro'] = 'Provencal, Old (to 1500)'; + $LanguageLookup['pus'] = 'Pushto'; + $LanguageLookup['que'] = 'Quechua'; + $LanguageLookup['raj'] = 'Rajasthani'; + $LanguageLookup['rar'] = 'Rarotongan'; + $LanguageLookup['roa'] = 'Romance (Other)'; + $LanguageLookup['roh'] = 'Rhaeto-Romance'; + $LanguageLookup['rom'] = 'Romany'; + $LanguageLookup['ron'] = 'Romanian'; + $LanguageLookup['rum'] = 'Romanian'; + $LanguageLookup['run'] = 'Rundi'; + $LanguageLookup['rus'] = 'Russian'; + $LanguageLookup['sad'] = 'Sandawe'; + $LanguageLookup['sag'] = 'Sango'; + $LanguageLookup['sah'] = 'Yakut'; + $LanguageLookup['sai'] = 'South American Indian (Other)'; + $LanguageLookup['sal'] = 'Salishan Languages'; + $LanguageLookup['sam'] = 'Samaritan Aramaic'; + $LanguageLookup['san'] = 'Sanskrit'; + $LanguageLookup['sco'] = 'Scots'; + $LanguageLookup['scr'] = 'Serbo-Croatian'; + $LanguageLookup['sel'] = 'Selkup'; + $LanguageLookup['sem'] = 'Semitic (Other)'; + $LanguageLookup['sga'] = 'Irish, Old (to 900)'; + $LanguageLookup['shn'] = 'Shan'; + $LanguageLookup['sid'] = 'Sidamo'; + $LanguageLookup['sin'] = 'Singhalese'; + $LanguageLookup['sio'] = 'Siouan Languages'; + $LanguageLookup['sit'] = 'Sino-Tibetan (Other)'; + $LanguageLookup['sla'] = 'Slavic (Other)'; + $LanguageLookup['slk'] = 'Slovak'; + $LanguageLookup['slo'] = 'Slovak'; + $LanguageLookup['slv'] = 'Slovenian'; + $LanguageLookup['smi'] = 'Sami Languages'; + $LanguageLookup['smo'] = 'Samoan'; + $LanguageLookup['sna'] = 'Shona'; + $LanguageLookup['snd'] = 'Sindhi'; + $LanguageLookup['sog'] = 'Sogdian'; + $LanguageLookup['som'] = 'Somali'; + $LanguageLookup['son'] = 'Songhai'; + $LanguageLookup['sot'] = 'Sotho, Southern'; + $LanguageLookup['spa'] = 'Spanish'; + $LanguageLookup['sqi'] = 'Albanian'; + $LanguageLookup['srd'] = 'Sardinian'; + $LanguageLookup['srr'] = 'Serer'; + $LanguageLookup['ssa'] = 'Nilo-Saharan (Other)'; + $LanguageLookup['ssw'] = 'Siswant'; + $LanguageLookup['ssw'] = 'Swazi'; + $LanguageLookup['suk'] = 'Sukuma'; + $LanguageLookup['sun'] = 'Sudanese'; + $LanguageLookup['sus'] = 'Susu'; + $LanguageLookup['sux'] = 'Sumerian'; + $LanguageLookup['sve'] = 'Swedish'; + $LanguageLookup['swa'] = 'Swahili'; + $LanguageLookup['swe'] = 'Swedish'; + $LanguageLookup['syr'] = 'Syriac'; + $LanguageLookup['tah'] = 'Tahitian'; + $LanguageLookup['tam'] = 'Tamil'; + $LanguageLookup['tat'] = 'Tatar'; + $LanguageLookup['tel'] = 'Telugu'; + $LanguageLookup['tem'] = 'Timne'; + $LanguageLookup['ter'] = 'Tereno'; + $LanguageLookup['tgk'] = 'Tajik'; + $LanguageLookup['tgl'] = 'Tagalog'; + $LanguageLookup['tha'] = 'Thai'; + $LanguageLookup['tib'] = 'Tibetan'; + $LanguageLookup['tig'] = 'Tigre'; + $LanguageLookup['tir'] = 'Tigrinya'; + $LanguageLookup['tiv'] = 'Tivi'; + $LanguageLookup['tli'] = 'Tlingit'; + $LanguageLookup['tmh'] = 'Tamashek'; + $LanguageLookup['tog'] = 'Tonga (Nyasa)'; + $LanguageLookup['ton'] = 'Tonga (Tonga Islands)'; + $LanguageLookup['tru'] = 'Truk'; + $LanguageLookup['tsi'] = 'Tsimshian'; + $LanguageLookup['tsn'] = 'Tswana'; + $LanguageLookup['tso'] = 'Tsonga'; + $LanguageLookup['tuk'] = 'Turkmen'; + $LanguageLookup['tum'] = 'Tumbuka'; + $LanguageLookup['tur'] = 'Turkish'; + $LanguageLookup['tut'] = 'Altaic (Other)'; + $LanguageLookup['twi'] = 'Twi'; + $LanguageLookup['tyv'] = 'Tuvinian'; + $LanguageLookup['uga'] = 'Ugaritic'; + $LanguageLookup['uig'] = 'Uighur'; + $LanguageLookup['ukr'] = 'Ukrainian'; + $LanguageLookup['umb'] = 'Umbundu'; + $LanguageLookup['und'] = 'Undetermined'; + $LanguageLookup['urd'] = 'Urdu'; + $LanguageLookup['uzb'] = 'Uzbek'; + $LanguageLookup['vai'] = 'Vai'; + $LanguageLookup['ven'] = 'Venda'; + $LanguageLookup['vie'] = 'Vietnamese'; + $LanguageLookup['vol'] = 'Volapük'; + $LanguageLookup['vot'] = 'Votic'; + $LanguageLookup['wak'] = 'Wakashan Languages'; + $LanguageLookup['wal'] = 'Walamo'; + $LanguageLookup['war'] = 'Waray'; + $LanguageLookup['was'] = 'Washo'; + $LanguageLookup['wel'] = 'Welsh'; + $LanguageLookup['wen'] = 'Sorbian Languages'; + $LanguageLookup['wol'] = 'Wolof'; + $LanguageLookup['xho'] = 'Xhosa'; + $LanguageLookup['yao'] = 'Yao'; + $LanguageLookup['yap'] = 'Yap'; + $LanguageLookup['yid'] = 'Yiddish'; + $LanguageLookup['yor'] = 'Yoruba'; + $LanguageLookup['zap'] = 'Zapotec'; + $LanguageLookup['zen'] = 'Zenaga'; + $LanguageLookup['zha'] = 'Zhuang'; + $LanguageLookup['zho'] = 'Chinese'; + $LanguageLookup['zul'] = 'Zulu'; + $LanguageLookup['zun'] = 'Zuni'; + } + + return (isset($LanguageLookup["$languagecode"]) ? $LanguageLookup["$languagecode"] : ''); +} + +function ETCOEventLookup($index) { + static $EventLookup = array(); + if (empty($EventLookup)) { + $EventLookup[0x00] = 'padding (has no meaning)'; + $EventLookup[0x01] = 'end of initial silence'; + $EventLookup[0x02] = 'intro start'; + $EventLookup[0x03] = 'main part start'; + $EventLookup[0x04] = 'outro start'; + $EventLookup[0x05] = 'outro end'; + $EventLookup[0x06] = 'verse start'; + $EventLookup[0x07] = 'refrain start'; + $EventLookup[0x08] = 'interlude start'; + $EventLookup[0x09] = 'theme start'; + $EventLookup[0x0A] = 'variation start'; + $EventLookup[0x0B] = 'key change'; + $EventLookup[0x0C] = 'time change'; + $EventLookup[0x0D] = 'momentary unwanted noise (Snap, Crackle & Pop)'; + $EventLookup[0x0E] = 'sustained noise'; + $EventLookup[0x0F] = 'sustained noise end'; + $EventLookup[0x10] = 'intro end'; + $EventLookup[0x11] = 'main part end'; + $EventLookup[0x12] = 'verse end'; + $EventLookup[0x13] = 'refrain end'; + $EventLookup[0x14] = 'theme end'; + $EventLookup[0x15] = 'profanity'; + $EventLookup[0x16] = 'profanity end'; + for ($i = 0x17; $i <= 0xDF; $i++) { + $EventLookup[$i] = 'reserved for future use'; + } + for ($i = 0xE0; $i <= 0xEF; $i++) { + $EventLookup[$i] = 'not predefined synch 0-F'; + } + for ($i = 0xF0; $i <= 0xFC; $i++) { + $EventLookup[$i] = 'reserved for future use'; + } + $EventLookup[0xFD] = 'audio end (start of silence)'; + $EventLookup[0xFE] = 'audio file ends'; + $EventLookup[0xFF] = 'one more byte of events follows'; + } + + return (isset($EventLookup[$index]) ? $EventLookup[$index] : ''); +} + +function SYTLContentTypeLookup($index) { + static $SYTLContentTypeLookup = array(); + if (empty($SYTLContentTypeLookup)) { + $SYTLContentTypeLookup[0x00] = 'other'; + $SYTLContentTypeLookup[0x01] = 'lyrics'; + $SYTLContentTypeLookup[0x02] = 'text transcription'; + $SYTLContentTypeLookup[0x03] = 'movement/part name'; // (e.g. 'Adagio') + $SYTLContentTypeLookup[0x04] = 'events'; // (e.g. 'Don Quijote enters the stage') + $SYTLContentTypeLookup[0x05] = 'chord'; // (e.g. 'Bb F Fsus') + $SYTLContentTypeLookup[0x06] = 'trivia/\'pop up\' information'; + $SYTLContentTypeLookup[0x07] = 'URLs to webpages'; + $SYTLContentTypeLookup[0x08] = 'URLs to images'; + } + + return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : ''); +} + +function APICPictureTypeLookup($index) { + static $APICPictureTypeLookup = array(); + if (empty($APICPictureTypeLookup)) { + $APICPictureTypeLookup[0x00] = 'Other'; + $APICPictureTypeLookup[0x01] = '32x32 pixels \'file icon\' (PNG only)'; + $APICPictureTypeLookup[0x02] = 'Other file icon'; + $APICPictureTypeLookup[0x03] = 'Cover (front)'; + $APICPictureTypeLookup[0x04] = 'Cover (back)'; + $APICPictureTypeLookup[0x05] = 'Leaflet page'; + $APICPictureTypeLookup[0x06] = 'Media (e.g. label side of CD)'; + $APICPictureTypeLookup[0x07] = 'Lead artist/lead performer/soloist'; + $APICPictureTypeLookup[0x08] = 'Artist/performer'; + $APICPictureTypeLookup[0x09] = 'Conductor'; + $APICPictureTypeLookup[0x0A] = 'Band/Orchestra'; + $APICPictureTypeLookup[0x0B] = 'Composer'; + $APICPictureTypeLookup[0x0C] = 'Lyricist/text writer'; + $APICPictureTypeLookup[0x0D] = 'Recording Location'; + $APICPictureTypeLookup[0x0E] = 'During recording'; + $APICPictureTypeLookup[0x0F] = 'During performance'; + $APICPictureTypeLookup[0x10] = 'Movie/video screen capture'; + $APICPictureTypeLookup[0x11] = 'A bright coloured fish'; + $APICPictureTypeLookup[0x12] = 'Illustration'; + $APICPictureTypeLookup[0x13] = 'Band/artist logotype'; + $APICPictureTypeLookup[0x14] = 'Publisher/Studio logotype'; + } + + return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : ''); +} + +function COMRReceivedAsLookup($index) { + static $COMRReceivedAsLookup = array(); + if (empty($COMRReceivedAsLookup)) { + $COMRReceivedAsLookup[0x00] = 'Other'; + $COMRReceivedAsLookup[0x01] = 'Standard CD album with other songs'; + $COMRReceivedAsLookup[0x02] = 'Compressed audio on CD'; + $COMRReceivedAsLookup[0x03] = 'File over the Internet'; + $COMRReceivedAsLookup[0x04] = 'Stream over the Internet'; + $COMRReceivedAsLookup[0x05] = 'As note sheets'; + $COMRReceivedAsLookup[0x06] = 'As note sheets in a book with other sheets'; + $COMRReceivedAsLookup[0x07] = 'Music on other media'; + $COMRReceivedAsLookup[0x08] = 'Non-musical merchandise'; + } + + return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : ''); +} + +function RVA2ChannelTypeLookup($index) { + static $RVA2ChannelTypeLookup = array(); + if (empty($RVA2ChannelTypeLookup)) { + $RVA2ChannelTypeLookup[0x00] = 'Other'; + $RVA2ChannelTypeLookup[0x01] = 'Master volume'; + $RVA2ChannelTypeLookup[0x02] = 'Front right'; + $RVA2ChannelTypeLookup[0x03] = 'Front left'; + $RVA2ChannelTypeLookup[0x04] = 'Back right'; + $RVA2ChannelTypeLookup[0x05] = 'Back left'; + $RVA2ChannelTypeLookup[0x06] = 'Front centre'; + $RVA2ChannelTypeLookup[0x07] = 'Back centre'; + $RVA2ChannelTypeLookup[0x08] = 'Subwoofer'; + } + + return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : ''); +} + +function FrameNameLongLookup($framename) { + static $FrameNameLongLookup = array(); + if (empty($FrameNameLongLookup)) { + $FrameNameLongLookup['AENC'] = 'Audio encryption'; + $FrameNameLongLookup['APIC'] = 'Attached picture'; + $FrameNameLongLookup['ASPI'] = 'Audio seek point index'; + $FrameNameLongLookup['BUF'] = 'Recommended buffer size'; + $FrameNameLongLookup['CNT'] = 'Play counter'; + $FrameNameLongLookup['COM'] = 'Comments'; + $FrameNameLongLookup['COMM'] = 'Comments'; + $FrameNameLongLookup['COMR'] = 'Commercial frame'; + $FrameNameLongLookup['CRA'] = 'Audio encryption'; + $FrameNameLongLookup['CRM'] = 'Encrypted meta frame'; + $FrameNameLongLookup['ENCR'] = 'Encryption method registration'; + $FrameNameLongLookup['EQU'] = 'Equalization'; + $FrameNameLongLookup['EQU2'] = 'Equalisation (2)'; + $FrameNameLongLookup['EQUA'] = 'Equalization'; + $FrameNameLongLookup['ETC'] = 'Event timing codes'; + $FrameNameLongLookup['ETCO'] = 'Event timing codes'; + $FrameNameLongLookup['GEO'] = 'General encapsulated object'; + $FrameNameLongLookup['GEOB'] = 'General encapsulated object'; + $FrameNameLongLookup['GRID'] = 'Group identification registration'; + $FrameNameLongLookup['IPL'] = 'Involved people list'; + $FrameNameLongLookup['IPLS'] = 'Involved people list'; + $FrameNameLongLookup['LINK'] = 'Linked information'; + $FrameNameLongLookup['LNK'] = 'Linked information'; + $FrameNameLongLookup['MCDI'] = 'Music CD identifier'; + $FrameNameLongLookup['MCI'] = 'Music CD Identifier'; + $FrameNameLongLookup['MLL'] = 'MPEG location lookup table'; + $FrameNameLongLookup['MLLT'] = 'MPEG location lookup table'; + $FrameNameLongLookup['OWNE'] = 'Ownership frame'; + $FrameNameLongLookup['PCNT'] = 'Play counter'; + $FrameNameLongLookup['PIC'] = 'Attached picture'; + $FrameNameLongLookup['POP'] = 'Popularimeter'; + $FrameNameLongLookup['POPM'] = 'Popularimeter'; + $FrameNameLongLookup['POSS'] = 'Position synchronisation frame'; + $FrameNameLongLookup['PRIV'] = 'Private frame'; + $FrameNameLongLookup['RBUF'] = 'Recommended buffer size'; + $FrameNameLongLookup['REV'] = 'Reverb'; + $FrameNameLongLookup['RVA'] = 'Relative volume adjustment'; + $FrameNameLongLookup['RVA2'] = 'Relative volume adjustment (2)'; + $FrameNameLongLookup['RVAD'] = 'Relative volume adjustment'; + $FrameNameLongLookup['RVRB'] = 'Reverb'; + $FrameNameLongLookup['SEEK'] = 'Seek frame'; + $FrameNameLongLookup['SIGN'] = 'Signature frame'; + $FrameNameLongLookup['SLT'] = 'Synchronized lyric/text'; + $FrameNameLongLookup['STC'] = 'Synced tempo codes'; + $FrameNameLongLookup['SYLT'] = 'Synchronised lyric/text'; + $FrameNameLongLookup['SYTC'] = 'Synchronised tempo codes'; + $FrameNameLongLookup['TAL'] = 'Album/Movie/Show title'; + $FrameNameLongLookup['TALB'] = 'Album/Movie/Show title'; + $FrameNameLongLookup['TBP'] = 'BPM (Beats Per Minute)'; + $FrameNameLongLookup['TBPM'] = 'BPM (beats per minute)'; + $FrameNameLongLookup['TCM'] = 'Composer'; + $FrameNameLongLookup['TCO'] = 'Content type'; + $FrameNameLongLookup['TCOM'] = 'Composer'; + $FrameNameLongLookup['TCON'] = 'Content type'; + $FrameNameLongLookup['TCOP'] = 'Copyright message'; + $FrameNameLongLookup['TCR'] = 'Copyright message'; + $FrameNameLongLookup['TDA'] = 'Date'; + $FrameNameLongLookup['TDAT'] = 'Date'; + $FrameNameLongLookup['TDEN'] = 'Encoding time'; + $FrameNameLongLookup['TDLY'] = 'Playlist delay'; + $FrameNameLongLookup['TDOR'] = 'Original release time'; + $FrameNameLongLookup['TDRC'] = 'Recording time'; + $FrameNameLongLookup['TDRL'] = 'Release time'; + $FrameNameLongLookup['TDTG'] = 'Tagging time'; + $FrameNameLongLookup['TDY'] = 'Playlist delay'; + $FrameNameLongLookup['TEN'] = 'Encoded by'; + $FrameNameLongLookup['TENC'] = 'Encoded by'; + $FrameNameLongLookup['TEXT'] = 'Lyricist/Text writer'; + $FrameNameLongLookup['TFLT'] = 'File type'; + $FrameNameLongLookup['TFT'] = 'File type'; + $FrameNameLongLookup['TIM'] = 'Time'; + $FrameNameLongLookup['TIME'] = 'Time'; + $FrameNameLongLookup['TIPL'] = 'Involved people list'; + $FrameNameLongLookup['TIT1'] = 'Content group description'; + $FrameNameLongLookup['TIT2'] = 'Title/songname/content description'; + $FrameNameLongLookup['TIT3'] = 'Subtitle/Description refinement'; + $FrameNameLongLookup['TKE'] = 'Initial key'; + $FrameNameLongLookup['TKEY'] = 'Initial key'; + $FrameNameLongLookup['TLA'] = 'Language(s)'; + $FrameNameLongLookup['TLAN'] = 'Language(s)'; + $FrameNameLongLookup['TLE'] = 'Length'; + $FrameNameLongLookup['TLEN'] = 'Length'; + $FrameNameLongLookup['TMCL'] = 'Musician credits list'; + $FrameNameLongLookup['TMED'] = 'Media type'; + $FrameNameLongLookup['TMOO'] = 'Mood'; + $FrameNameLongLookup['TMT'] = 'Media type'; + $FrameNameLongLookup['TOA'] = 'Original artist(s)/performer(s)'; + $FrameNameLongLookup['TOAL'] = 'Original album/movie/show title'; + $FrameNameLongLookup['TOF'] = 'Original filename'; + $FrameNameLongLookup['TOFN'] = 'Original filename'; + $FrameNameLongLookup['TOL'] = 'Original Lyricist(s)/text writer(s)'; + $FrameNameLongLookup['TOLY'] = 'Original lyricist(s)/text writer(s)'; + $FrameNameLongLookup['TOPE'] = 'Original artist(s)/performer(s)'; + $FrameNameLongLookup['TOR'] = 'Original release year'; + $FrameNameLongLookup['TORY'] = 'Original release year'; + $FrameNameLongLookup['TOT'] = 'Original album/Movie/Show title'; + $FrameNameLongLookup['TOWN'] = 'File owner/licensee'; + $FrameNameLongLookup['TP1'] = 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group'; + $FrameNameLongLookup['TP2'] = 'Band/Orchestra/Accompaniment'; + $FrameNameLongLookup['TP3'] = 'Conductor/Performer refinement'; + $FrameNameLongLookup['TP4'] = 'Interpreted, remixed, or otherwise modified by'; + $FrameNameLongLookup['TPA'] = 'Part of a set'; + $FrameNameLongLookup['TPB'] = 'Publisher'; + $FrameNameLongLookup['TPE1'] = 'Lead performer(s)/Soloist(s)'; + $FrameNameLongLookup['TPE2'] = 'Band/orchestra/accompaniment'; + $FrameNameLongLookup['TPE3'] = 'Conductor/performer refinement'; + $FrameNameLongLookup['TPE4'] = 'Interpreted, remixed, or otherwise modified by'; + $FrameNameLongLookup['TPOS'] = 'Part of a set'; + $FrameNameLongLookup['TPRO'] = 'Produced notice'; + $FrameNameLongLookup['TPUB'] = 'Publisher'; + $FrameNameLongLookup['TRC'] = 'ISRC (International Standard Recording Code)'; + $FrameNameLongLookup['TRCK'] = 'Track number/Position in set'; + $FrameNameLongLookup['TRD'] = 'Recording dates'; + $FrameNameLongLookup['TRDA'] = 'Recording dates'; + $FrameNameLongLookup['TRK'] = 'Track number/Position in set'; + $FrameNameLongLookup['TRSN'] = 'Internet radio station name'; + $FrameNameLongLookup['TRSO'] = 'Internet radio station owner'; + $FrameNameLongLookup['TSI'] = 'Size'; + $FrameNameLongLookup['TSIZ'] = 'Size'; + $FrameNameLongLookup['TSOA'] = 'Album sort order'; + $FrameNameLongLookup['TSOP'] = 'Performer sort order'; + $FrameNameLongLookup['TSOT'] = 'Title sort order'; + $FrameNameLongLookup['TSRC'] = 'ISRC (international standard recording code)'; + $FrameNameLongLookup['TSS'] = 'Software/hardware and settings used for encoding'; + $FrameNameLongLookup['TSSE'] = 'Software/Hardware and settings used for encoding'; + $FrameNameLongLookup['TSST'] = 'Set subtitle'; + $FrameNameLongLookup['TT1'] = 'Content group description'; + $FrameNameLongLookup['TT2'] = 'Title/Songname/Content description'; + $FrameNameLongLookup['TT3'] = 'Subtitle/Description refinement'; + $FrameNameLongLookup['TXT'] = 'Lyricist/text writer'; + $FrameNameLongLookup['TXX'] = 'User defined text information frame'; + $FrameNameLongLookup['TXXX'] = 'User defined text information frame'; + $FrameNameLongLookup['TYE'] = 'Year'; + $FrameNameLongLookup['TYER'] = 'Year'; + $FrameNameLongLookup['UFI'] = 'Unique file identifier'; + $FrameNameLongLookup['UFID'] = 'Unique file identifier'; + $FrameNameLongLookup['ULT'] = 'Unsychronized lyric/text transcription'; + $FrameNameLongLookup['USER'] = 'Terms of use'; + $FrameNameLongLookup['USLT'] = 'Unsynchronised lyric/text transcription'; + $FrameNameLongLookup['WAF'] = 'Official audio file webpage'; + $FrameNameLongLookup['WAR'] = 'Official artist/performer webpage'; + $FrameNameLongLookup['WAS'] = 'Official audio source webpage'; + $FrameNameLongLookup['WCM'] = 'Commercial information'; + $FrameNameLongLookup['WCOM'] = 'Commercial information'; + $FrameNameLongLookup['WCOP'] = 'Copyright/Legal information'; + $FrameNameLongLookup['WCP'] = 'Copyright/Legal information'; + $FrameNameLongLookup['WOAF'] = 'Official audio file webpage'; + $FrameNameLongLookup['WOAR'] = 'Official artist/performer webpage'; + $FrameNameLongLookup['WOAS'] = 'Official audio source webpage'; + $FrameNameLongLookup['WORS'] = 'Official Internet radio station homepage'; + $FrameNameLongLookup['WPAY'] = 'Payment'; + $FrameNameLongLookup['WPB'] = 'Publishers official webpage'; + $FrameNameLongLookup['WPUB'] = 'Publishers official webpage'; + $FrameNameLongLookup['WXX'] = 'User defined URL link frame'; + $FrameNameLongLookup['WXXX'] = 'User defined URL link frame'; + + $FrameNameLongLookup['TFEA'] = 'Featured Artist'; // from Helium2 [www.helium2.com] + $FrameNameLongLookup['TSTU'] = 'Recording Studio'; // from Helium2 [www.helium2.com] + $FrameNameLongLookup['rgad'] = 'Replay Gain Adjustment'; // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html + } + + return (isset($FrameNameLongLookup["$framename"]) ? $FrameNameLongLookup["$framename"] : ''); +} + +function FrameNameShortLookup($framename) { + static $FrameNameShortLookup = array(); + if (empty($FrameNameShortLookup)) { + $FrameNameShortLookup['COM'] = 'comments'; + $FrameNameShortLookup['COMM'] = 'comments'; + $FrameNameShortLookup['TAL'] = 'album'; + $FrameNameShortLookup['TALB'] = 'album'; + $FrameNameShortLookup['TBP'] = 'bpm'; + $FrameNameShortLookup['TBPM'] = 'bpm'; + $FrameNameShortLookup['TCM'] = 'composer'; + $FrameNameShortLookup['TCO'] = 'genre'; + $FrameNameShortLookup['TCOM'] = 'composer'; + $FrameNameShortLookup['TCON'] = 'genre'; + $FrameNameShortLookup['TCOP'] = 'copyright'; + $FrameNameShortLookup['TCR'] = 'copyright'; + $FrameNameShortLookup['TEN'] = 'encoded_by'; + $FrameNameShortLookup['TENC'] = 'encoded_by'; + $FrameNameShortLookup['TEXT'] = 'lyricist'; + $FrameNameShortLookup['TIT1'] = 'description'; + $FrameNameShortLookup['TIT2'] = 'title'; + $FrameNameShortLookup['TIT3'] = 'subtitle'; + $FrameNameShortLookup['TLA'] = 'language'; + $FrameNameShortLookup['TLAN'] = 'language'; + $FrameNameShortLookup['TLE'] = 'length'; + $FrameNameShortLookup['TLEN'] = 'length'; + $FrameNameShortLookup['TMOO'] = 'mood'; + $FrameNameShortLookup['TOA'] = 'original_artist'; + $FrameNameShortLookup['TOAL'] = 'original_album'; + $FrameNameShortLookup['TOF'] = 'original_filename'; + $FrameNameShortLookup['TOFN'] = 'original_filename'; + $FrameNameShortLookup['TOL'] = 'original_lyricist'; + $FrameNameShortLookup['TOLY'] = 'original_lyricist'; + $FrameNameShortLookup['TOPE'] = 'original_artist'; + $FrameNameShortLookup['TOT'] = 'original_album'; + $FrameNameShortLookup['TP1'] = 'artist'; + $FrameNameShortLookup['TP2'] = 'band'; + $FrameNameShortLookup['TP3'] = 'conductor'; + $FrameNameShortLookup['TP4'] = 'remixer'; + $FrameNameShortLookup['TPB'] = 'publisher'; + $FrameNameShortLookup['TPE1'] = 'artist'; + $FrameNameShortLookup['TPE2'] = 'band'; + $FrameNameShortLookup['TPE3'] = 'conductor'; + $FrameNameShortLookup['TPE4'] = 'remixer'; + $FrameNameShortLookup['TPUB'] = 'publisher'; + $FrameNameShortLookup['TRC'] = 'isrc'; + $FrameNameShortLookup['TRCK'] = 'track'; + $FrameNameShortLookup['TRK'] = 'track'; + $FrameNameShortLookup['TSI'] = 'size'; + $FrameNameShortLookup['TSIZ'] = 'size'; + $FrameNameShortLookup['TSRC'] = 'isrc'; + $FrameNameShortLookup['TSS'] = 'encoder_settings'; + $FrameNameShortLookup['TSSE'] = 'encoder_settings'; + $FrameNameShortLookup['TSST'] = 'subtitle'; + $FrameNameShortLookup['TT1'] = 'description'; + $FrameNameShortLookup['TT2'] = 'title'; + $FrameNameShortLookup['TT3'] = 'subtitle'; + $FrameNameShortLookup['TXT'] = 'lyricist'; + $FrameNameShortLookup['TXX'] = 'text'; + $FrameNameShortLookup['TXXX'] = 'text'; + $FrameNameShortLookup['TYE'] = 'year'; + $FrameNameShortLookup['TYER'] = 'year'; + $FrameNameShortLookup['UFI'] = 'unique_file_identifier'; + $FrameNameShortLookup['UFID'] = 'unique_file_identifier'; + $FrameNameShortLookup['ULT'] = 'unsychronized_lyric'; + $FrameNameShortLookup['USER'] = 'terms_of_use'; + $FrameNameShortLookup['USLT'] = 'unsynchronised lyric'; + $FrameNameShortLookup['WAF'] = 'url_file'; + $FrameNameShortLookup['WAR'] = 'url_artist'; + $FrameNameShortLookup['WAS'] = 'url_source'; + $FrameNameShortLookup['WCOP'] = 'copyright'; + $FrameNameShortLookup['WCP'] = 'copyright'; + $FrameNameShortLookup['WOAF'] = 'url_file'; + $FrameNameShortLookup['WOAR'] = 'url_artist'; + $FrameNameShortLookup['WOAS'] = 'url_souce'; + $FrameNameShortLookup['WORS'] = 'url_station'; + $FrameNameShortLookup['WPB'] = 'url_publisher'; + $FrameNameShortLookup['WPUB'] = 'url_publisher'; + $FrameNameShortLookup['WXX'] = 'url_user'; + $FrameNameShortLookup['WXXX'] = 'url_user'; + + $FrameNameShortLookup['TFEA'] = 'featured_artist'; + $FrameNameShortLookup['TSTU'] = 'studio'; + } + + return (isset($FrameNameShortLookup["$framename"]) ? $FrameNameShortLookup["$framename"] : ''); +} + +function TextEncodingLookup($type, $encoding) { + // http://www.id3.org/id3v2.4.0-structure.txt + // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings: + // $00 ISO-8859-1. Terminated with $00. + // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00. + // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00. + // $03 UTF-8 encoded Unicode. Terminated with $00. + + $TextEncodingLookup['encoding'] = array('ISO-8859-1', 'UTF-16', 'UTF-16BE', 'UTF-8'); + $TextEncodingLookup['terminator'] = array(chr(0), chr(0).chr(0), chr(0).chr(0), chr(0)); + + return (isset($TextEncodingLookup["$type"][$encoding]) ? $TextEncodingLookup["$type"][$encoding] : ''); +} + +function TextEncodingVerified($text_encoding, &$ThisFileInfo, $frame_name) { + switch ($text_encoding) { + case 0: + case 1: + case 2: + case 3: + return $text_encoding; + break; + + default: + $ThisFileInfo['warning'] .= "\n".'Invalid text encoding byte ('.$text_encoding.') in frame "'.$frame_name.'", defaulting to ASCII encoding'; + return 0; + break; + } +} + +function IsValidID3v2FrameName($framename, $id3v2majorversion) { + switch ($id3v2majorversion) { + case 2: + return ereg('[A-Z][A-Z0-9]{2}', $framename); + break; + + case 3: + case 4: + return ereg('[A-Z][A-Z0-9]{3}', $framename); + break; + } + return false; +} + +function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) { + for ($i = 0; $i < strlen($numberstring); $i++) { + if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) { + if (($numberstring{$i} == '.') && $allowdecimal) { + // allowed + } elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) { + // allowed + } else { + return false; + } + } + } + return true; +} + +function IsValidDateStampString($datestamp) { + if (strlen($datestamp) != 8) { + return false; + } + if (!IsANumber($datestamp, false)) { + return false; + } + $year = substr($datestamp, 0, 4); + $month = substr($datestamp, 4, 2); + $day = substr($datestamp, 6, 2); + if (($year == 0) || ($month == 0) || ($day == 0)) { + return false; + } + if ($month > 12) { + return false; + } + if ($day > 31) { + return false; + } + if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) { + return false; + } + if (($day > 29) && ($month == 2)) { + return false; + } + return true; +} + +function ID3v2HeaderLength($majorversion) { + if ($majorversion == 2) { + return 6; + } else { + return 10; + } +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.iso.php b/livesupport/modules/getid3/var/getid3.iso.php new file mode 100644 index 000000000..51daccc77 --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.iso.php @@ -0,0 +1,343 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.iso.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function getISOHeaderFilepointer($fd, &$ThisFileInfo) { + $ThisFileInfo['fileformat'] = 'iso'; + + for ($i = 16; $i <= 19; $i++) { + fseek($fd, 2048 * $i, SEEK_SET); + $ISOheader = fread($fd, 2048); + if (substr($ISOheader, 1, 5) == 'CD001') { + switch (ord($ISOheader{0})) { + case 1: + $ThisFileInfo['iso']['primary_volume_descriptor']['offset'] = 2048 * $i; + ParsePrimaryVolumeDescriptor($ISOheader, $ThisFileInfo); + break; + + case 2: + $ThisFileInfo['iso']['supplementary_volume_descriptor']['offset'] = 2048 * $i; + ParseSupplementaryVolumeDescriptor($ISOheader, $ThisFileInfo); + break; + + default: + // skip + break; + } + } + } + + ParsePathTable($fd, $ThisFileInfo); + + $ThisFileInfo['iso']['files'] = array(); + foreach ($ThisFileInfo['iso']['path_table']['directories'] as $directorynum => $directorydata) { + + $ThisFileInfo['iso']['directories'][$directorynum] = ParseDirectoryRecord($fd, $directorydata, $ThisFileInfo); + + } + + return true; + +} + + +function ParsePrimaryVolumeDescriptor(&$ISOheader, &$ThisFileInfo) { + // ISO integer values are stored *BOTH* Little-Endian AND Big-Endian format!! + // ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field + + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_descriptor_type'] = LittleEndian2Int(substr($ISOheader, 0, 1)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['standard_identifier'] = substr($ISOheader, 1, 5); + if ($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['standard_identifier'] != 'CD001') { + $ThisFileInfo['error'] .= "\n".'Expected "CD001" at offset ('.($ThisFileInfo['iso']['primary_volume_descriptor']['offset'] + 1).'), found "'.$ThisFileInfo['iso']['primary_volume_descriptor']['raw']['standard_identifier'].'" instead'; + return false; + } + + + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_descriptor_version'] = LittleEndian2Int(substr($ISOheader, 6, 1)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['unused_1'] = substr($ISOheader, 7, 1); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['system_identifier'] = substr($ISOheader, 8, 32); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_identifier'] = substr($ISOheader, 40, 32); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['unused_2'] = substr($ISOheader, 72, 8); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_space_size'] = LittleEndian2Int(substr($ISOheader, 80, 4)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['unused_3'] = substr($ISOheader, 88, 32); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_set_size'] = LittleEndian2Int(substr($ISOheader, 120, 2)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_sequence_number'] = LittleEndian2Int(substr($ISOheader, 124, 2)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['logical_block_size'] = LittleEndian2Int(substr($ISOheader, 128, 2)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_size'] = LittleEndian2Int(substr($ISOheader, 132, 4)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_l_location'] = LittleEndian2Int(substr($ISOheader, 140, 2)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_l_opt_location'] = LittleEndian2Int(substr($ISOheader, 144, 2)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_m_location'] = LittleEndian2Int(substr($ISOheader, 148, 2)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_m_opt_location'] = LittleEndian2Int(substr($ISOheader, 152, 2)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['root_directory_record'] = substr($ISOheader, 156, 34); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_set_identifier'] = substr($ISOheader, 190, 128); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['publisher_identifier'] = substr($ISOheader, 318, 128); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['data_preparer_identifier'] = substr($ISOheader, 446, 128); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['application_identifier'] = substr($ISOheader, 574, 128); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['copyright_file_identifier'] = substr($ISOheader, 702, 37); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['abstract_file_identifier'] = substr($ISOheader, 739, 37); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['bibliographic_file_identifier'] = substr($ISOheader, 776, 37); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_creation_date_time'] = substr($ISOheader, 813, 17); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_modification_date_time'] = substr($ISOheader, 830, 17); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_expiration_date_time'] = substr($ISOheader, 847, 17); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_effective_date_time'] = substr($ISOheader, 864, 17); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['file_structure_version'] = LittleEndian2Int(substr($ISOheader, 881, 1)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['unused_4'] = LittleEndian2Int(substr($ISOheader, 882, 1)); + $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['application_data'] = substr($ISOheader, 883, 512); + //$ThisFileInfo['iso']['primary_volume_descriptor']['raw']['unused_5'] = substr($ISOheader, 1395, 653); + + $ThisFileInfo['iso']['primary_volume_descriptor']['system_identifier'] = trim($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['system_identifier']); + $ThisFileInfo['iso']['primary_volume_descriptor']['volume_identifier'] = trim($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_identifier']); + $ThisFileInfo['iso']['primary_volume_descriptor']['volume_set_identifier'] = trim($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_set_identifier']); + $ThisFileInfo['iso']['primary_volume_descriptor']['publisher_identifier'] = trim($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['publisher_identifier']); + $ThisFileInfo['iso']['primary_volume_descriptor']['data_preparer_identifier'] = trim($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['data_preparer_identifier']); + $ThisFileInfo['iso']['primary_volume_descriptor']['application_identifier'] = trim($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['application_identifier']); + $ThisFileInfo['iso']['primary_volume_descriptor']['copyright_file_identifier'] = trim($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['copyright_file_identifier']); + $ThisFileInfo['iso']['primary_volume_descriptor']['abstract_file_identifier'] = trim($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['abstract_file_identifier']); + $ThisFileInfo['iso']['primary_volume_descriptor']['bibliographic_file_identifier'] = trim($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['bibliographic_file_identifier']); + $ThisFileInfo['iso']['primary_volume_descriptor']['volume_creation_date_time'] = ISOtimeText2UNIXtime($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_creation_date_time']); + $ThisFileInfo['iso']['primary_volume_descriptor']['volume_modification_date_time'] = ISOtimeText2UNIXtime($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_modification_date_time']); + $ThisFileInfo['iso']['primary_volume_descriptor']['volume_expiration_date_time'] = ISOtimeText2UNIXtime($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_expiration_date_time']); + $ThisFileInfo['iso']['primary_volume_descriptor']['volume_effective_date_time'] = ISOtimeText2UNIXtime($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_effective_date_time']); + + if (($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_space_size'] * 2048) > $ThisFileInfo['filesize']) { + $ThisFileInfo['error'] .= "\n".'Volume Space Size ('.($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['volume_space_size'] * 2048).' bytes) is larger than the file size ('.$ThisFileInfo['filesize'].' bytes) (truncated file?)'; + } + + return true; +} + + +function ParseSupplementaryVolumeDescriptor(&$ISOheader, &$ThisFileInfo) { + // ISO integer values are stored Both-Endian format!! + // ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field + + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_descriptor_type'] = LittleEndian2Int(substr($ISOheader, 0, 1)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['standard_identifier'] = substr($ISOheader, 1, 5); + if ($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['standard_identifier'] != 'CD001') { + $ThisFileInfo['error'] .= "\n".'Expected "CD001" at offset ('.($ThisFileInfo['iso']['supplementary_volume_descriptor']['offset'] + 1).'), found "'.$ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['standard_identifier'].'" instead'; + return false; + } + + + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_descriptor_version'] = LittleEndian2Int(substr($ISOheader, 6, 1)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['unused_1'] = substr($ISOheader, 7, 1); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['system_identifier'] = substr($ISOheader, 8, 32); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_identifier'] = substr($ISOheader, 40, 32); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['unused_2'] = substr($ISOheader, 72, 8); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_space_size'] = LittleEndian2Int(substr($ISOheader, 80, 4)); + if ($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_space_size'] == 0) { + // Supplementary Volume Descriptor not used +// unset($ThisFileInfo['iso']['supplementary_volume_descriptor']); +// return false; + } + + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['unused_3'] = substr($ISOheader, 88, 32); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_set_size'] = LittleEndian2Int(substr($ISOheader, 120, 2)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_sequence_number'] = LittleEndian2Int(substr($ISOheader, 124, 2)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['logical_block_size'] = LittleEndian2Int(substr($ISOheader, 128, 2)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_size'] = LittleEndian2Int(substr($ISOheader, 132, 4)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location'] = LittleEndian2Int(substr($ISOheader, 140, 2)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_l_opt_location'] = LittleEndian2Int(substr($ISOheader, 144, 2)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_m_location'] = LittleEndian2Int(substr($ISOheader, 148, 2)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_m_opt_location'] = LittleEndian2Int(substr($ISOheader, 152, 2)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['root_directory_record'] = substr($ISOheader, 156, 34); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_set_identifier'] = substr($ISOheader, 190, 128); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['publisher_identifier'] = substr($ISOheader, 318, 128); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['data_preparer_identifier'] = substr($ISOheader, 446, 128); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['application_identifier'] = substr($ISOheader, 574, 128); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['copyright_file_identifier'] = substr($ISOheader, 702, 37); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['abstract_file_identifier'] = substr($ISOheader, 739, 37); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['bibliographic_file_identifier'] = substr($ISOheader, 776, 37); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_creation_date_time'] = substr($ISOheader, 813, 17); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_modification_date_time'] = substr($ISOheader, 830, 17); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_expiration_date_time'] = substr($ISOheader, 847, 17); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_effective_date_time'] = substr($ISOheader, 864, 17); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['file_structure_version'] = LittleEndian2Int(substr($ISOheader, 881, 1)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['unused_4'] = LittleEndian2Int(substr($ISOheader, 882, 1)); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['application_data'] = substr($ISOheader, 883, 512); + //$ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['unused_5'] = substr($ISOheader, 1395, 653); + + $ThisFileInfo['iso']['supplementary_volume_descriptor']['system_identifier'] = trim($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['system_identifier']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['volume_identifier'] = trim($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_identifier']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['volume_set_identifier'] = trim($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_set_identifier']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['publisher_identifier'] = trim($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['publisher_identifier']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['data_preparer_identifier'] = trim($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['data_preparer_identifier']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['application_identifier'] = trim($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['application_identifier']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['copyright_file_identifier'] = trim($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['copyright_file_identifier']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['abstract_file_identifier'] = trim($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['abstract_file_identifier']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['bibliographic_file_identifier'] = trim($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['bibliographic_file_identifier']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['volume_creation_date_time'] = ISOtimeText2UNIXtime($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_creation_date_time']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['volume_modification_date_time'] = ISOtimeText2UNIXtime($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_modification_date_time']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['volume_expiration_date_time'] = ISOtimeText2UNIXtime($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_expiration_date_time']); + $ThisFileInfo['iso']['supplementary_volume_descriptor']['volume_effective_date_time'] = ISOtimeText2UNIXtime($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_effective_date_time']); + + if (($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_space_size'] * $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['logical_block_size']) > $ThisFileInfo['filesize']) { + $ThisFileInfo['error'] .= "\n".'Volume Space Size ('.($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['volume_space_size'] * $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['logical_block_size']).' bytes) is larger than the file size ('.$ThisFileInfo['filesize'].' bytes) (truncated file?)'; + } + + return true; +} + + +function ParsePathTable($fd, &$ThisFileInfo) { + if (!isset($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location']) && !isset($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_l_location'])) { + return false; + } + if (isset($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location'])) { + $PathTableLocation = $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location']; + $PathTableSize = $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_size']; + $TextEncoding = 255; // Big-Endian Unicode + } else { + $PathTableLocation = $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_l_location']; + $PathTableSize = $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_size']; + $TextEncoding = 0; // ASCII + } + + if (($PathTableLocation * 2048) > $ThisFileInfo['filesize']) { + $ThisFileInfo['error'] .= "\n".'Path Table Location specifies an offset ('.($PathTableLocation * 2048).') beyond the end-of-file ('.$ThisFileInfo['filesize'].')'; + return false; + } + + $ThisFileInfo['iso']['path_table']['offset'] = $PathTableLocation * 2048; + fseek($fd, $ThisFileInfo['iso']['path_table']['offset'], SEEK_SET); + $ThisFileInfo['iso']['path_table']['raw'] = fread($fd, $PathTableSize); + + $offset = 0; + $pathcounter = 1; + while ($offset < $PathTableSize) { + $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['length'] = LittleEndian2Int(substr($ThisFileInfo['iso']['path_table']['raw'], $offset, 1)); + $offset += 1; + $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['extended_length'] = LittleEndian2Int(substr($ThisFileInfo['iso']['path_table']['raw'], $offset, 1)); + $offset += 1; + $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['location_logical'] = LittleEndian2Int(substr($ThisFileInfo['iso']['path_table']['raw'], $offset, 4)); + $offset += 4; + $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['parent_directory'] = LittleEndian2Int(substr($ThisFileInfo['iso']['path_table']['raw'], $offset, 2)); + $offset += 2; + $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['name'] = substr($ThisFileInfo['iso']['path_table']['raw'], $offset, $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['length']); + $offset += $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['length'] + ($ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['length'] % 2); + + $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['name_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['name'], $TextEncoding); + + $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['location_bytes'] = $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['location_logical'] * 2048; + if ($pathcounter == 1) { + $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['full_path'] = '/'; + } else { + $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['full_path'] = $ThisFileInfo['iso']['path_table']['directories'][$ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['parent_directory']]['full_path'].$ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['name_ascii'].'/'; + } + $FullPathArray[] = $ThisFileInfo['iso']['path_table']['directories'][$pathcounter]['full_path']; + + $pathcounter++; + + } + + return true; +} + + +function ParseDirectoryRecord(&$fd, $directorydata, &$ThisFileInfo) { + if (isset($ThisFileInfo['iso']['supplementary_volume_descriptor'])) { + $TextEncoding = 255; // Big-Endian Unicode + } else { + $TextEncoding = 0; // ASCII + } + + + fseek($fd, $directorydata['location_bytes'], SEEK_SET); + $DirectoryRecordData = fread($fd, 1); + + while (ord($DirectoryRecordData{0}) > 33) { + + $DirectoryRecordData .= fread($fd, ord($DirectoryRecordData{0}) - 1); + + $ThisDirectoryRecord['raw']['length'] = LittleEndian2Int(substr($DirectoryRecordData, 0, 1)); + $ThisDirectoryRecord['raw']['extended_attribute_length'] = LittleEndian2Int(substr($DirectoryRecordData, 1, 1)); + $ThisDirectoryRecord['raw']['offset_logical'] = LittleEndian2Int(substr($DirectoryRecordData, 2, 4)); + $ThisDirectoryRecord['raw']['filesize'] = LittleEndian2Int(substr($DirectoryRecordData, 10, 4)); + $ThisDirectoryRecord['raw']['recording_date_time'] = substr($DirectoryRecordData, 18, 7); + $ThisDirectoryRecord['raw']['file_flags'] = LittleEndian2Int(substr($DirectoryRecordData, 25, 1)); + $ThisDirectoryRecord['raw']['file_unit_size'] = LittleEndian2Int(substr($DirectoryRecordData, 26, 1)); + $ThisDirectoryRecord['raw']['interleave_gap_size'] = LittleEndian2Int(substr($DirectoryRecordData, 27, 1)); + $ThisDirectoryRecord['raw']['volume_sequence_number'] = LittleEndian2Int(substr($DirectoryRecordData, 28, 2)); + $ThisDirectoryRecord['raw']['file_identifier_length'] = LittleEndian2Int(substr($DirectoryRecordData, 32, 1)); + $ThisDirectoryRecord['raw']['file_identifier'] = substr($DirectoryRecordData, 33, $ThisDirectoryRecord['raw']['file_identifier_length']); + + $ThisDirectoryRecord['file_identifier_ascii'] = RoughTranslateUnicodeToASCII($ThisDirectoryRecord['raw']['file_identifier'], $TextEncoding); + + $ThisDirectoryRecord['filesize'] = $ThisDirectoryRecord['raw']['filesize']; + $ThisDirectoryRecord['offset_bytes'] = $ThisDirectoryRecord['raw']['offset_logical'] * 2048; + $ThisDirectoryRecord['file_flags']['hidden'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x01); + $ThisDirectoryRecord['file_flags']['directory'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x02); + $ThisDirectoryRecord['file_flags']['associated'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x04); + $ThisDirectoryRecord['file_flags']['extended'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x08); + $ThisDirectoryRecord['file_flags']['permissions'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x10); + $ThisDirectoryRecord['file_flags']['multiple'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x80); + $ThisDirectoryRecord['recording_timestamp'] = ISOtime2UNIXtime($ThisDirectoryRecord['raw']['recording_date_time']); + + if ($ThisDirectoryRecord['file_flags']['directory']) { + $ThisDirectoryRecord['filename'] = $directorydata['full_path']; + } else { + $ThisDirectoryRecord['filename'] = $directorydata['full_path'].ISOstripFilenameVersion($ThisDirectoryRecord['file_identifier_ascii']); + $ThisFileInfo['iso']['files'] = array_merge_clobber($ThisFileInfo['iso']['files'], CreateDeepArray($ThisDirectoryRecord['filename'], '/', $ThisDirectoryRecord['filesize'])); + } + + $DirectoryRecord[] = $ThisDirectoryRecord; + $DirectoryRecordData = fread($fd, 1); + } + + return $DirectoryRecord; +} + +function ISOstripFilenameVersion($ISOfilename) { + // convert 'filename.ext;1' to 'filename.ext' + if (!strstr($ISOfilename, ';')) { + return $ISOfilename; + } else { + return substr($ISOfilename, 0, strpos($ISOfilename, ';')); + } +} + +function ISOtimeText2UNIXtime($ISOtime) { + + $UNIXyear = (int) substr($ISOtime, 0, 4); + $UNIXmonth = (int) substr($ISOtime, 4, 2); + $UNIXday = (int) substr($ISOtime, 6, 2); + $UNIXhour = (int) substr($ISOtime, 8, 2); + $UNIXminute = (int) substr($ISOtime, 10, 2); + $UNIXsecond = (int) substr($ISOtime, 12, 2); + + if (!$UNIXyear) { + return false; + } + return mktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear); +} + +function ISOtime2UNIXtime($ISOtime) { + // Represented by seven bytes: + // 1: Number of years since 1900 + // 2: Month of the year from 1 to 12 + // 3: Day of the Month from 1 to 31 + // 4: Hour of the day from 0 to 23 + // 5: Minute of the hour from 0 to 59 + // 6: second of the minute from 0 to 59 + // 7: Offset from Greenwich Mean Time in number of 15 minute intervals from -48 (West) to +52 (East) + + $UNIXyear = ord($ISOtime{0}) + 1900; + $UNIXmonth = ord($ISOtime{1}); + $UNIXday = ord($ISOtime{2}); + $UNIXhour = ord($ISOtime{3}); + $UNIXminute = ord($ISOtime{4}); + $UNIXsecond = ord($ISOtime{5}); + $GMToffset = TwosCompliment2Decimal(ord($ISOtime{5})); + + return mktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear); +} + + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.jpg.php b/livesupport/modules/getid3/var/getid3.jpg.php new file mode 100644 index 000000000..ad302c703 --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.jpg.php @@ -0,0 +1,58 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.jpg.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function getJPGHeaderFilepointer(&$fd, &$ThisFileInfo) { + $ThisFileInfo['fileformat'] = 'jpg'; + $ThisFileInfo['video']['dataformat'] = 'jpg'; + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + require_once(GETID3_INCLUDEPATH.'getid3.getimagesize.php'); + + list($width, $height, $type) = GetDataImageSize(fread($fd, $ThisFileInfo['filesize'])); + if ($type == 2) { + + $ThisFileInfo['video']['resolution_x'] = $width; + $ThisFileInfo['video']['resolution_y'] = $height; + + if (version_compare(phpversion(), '4.2.0', '>=')) { + + if (function_exists('exif_read_data')) { + + ob_start(); + $ThisFileInfo['jpg']['exif'] = exif_read_data($ThisFileInfo['filenamepath'], '', true, false); + $errors = ob_get_contents(); + if ($errors) { + $ThisFileInfo['warning'] .= "\n".strip_tags($errors); + unset($ThisFileInfo['jpg']['exif']); + } + ob_end_clean(); + + } else { + + $ThisFileInfo['error'] .= "\n".'EXIF parsing only available when compiled with --enable-exif (or php_exif.dll enabled for Windows)'; + + } + + } else { + + $ThisFileInfo['error'] .= "\n".'EXIF parsing only available in PHP v4.2.0 and higher (you are using PHP v'.phpversion().') compiled with --enable-exif (or php_exif.dll enabled for Windows)'; + + } + + return true; + + } + + unset($ThisFileInfo['fileformat']); + return false; +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.la.php b/livesupport/modules/getid3/var/getid3.la.php new file mode 100644 index 000000000..8ffb1cd0a --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.la.php @@ -0,0 +1,131 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.la.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function getLAHeaderFilepointer(&$fd, &$ThisFileInfo) { + $offset = 0; + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + $rawdata = fread($fd, FREAD_BUFFER_SIZE); + + switch (substr($rawdata, $offset, 4)) { + case 'LA02': + case 'LA03': + $ThisFileInfo['fileformat'] = 'la'; + $ThisFileInfo['audio']['dataformat'] = 'la'; + $ThisFileInfo['la']['version_major'] = (int) substr($rawdata, $offset + 2, 1); + $ThisFileInfo['la']['version_minor'] = (int) substr($rawdata, $offset + 3, 1); + $ThisFileInfo['la']['version'] = (float) $ThisFileInfo['la']['version_major'] + ($ThisFileInfo['la']['version_minor'] / 10); + $offset += 4; + + $ThisFileInfo['la']['uncompressed_size'] = LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + if ($ThisFileInfo['la']['uncompressed_size'] == 0) { + $ThisFileInfo['error'] .= "\n".'Corrupt LA file: uncompressed_size == zero'; + return false; + } + + $WAVEchunk = substr($rawdata, $offset, 4); + if ($WAVEchunk !== 'WAVE') { + $ThisFileInfo['error'] .= "\n".'Expected "WAVE" ('.PrintHexBytes('WAVE').') at offset '.$offset.', found "'.$WAVEchunk.'" ('.PrintHexBytes($WAVEchunk).') instead.'; + return false; + } + $offset += 4; + + $ThisFileInfo['la']['format_size'] = 24; + if ($ThisFileInfo['la']['version'] > 0.2) { + + $ThisFileInfo['la']['format_size'] = LittleEndian2Int(substr($rawdata, $offset, 4)); + $ThisFileInfo['la']['header_size'] = 49 + $ThisFileInfo['la']['format_size'] - 24; + $offset += 4; + + } else { + + // version two didn't support additional data blocks + $ThisFileInfo['la']['header_size'] = 41; + + } + + $fmt_chunk = substr($rawdata, $offset, 4); + if ($fmt_chunk !== 'fmt ') { + $ThisFileInfo['error'] .= "\n".'Expected "fmt " ('.PrintHexBytes('fmt ').') at offset '.$offset.', found "'.$fmt_chunk.'" ('.PrintHexBytes($fmt_chunk).') instead.'; + return false; + } + $offset += 4; + $fmt_size = LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + + $ThisFileInfo['la']['format_raw'] = LittleEndian2Int(substr($rawdata, $offset, 2)); + $offset += 2; + + $ThisFileInfo['la']['channels'] = LittleEndian2Int(substr($rawdata, $offset, 2)); + $offset += 2; + if ($ThisFileInfo['la']['channels'] == 0) { + $ThisFileInfo['error'] .= "\n".'Corrupt LA file: channels == zero'; + return false; + } + + $ThisFileInfo['la']['sample_rate'] = LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + if ($ThisFileInfo['la']['sample_rate'] == 0) { + $ThisFileInfo['error'] .= "\n".'Corrupt LA file: sample_rate == zero'; + return false; + } + + $ThisFileInfo['la']['bytes_per_second'] = LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + $ThisFileInfo['la']['bytes_per_sample'] = LittleEndian2Int(substr($rawdata, $offset, 2)); + $offset += 2; + $ThisFileInfo['la']['bits_per_sample'] = LittleEndian2Int(substr($rawdata, $offset, 2)); + $offset += 2; + + $ThisFileInfo['la']['samples'] = LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + + $ThisFileInfo['la']['seekable'] = (bool) LittleEndian2Int(substr($rawdata, $offset, 1)); + $offset += 1; + + $ThisFileInfo['la']['original_crc'] = LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + + require_once(GETID3_INCLUDEPATH.'getid3.riff.php'); + $ThisFileInfo['la']['codec'] = RIFFwFormatTagLookup($ThisFileInfo['la']['format_raw']); + $ThisFileInfo['la']['compression_ratio'] = (float) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['la']['uncompressed_size']); + $ThisFileInfo['playtime_seconds'] = (float) ($ThisFileInfo['la']['samples'] / $ThisFileInfo['la']['sample_rate']) / $ThisFileInfo['la']['channels']; + if ($ThisFileInfo['playtime_seconds'] == 0) { + $ThisFileInfo['error'] .= "\n".'Corrupt LA file: playtime_seconds == zero'; + return false; + } + + // add size of file header to avdataoffset - calc bitrate correctly + MD5 data + $ThisFileInfo['avdataoffset'] += $ThisFileInfo['la']['header_size']; + + $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds']; + $ThisFileInfo['audio']['codec'] = $ThisFileInfo['la']['codec']; + $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['la']['bits_per_sample']; + break; + + default: + if (substr($rawdata, $offset, 2) == 'LA') { + $ThisFileInfo['error'] .= "\n".'This version of getID3() (v'.GETID3VERSION.') doesn\'t support LA version '.substr($rawdata, $offset + 2, 1).'.'.substr($rawdata, $offset + 3, 1).' which this appears to be - check http://getid3.sourceforge.net for updates.'; + } else { + $ThisFileInfo['error'] .= "\n".'Not a LA (Lossless-Audio) file'; + } + return false; + break; + } + + $ThisFileInfo['audio']['channels'] = $ThisFileInfo['la']['channels']; + $ThisFileInfo['audio']['sample_rate'] = (int) $ThisFileInfo['la']['sample_rate']; + $ThisFileInfo['audio']['encoder'] = (string) $ThisFileInfo['la']['version']; + + return true; +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.ogginfo.php b/livesupport/modules/getid3/var/getid3.ogginfo.php new file mode 100644 index 000000000..c270694e3 --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.ogginfo.php @@ -0,0 +1,104 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.ogginfo.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function OggWrite($filename, $comments) { + + // Uses vorbiscomment(.exe) to write comments, if available. + + if ((bool) ini_get('safe_mode')) { + + echo 'Failed making system call to vorbiscomment.exe - cannot write comments - error returned: PHP running in Safe Mode (backtick operator not available)'; + return false; + + } else { + + // Prevent user from aborting script + $old_abort = ignore_user_abort(true); + + // Create file with new comments + $commentsfilename = tempnam('/tmp', 'getID3'); + if ($fpcomments = fopen($commentsfilename, 'wb')) { + + foreach ($comments as $key => $value) { + if (!is_array($value)) { + $comments[$key] = array($value); + } + } + foreach ($comments as $key => $value) { + foreach ($value as $valuekey => $valuevalue) { + str_replace("\r", "\n", $valuevalue); + if (strstr($valuevalue, "\n")) { + unset($comments[$key][$valuekey]); + $multilineexploded = explode("\n", $valuevalue); + foreach ($multilineexploded as $newcomment) { + if (strlen(trim($newcomment)) > 0) { + $comments[$key][] = $newcomment; + } + } + } + } + } + foreach ($comments as $key => $value) { + foreach ($value as $commentdata) { + fwrite($fpcomments, CleanOggCommentName($key).'='.$commentdata."\n"); + } + } + fclose($fpcomments); + } + + if (substr(php_uname(), 0, 7) == 'Windows') { + + if (file_exists(GETID3_INCLUDEPATH.'vorbiscomment.exe')) { + + $VorbisCommentError = `vorbiscomment.exe -w -c "$commentsfilename" "$filename"`; + + } else { + + $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_INCLUDEPATH; + + } + + } else { + + $VorbisCommentError = `vorbiscomment -w -c "$commentsfilename" "$filename" 2>&1`; + + } + + if (!empty($VorbisCommentError)) { + + echo 'Failed making system call to vorbiscomment(.exe) - cannot write comments. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError; + return false; + + } + + // Remove temporary comments file + unlink($commentsfilename); + + // Reset abort setting + ignore_user_abort($old_abort); + + return true; + } +} + + +function CleanOggCommentName($originalcommentname) { + // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded. + // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through + // 0x7A inclusive (a-z). + + // replace invalid chars with a space, return uppercase text + // Thanks Chris Bolt for improving this function + return strtoupper(ereg_replace('[^ -<>-}]', ' ', $originalcommentname)); + +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.php b/livesupport/modules/getid3/var/getid3.php new file mode 100644 index 000000000..6c8a0a78c --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.php @@ -0,0 +1,666 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// Requires: PHP 4.1.0 (or higher) // +// GD <1.6 for GIF and JPEG functions // +// GD >=1.6 for PNG and JPEG functions // +// GD >=2.0 for BMP display function // +// // +// Please see getid3.readme.txt for more information // +// // +///////////////////////////////////////////////////////////////// + +// Defines +define('GETID3VERSION', '1.6.0'); +define('FREAD_BUFFER_SIZE', 16384); // number of bytes to read in at once + +// Get base path of getID3() +$includedfilepaths = get_included_files(); +foreach ($includedfilepaths as $key => $val) { + if (basename($val) == 'getid3.php') { + if (substr(php_uname(), 0, 7) == 'Windows') { + define('GETID3_INCLUDEPATH', str_replace('\\', '/', dirname($val)).'/'); + } else { + define('GETID3_INCLUDEPATH', dirname($val).'/'); + } + } +} +if (!defined('GETID3_INCLUDEPATH')) { + define('GETID3_INCLUDEPATH', ''); +} + + +function GetAllFileInfo($filename, $assumedFormat='', $MD5file=false, $MD5data=false) { + require_once(GETID3_INCLUDEPATH.'getid3.functions.php'); // Function library + + $ThisFileInfo['getID3version'] = GETID3VERSION; + $ThisFileInfo['fileformat'] = ''; // filled in later + $ThisFileInfo['audio']['dataformat'] = ''; // filled in later, unset if not used + $ThisFileInfo['video']['dataformat'] = ''; // filled in later, unset if not used + $ThisFileInfo['tags'] = array(); // filled in later, unset if not used + $ThisFileInfo['error'] = ''; // filled in later, unset if not used + $ThisFileInfo['warning'] = ''; // filled in later, unset if not used + $ThisFileInfo['exist'] = false; + + if (eregi('^(ht|f)tp://', $filename)) { + + // remote file + $ThisFileInfo['filename'] = $filename; + $ThisFileInfo['error'] .= "\n".'Remote files are not supported in this version of getID3() - please copy the file locally first'; + + } else { + + // local file + + $ThisFileInfo['filename'] = basename($filename); + $ThisFileInfo['filepath'] = str_replace('\\', '/', realpath(dirname($filename))); + $ThisFileInfo['filenamepath'] = $ThisFileInfo['filepath'].'/'.$ThisFileInfo['filename']; + ob_start(); + if ($localfilepointer = fopen($filename, 'rb')) { + + $ThisFileInfo['exist'] = true; + + //$ThisFileInfo['filesize'] = filesize($ThisFileInfo['filenamepath']); + // PHP doesn't support integers larger than 31-bit (~2GB) + // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize + // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer + fseek($localfilepointer, 0, SEEK_END); + $ThisFileInfo['filesize'] = ftell($localfilepointer); + ob_end_clean(); + if ($ThisFileInfo['filesize'] == 0) { + if (filesize($ThisFileInfo['filenamepath']) != 0) { + + unset($ThisFileInfo['filesize']); + $ThisFileInfo['error'] .= "\n".'File is most likely larger than 2GB and is not supported by PHP'; + + } + + // remove unneeded/meaningless keys + CleanUpGetAllMP3info($ThisFileInfo); + + // close & remove local filepointer + CloseRemoveFilepointer($localfilepointer); + return $ThisFileInfo; + + } + + + } else { + + $ThisFileInfo['error'] .= "\n".'Error opening file: '.trim(strip_tags(ob_get_contents())); + ob_end_clean(); + + // remove unneeded/meaningless keys + CleanUpGetAllMP3info($ThisFileInfo); + + // close & remove local filepointer + CloseRemoveFilepointer($localfilepointer); + return $ThisFileInfo; + + } + + } + + // Initialize avdataoffset and avdataend + $ThisFileInfo['avdataoffset'] = 0; + $ThisFileInfo['avdataend'] = $ThisFileInfo['filesize']; + + // Handle APE tags + HandleAPETag($localfilepointer, $ThisFileInfo); + + rewind($localfilepointer); + //$formattest = fread($localfilepointer, 16); // 16 bytes is sufficient for any format except ISO CD-image + $formattest = fread($localfilepointer, 32774); // (ISO needs at least 32774 bytes) + + // Handle ID3v2 tag + if (substr($formattest, 0, 3) == 'ID3') { + HandleID3v2Tag($localfilepointer, $ThisFileInfo); + rewind($localfilepointer); + fseek($localfilepointer, $ThisFileInfo['avdataoffset'], SEEK_SET); + $formattest = fread($localfilepointer, 32774); // (ISO9660 needs at least 32774 bytes) + } + + // Handle ID3v1 tags + HandleID3v1Tag($localfilepointer, $ThisFileInfo); + + // Nothing-but-tags check + if (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) > 0) { + + if ($DeterminedFormat = GetFileFormat($formattest)) { + + // break if ID3/APE tags found on illegal format + if (!$DeterminedFormat['allowtags'] && ($ThisFileInfo['avdataoffset'] > 0) && ($ThisFileInfo['avdataend'] != $ThisFileInfo['filesize'])) { + $ThisFileInfo['error'] .= "\n".'Illegal ID3 and/or APE tag found on non multimedia file.'; + break; + } + + // set mime type + $ThisFileInfo['mime_type'] = $DeterminedFormat['mimetype']; + + // supported format signature pattern detected + require_once(GETID3_INCLUDEPATH.$DeterminedFormat['include']); + + switch ($DeterminedFormat['format']) { + //case 'midi': + // if ($assumedFormat === false) { + // // do not parse all MIDI tracks - much faster + // getMIDIHeaderFilepointer($localfilepointer, $ThisFileInfo, false); + // } else { + // getMIDIHeaderFilepointer($localfilepointer, $ThisFileInfo); + // } + // break; + + //case 'aac': + // if (!getAACADIFheaderFilepointer($localfilepointer, $ThisFileInfo)) { + // $dummy = $ThisFileInfo; + // unset($dummy['error']); + // if (getAACADTSheaderFilepointer($localfilepointer, $dummy)) { + // $ThisFileInfo = $dummy; + // } + // } + // break; + + default: + $VariableFunctionName = $DeterminedFormat['function']; + $VariableFunctionName($localfilepointer, $ThisFileInfo); + break; + } + + } elseif ((($assumedFormat == 'mp3') || (($assumedFormat == '') && ((substr($formattest, 0, 3) == 'ID3') || (substr(BigEndian2Bin(substr($formattest, 0, 2)), 0, 11) == '11111111111'))))) { + + // assume AAC-ADTS format + require_once(GETID3_INCLUDEPATH.'getid3.aac.php'); + $dummy = $ThisFileInfo; + if (getAACADTSheaderFilepointer($localfilepointer, $dummy)) { + + $ThisFileInfo = $dummy; + + } else { + + // it's not AAC-ADTS format, probably MP3 + require_once(GETID3_INCLUDEPATH.'getid3.mp3.php'); + getMP3headerFilepointer($localfilepointer, $ThisFileInfo); + + } + + } else { + + // unknown format, do nothing + + } + + } + + if (isset($ThisFileInfo['fileformat'])) { + + // Calculate combined bitrate - audio + video + $CombinedBitrate = 0; + $CombinedBitrate += (isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0); + $CombinedBitrate += (isset($ThisFileInfo['video']['bitrate']) ? $ThisFileInfo['video']['bitrate'] : 0); + if (($CombinedBitrate > 0) && !isset($ThisFileInfo['bitrate'])) { + $ThisFileInfo['bitrate'] = $CombinedBitrate; + } + + // Set playtime string + if (!empty($ThisFileInfo['playtime_seconds']) && empty($ThisFileInfo['playtime_string'])) { + $ThisFileInfo['playtime_string'] = PlaytimeString($ThisFileInfo['playtime_seconds']); + } + + if (!empty($ThisFileInfo['audio']['channels'])) { + switch ($ThisFileInfo['audio']['channels']) { + case 1: + $ThisFileInfo['audio']['channelmode'] = 'mono'; + break; + + case 2: + $ThisFileInfo['audio']['channelmode'] = 'stereo'; + break; + + default: + // unknown? + break; + } + } + } + + // Get the MD5 hash of the entire file + if ($MD5file && empty($ThisFileInfo['md5_file'])) { + $ThisFileInfo['md5_file'] = md5_file($filename); + } + + // Get the MD5 hash of the audio/video portion of the file + // (without ID3/APE/Lyrics3/etc header/footer tags + if ($MD5data && empty($ThisFileInfo['md5_data'])) { + getMD5data($ThisFileInfo); + } + + // return tags data in alphabetical order, without duplicates + $ThisFileInfo['tags'] = array_unique($ThisFileInfo['tags']); + sort($ThisFileInfo['tags']); + + // remove unneeded/meaningless keys + CleanUpGetAllMP3info($ThisFileInfo); + + // close & remove local filepointer + CloseRemoveFilepointer($localfilepointer); + + return $ThisFileInfo; +} + + +function CleanUpGetAllMP3info(&$ThisFileInfo) { + if (empty($ThisFileInfo['fileformat'])) { + // remove meaningless entries from unknown-format files + unset($ThisFileInfo['fileformat']); + unset($ThisFileInfo['audio']['dataformat']); + unset($ThisFileInfo['video']['dataformat']); + unset($ThisFileInfo['avdataoffset']); + unset($ThisFileInfo['avdataend']); + } + + $PotentialKeysToRemove = array('dataformat', 'bitrate_mode'); + foreach (array('audio', 'video') as $key1) { + $RemoveThisKey = true; + if (count($ThisFileInfo[$key1]) > count($PotentialKeysToRemove)) { + $RemoveThisKey = false; + } else { + foreach ($PotentialKeysToRemove as $key2) { + if (!in_array($key2, $PotentialKeysToRemove)) { + $RemoveThisKey = false; + break; + } + } + } + if ($RemoveThisKey) { + unset($ThisFileInfo[$key1]); + } + } + + $PotentialKeysToRemove = array('comments', 'error', 'warning', 'audio', 'video'); + foreach ($PotentialKeysToRemove as $keyname) { + if (empty($ThisFileInfo["$keyname"])) { + unset($ThisFileInfo["$keyname"]); + } + } + + return true; +} + +function CloseRemoveFilepointer(&$filepointer) { + if (isset($localfilepointer) && is_resource($localfilepointer) && (get_resource_type($localfilepointer) == 'file')) { + fclose($localfilepointer); + if (isset($localfilepointer)) { + unset($localfilepointer); + } + } + return true; +} + + +function CopyFormatCommentsToRootComments($commentsarray, &$ThisFileInfo, $KeysToCopy=array('title'=>'title', 'artist'=>'artist', 'album'=>'album', 'year'=>'year', 'genre'=>'genre', 'comment'=>'comment', 'track'=>'track'), $ReplaceAll=false, $Append=false) { + if ($ReplaceAll) { + $ThisFileInfo['comments'] = array(); + } + + if (!is_array($KeysToCopy)) { + $KeysToCopy = array(); + foreach (array_keys($commentsarray) as $key => $value) { + $KeysToCopy[$value] = $value; + } + } + foreach ($KeysToCopy as $FromKey => $ToKey) { + $ToKey = strtolower($ToKey); + if (!empty($commentsarray["$FromKey"])) { + if (is_array($commentsarray["$FromKey"])) { + foreach ($commentsarray["$FromKey"] as $CommentArrayValue) { + if ((empty($ThisFileInfo['comments']["$ToKey"])) || ($Append && !in_array($CommentArrayValue, $ThisFileInfo['comments']["$ToKey"], false))) { + $ThisFileInfo['comments']["$ToKey"][] = $CommentArrayValue; + } + } + } else { + if ((empty($ThisFileInfo['comments']["$ToKey"])) || ($Append && !in_array($commentsarray["$FromKey"], $ThisFileInfo['comments']["$ToKey"], false))) { + $ThisFileInfo['comments']["$ToKey"][] = $commentsarray["$FromKey"]; + } + } + } + } + return true; +} + +function GetFileFormat(&$filedata) { + // this function will determine the format of a file based on usually + // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG, + // and in the case of ISO CD image, 6 bytes offset 32kb from the start + // of the file). + + // Array containing information about all supported formats + static $format_info = array(); + if (empty($format_info)) { + $format_info = array( + + // Format: => array(, , , , ) + + + // Audio formats + + // AAC - audio - Advanced Audio Coding (AAC) - ADIF format + 'aac' => array('^ADIF', 'getid3.aac.php', 'getAACADIFheaderFilepointer', true, 'application/octet-stream'), + + // AIFF - audio - Audio Interchange File Format (AIFF) + //'aiff' => array('^FORM', 'getid3.aiff.php', 'getAIFFHeaderFilepointer', true, 'audio/x-aiff'), + + // FLAC - audio - Free Lossless Audio Codec + 'flac' => array('^fLaC', 'getid3.flac.php', 'getFLACHeaderFilepointer', true, 'audio/x-flac'), + + // LA - audio - Lossless Audio (LA) + 'la' => array('^LA0[23]', 'getid3.la.php', 'getLAHeaderFilepointer', true, 'application/octet-stream'), + + // MIDI - audio - MIDI (Musical Instrument Digital Interface) + 'midi' => array('^MThd', 'getid3.midi.php', 'getMIDIHeaderFilepointer', true, 'audio/midi'), + + // MAC - audio - Monkey's Audio Compressor + 'mac' => array('^MAC ', 'getid3.monkey.php', 'getMonkeysAudioHeaderFilepointer', true, 'application/octet-stream'), + + // MPC - audio - Musepack / MPEGplus + 'mpc' => array('^MP\+', 'getid3.mpc.php', 'getMPCHeaderFilepointer', true, 'application/octet-stream'), + + // Ogg - audio - Ogg Vorbis + 'ogg' => array('^OggS', 'getid3.ogg.php', 'getOggHeaderFilepointer', true, 'application/x-ogg'), + + // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF) + 'vqf' => array('^TWIN', 'getid3.vqf.php', 'getVQFHeaderFilepointer', true, 'application/octet-stream'), + + + // Audio-Video formats + + // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio + 'asf' => array('^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C', 'getid3.asf.php', 'getASFHeaderFilepointer', true, 'video/x-ms-asf'), + + // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) + 'riff' => array('^(RIFF|SDSS)', 'getid3.riff.php', 'getRIFFHeaderFilepointer', true, 'audio/x-wave'), + + // Real - audio/video - RealAudio, RealVideo + 'real' => array('^\.RMF', 'getid3.real.php', 'getRealHeaderFilepointer', true, 'audio/x-realaudio'), + + // NSV - audio/video - Nullsoft Streaming Video (NSV) + 'nsv' => array('^NSV[sf]', 'getid3.nsv.php', 'getNSVHeaderFilepointer', true, 'application/octet-stream'), + + // MPEG - audio/video - MPEG (Moving Pictures Experts Group) + 'mpeg' => array('^\x00\x00\x01\xBA', 'getid3.mpeg.php', 'getMPEGHeaderFilepointer', true, 'video/mpeg'), + + // QT - audio/video - Quicktime + 'quicktime' => array('^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)', 'getid3.quicktime.php', 'getQuicktimeHeaderFilepointer', true, 'video/quicktime'), + + + // Still-Image formats + + // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4) + 'bmp' => array('^BM', 'getid3.bmp.php', 'getBMPHeaderFilepointer', false, 'image/bmp'), + + // GIF - still image - Graphics Interchange Format + 'gif' => array('^GIF', 'getid3.gif.php', 'getGIFHeaderFilepointer', false, 'image/gif'), + + // JPEG - still image - Joint Photographic Experts Group (JPEG) + 'jpg' => array('^\xFF\xD8\xFF', 'getid3.jpg.php', 'getJPGHeaderFilepointer', false, 'image/jpg'), + + // PNG - still image - Portable Network Graphics (PNG) + 'png' => array('^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A', 'getid3.png.php', 'getPNGHeaderFilepointer', false, 'image/png'), + + + // Data formats + + // EXE - data - EXEcutable program (EXE, COM) + //'exe' => array('^MZ', 'getid3.exe.php', 'getEXEHeaderFilepointer', false, 'application/octet-stream'), + + // ISO - data - International Standards Organization (ISO) CD-ROM Image + 'iso' => array('^.{32769}CD001', 'getid3.iso.php', 'getISOHeaderFilepointer', false, 'application/octet-stream'), + + // RAR - data - RAR compressed data + //'rar' => array('^Rar\!', 'getid3.rar.php', 'getRARHeaderFilepointer', false, 'application/octet-stream'), + + // ZIP - data - ZIP compressed data + 'zip' => array('^PK\x03\x04', 'getid3.zip.php', 'getZIPHeaderFilepointer', false, 'application/zip'), + + ); + } + + // Identify file format - loop through $format_info and detect with reg expr + foreach ($format_info as $format_name => $info) { + // Using preg_match() instead of ereg() - much faster + // The /s switch on preg_match() forces preg_match() NOT to treat + // newline (0x0A) characters as special chars but do a binary match + if (preg_match('/'.$info[0].'/s', $filedata)) { + // Extract information + $FormatData['format'] = $format_name; + //$FormatData['pattern'] = $info[0]; + $FormatData['include'] = $info[1]; + $FormatData['function'] = $info[2]; + $FormatData['allowtags'] = $info[3]; + $FormatData['mimetype'] = $info[4]; + + return $FormatData; + + } + } + return false; +} + + +function HandleAPETag(&$fd, &$ThisFileInfo) { + require_once(GETID3_INCLUDEPATH.'getid3.ape.php'); + getAPEtagFilepointer($fd, $ThisFileInfo); + + if (isset($ThisFileInfo['ape']['header']['raw']['tagsize'])) { + + $ThisFileInfo['avdataend'] -= $ThisFileInfo['ape']['header']['raw']['tagsize'] + 32; + + // APE tags has second highest priority + CopyFormatCommentsToRootComments($ThisFileInfo['ape']['comments'], $ThisFileInfo, true, true, true); + + // add tag to array of tags + $ThisFileInfo['tags'][] = 'ape'; + + } + + return true; +} + + + +function HandleID3v1Tag(&$fd, &$ThisFileInfo) { + fseek($fd, (0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - LYRICSEND - [Lyrics3size] + $lyrics3_id3v1 = fread($fd, (128 + 9 + 6)); + $lyrics3lsz = substr($lyrics3_id3v1, 0, 6); // Lyrics3size + $lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200 + $id3v1tag = substr($lyrics3_id3v1, 15, 128); // ID3v1 + + if ($lyrics3end == 'LYRICSEND') { + // Lyrics3 v1 and ID3v1 + + $lyrics3size = 5100; + $ThisFileInfo['avdataend'] -= $lyrics3size; + require_once(GETID3_INCLUDEPATH.'getid3.lyrics3.php'); + getLyrics3Filepointer($ThisFileInfo, $fd, 0 - 128 - $lyrics3size, 1, $lyrics3size); + + } elseif ($lyrics3end == 'LYRICS200') { + // Lyrics3 v2 and ID3v1 + + $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' + $ThisFileInfo['avdataend'] -= $lyrics3size; + require_once(GETID3_INCLUDEPATH.'getid3.lyrics3.php'); + getLyrics3Filepointer($ThisFileInfo, $fd, -128 - $lyrics3size, 2, $lyrics3size); + + } elseif (substr($lyrics3_id3v1, strlen($lyrics3_id3v1) - 1 - 9, 9) == 'LYRICSEND') { + // Lyrics3 v1, no ID3v1 (I think according to Lyrics3 specs there MUST be ID3v1, but just in case :) + + $lyrics3size = 5100; + $ThisFileInfo['avdataend'] -= $lyrics3size; + require_once(GETID3_INCLUDEPATH.'getid3.lyrics3.php'); + getLyrics3Filepointer($ThisFileInfo, $fd, 0 - $lyrics3size, 1, $lyrics3size); + + } elseif (substr($lyrics3_id3v1, strlen($lyrics3_id3v1) - 1 - 9, 9) == 'LYRICS200') { + // Lyrics3 v2, no ID3v1 (I think according to Lyrics3 specs there MUST be ID3v1, but just in case :) + + $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' + $ThisFileInfo['avdataend'] -= $lyrics3size; + require_once(GETID3_INCLUDEPATH.'getid3.lyrics3.php'); + getLyrics3Filepointer($ThisFileInfo, $fd, 0 - $lyrics3size, 2, $lyrics3size); + } + + if (substr($id3v1tag, 0, 3) == 'TAG') { + $ThisFileInfo['avdataend'] -= 128; + + require_once(GETID3_INCLUDEPATH.'getid3.id3v1.php'); + getID3v1Filepointer($fd, $ThisFileInfo); + + // Do not change fileformat if already set + if (empty($ThisFileInfo['fileformat'])) { + $ThisFileInfo['fileformat'] = 'id3'; + } + + $ThisFileInfo['tags'][] = 'id3v1'; + + // ID3v1 has lowest preference. We add if $ThisFileInfo[comments] is empty - this will override empty tags of higher preference, or add comments to root if not already present + if (isset($ThisFileInfo['id3v1'])) { + CopyFormatCommentsToRootComments($ThisFileInfo['id3v1'], $ThisFileInfo, true, false, false); + } + } + + return true; +} + + + +function HandleID3v2Tag(&$fd, &$ThisFileInfo) { + require_once(GETID3_INCLUDEPATH.'getid3.id3v2.php'); + getID3v2Filepointer($fd, $ThisFileInfo); + + // Tag present + if (isset($ThisFileInfo['id3v2']['header'])) { + + // Do not change fileformat if already set + if (empty($ThisFileInfo['fileformat'])) { + $ThisFileInfo['fileformat'] = 'id3'; + } + + // Set avdataoffset + $ThisFileInfo['avdataoffset'] = $ThisFileInfo['id3v2']['headerlength']; + if (isset($ThisFileInfo['id3v2']['footer'])) { + $ThisFileInfo['avdataoffset'] += 10; + } + + $ThisFileInfo['tags'][] = 'id3v2'; + + if (isset($ThisFileInfo['id3v2']['comments'])) { + CopyFormatCommentsToRootComments($ThisFileInfo['id3v2']['comments'], $ThisFileInfo, true, false, false); + } + + } + + return true; +} + +function getMD5data(&$ThisFileInfo) { + + if (($ThisFileInfo['fileformat'] == 'ogg') && (@$ThisFileInfo['audio']['dataformat'] == 'vorbis')) { + + // We cannot get an identical md5_data value for Ogg files where the comments + // span more than 1 Ogg page (compared to the same audio data with smaller + // comments) using the normal getID3() method of MD5'ing the data between the + // end of the comments and the end of the file (minus any trailing tags), + // because the page sequence numbers of the pages that the audio data is on + // do not match. Under normal circumstances, where comments are smaller than + // the nominal 4-8kB page size, then this is not a problem, but if there are + // very large comments, the only way around it is to strip off the comment + // tags with vorbiscomment and MD5 that file. + // This procedure must be applied to ALL Ogg files, not just the ones with + // comments larger than 1 page, because the below method simply MD5's the + // whole file with the comments stripped, not just the portion after the + // comments block (which is the standard getID3() method. + + // The above-mentioned problem of comments spanning multiple pages and changing + // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but + // currently vorbiscomment only works on OggVorbis files. + + if ((bool) ini_get('safe_mode')) { + + $ThisFileInfo['warning'] .= "\n".'Failed making system call to vorbiscomment.exe - md5_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)'; + $ThisFileInfo['md5_data'] = false; + + } else { + + // Prevent user from aborting script + $old_abort = ignore_user_abort(true); + + // Create empty file + $empty = tempnam('/tmp', 'getID3'); + touch($empty); + + + // Use vorbiscomment to make temp file without comments + $temp = tempnam('/tmp', 'getID3'); + $file = $ThisFileInfo['filenamepath']; + + if (substr(php_uname(), 0, 7) == 'Windows') { + + if (file_exists(GETID3_INCLUDEPATH.'vorbiscomment.exe')) { + + $VorbisCommentError = `vorbiscomment.exe -w -c "$empty" "$file" "$temp"`; + + } else { + + $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_INCLUDEPATH; + + } + + } else { + + $VorbisCommentError = `vorbiscomment -w -c "$empty" "$file" "$temp" 2>&1`; + + } + + if (!empty($VorbisCommentError)) { + + $ThisFileInfo['warning'] .= "\n".'Failed making system call to vorbiscomment(.exe) - md5_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError; + $ThisFileInfo['md5_data'] = false; + + } else { + + // Get md5 value of newly created file + $ThisFileInfo['md5_data'] = md5_file($temp); + + } + + // Clean up + unlink($empty); + unlink($temp); + + // Reset abort setting + ignore_user_abort($old_abort); + + } + + } else { + + if (!empty($ThisFileInfo['avdataoffset']) || (isset($ThisFileInfo['avdataend']) && ($ThisFileInfo['avdataend'] < $ThisFileInfo['filesize']))) { + $ThisFileInfo['md5_data'] = md5_data($ThisFileInfo['filenamepath'], $ThisFileInfo['avdataoffset'], $ThisFileInfo['avdataend']); + } else { + if (empty($ThisFileInfo['md5_file'])) { + $ThisFileInfo['md5_file'] = md5_file($ThisFileInfo['filenamepath']); + } + $ThisFileInfo['md5_data'] = $ThisFileInfo['md5_file']; + } + + } + return true; +} + + +function PoweredBygetID3($string='

') { + return str_replace('', GETID3VERSION, $string); +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.png.php b/livesupport/modules/getid3/var/getid3.png.php new file mode 100644 index 000000000..3290a5f5e --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.png.php @@ -0,0 +1,484 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.png.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function getPNGHeaderFilepointer(&$fd, &$ThisFileInfo) { + $ThisFileInfo['fileformat'] = 'png'; + $ThisFileInfo['video']['dataformat'] = 'png'; + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + $PNGfiledata = fread($fd, FREAD_BUFFER_SIZE); + $offset = 0; + + $PNGidentifier = substr($PNGfiledata, $offset, 8); // $89 $50 $4E $47 $0D $0A $1A $0A + $offset += 8; + if ($PNGidentifier != chr(0x89).chr(0x50).chr(0x4E).chr(0x47).chr(0x0D).chr(0x0A).chr(0x1A).chr(0x0A)) { + $ThisFileInfo['error'] .= "\n".'First 8 bytes of file ('.PrintHexBytes($PNGidentifier).') did not match expected PNG identifier'; + unset($ThisFileInfo['fileformat']); + return false; + } + + while (((ftell($fd) - (strlen($PNGfiledata) - $offset)) < $ThisFileInfo['filesize'])) { + $chunk['data_length'] = BigEndian2Int(substr($PNGfiledata, $offset, 4)); + $offset += 4; + while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && (ftell($fd) < $ThisFileInfo['filesize'])) { + $PNGfiledata .= fread($fd, FREAD_BUFFER_SIZE); + } + $chunk['type_text'] = substr($PNGfiledata, $offset, 4); + $offset += 4; + $chunk['type_raw'] = BigEndian2Int($chunk['type_text']); + $chunk['data'] = substr($PNGfiledata, $offset, $chunk['data_length']); + $offset += $chunk['data_length']; + $chunk['crc'] = BigEndian2Int(substr($PNGfiledata, $offset, 4)); + $offset += 4; + + $chunk['flags']['ancilliary'] = (bool) ($chunk['type_raw'] & 0x20000000); + $chunk['flags']['private'] = (bool) ($chunk['type_raw'] & 0x00200000); + $chunk['flags']['reserved'] = (bool) ($chunk['type_raw'] & 0x00002000); + $chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x00000020); + + switch ($chunk['type_text']) { + + case 'IHDR': // Image Header + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $ThisFileInfo['png'][$chunk['type_text']]['width'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 4)); + $ThisFileInfo['png'][$chunk['type_text']]['height'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 4, 4)); + $ThisFileInfo['png'][$chunk['type_text']]['raw']['bit_depth'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 8, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['raw']['color_type'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 9, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['raw']['compression_method'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 10, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['raw']['filter_method'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 11, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['raw']['interlace_method'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 12, 1)); + + $ThisFileInfo['png'][$chunk['type_text']]['compression_method_text'] = PNGcompressionMethodLookup($ThisFileInfo['png'][$chunk['type_text']]['raw']['compression_method']); + $ThisFileInfo['png'][$chunk['type_text']]['color_type']['palette'] = (bool) ($ThisFileInfo['png'][$chunk['type_text']]['raw']['color_type'] & 0x01); + $ThisFileInfo['png'][$chunk['type_text']]['color_type']['true_color'] = (bool) ($ThisFileInfo['png'][$chunk['type_text']]['raw']['color_type'] & 0x02); + $ThisFileInfo['png'][$chunk['type_text']]['color_type']['alpha'] = (bool) ($ThisFileInfo['png'][$chunk['type_text']]['raw']['color_type'] & 0x04); + + $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['png'][$chunk['type_text']]['width']; + $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['png'][$chunk['type_text']]['height']; + break; + + + case 'PLTE': // Palette + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $paletteoffset = 0; + for ($i = 0; $i <= 255; $i++) { + //$ThisFileInfo['png'][$chunk['type_text']]['red'][$i] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $paletteoffset++, 1)); + //$ThisFileInfo['png'][$chunk['type_text']]['green'][$i] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $paletteoffset++, 1)); + //$ThisFileInfo['png'][$chunk['type_text']]['blue'][$i] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $paletteoffset++, 1)); + $red = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $paletteoffset++, 1)); + $green = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $paletteoffset++, 1)); + $blue = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $paletteoffset++, 1)); + $ThisFileInfo['png'][$chunk['type_text']][$i] = (($red << 16) | ($green << 8) | ($blue)); + } + break; + + + case 'tRNS': // Transparency + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + switch ($ThisFileInfo['png']['IHDR']['raw']['color_type']) { + case 0: + $ThisFileInfo['png'][$chunk['type_text']]['transparent_color_gray'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 2)); + break; + + case 2: + $ThisFileInfo['png'][$chunk['type_text']]['transparent_color_red'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 2)); + $ThisFileInfo['png'][$chunk['type_text']]['transparent_color_green'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 2)); + $ThisFileInfo['png'][$chunk['type_text']]['transparent_color_blue'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 2)); + break; + + case 3: + for ($i = 0; $i < strlen($ThisFileInfo['png'][$chunk['type_text']]['header']['data']); $i++) { + $ThisFileInfo['png'][$chunk['type_text']]['palette_opacity'][$i] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $i, 1)); + } + break; + + case 4: + case 6: + $ThisFileInfo['error'] .= "\n".'Invalid color_type in tRNS chunk: '.$ThisFileInfo['png']['IHDR']['raw']['color_type']; + + default: + $ThisFileInfo['warning'] .= "\n".'Unhandled color_type in tRNS chunk: '.$ThisFileInfo['png']['IHDR']['raw']['color_type']; + break; + } + break; + + + case 'gAMA': // Image Gamma + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $ThisFileInfo['png'][$chunk['type_text']]['gamma'] = BigEndian2Int($ThisFileInfo['png'][$chunk['type_text']]['header']['data']) / 100000; + break; + + + case 'cHRM': // Primary Chromaticities + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $ThisFileInfo['png'][$chunk['type_text']]['white_x'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 4)) / 100000; + $ThisFileInfo['png'][$chunk['type_text']]['white_y'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 4, 4)) / 100000; + $ThisFileInfo['png'][$chunk['type_text']]['red_y'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 8, 4)) / 100000; + $ThisFileInfo['png'][$chunk['type_text']]['red_y'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 12, 4)) / 100000; + $ThisFileInfo['png'][$chunk['type_text']]['green_y'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 16, 4)) / 100000; + $ThisFileInfo['png'][$chunk['type_text']]['green_y'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 20, 4)) / 100000; + $ThisFileInfo['png'][$chunk['type_text']]['blue_y'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 24, 4)) / 100000; + $ThisFileInfo['png'][$chunk['type_text']]['blue_y'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 28, 4)) / 100000; + break; + + + case 'sRGB': // Standard RGB Color Space + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $ThisFileInfo['png'][$chunk['type_text']]['reindering_intent'] = BigEndian2Int($ThisFileInfo['png'][$chunk['type_text']]['header']['data']); + $ThisFileInfo['png'][$chunk['type_text']]['reindering_intent_text'] = PNGsRGBintentLookup($ThisFileInfo['png'][$chunk['type_text']]['reindering_intent']); + break; + + + case 'iCCP': // Embedded ICC Profile + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + list($profilename, $compressiondata) = explode(chr(0x00), $ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2); + $ThisFileInfo['png'][$chunk['type_text']]['profile_name'] = $profilename; + $ThisFileInfo['png'][$chunk['type_text']]['compression_method'] = BigEndian2Int(substr($compressiondata, 0, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['compression_profile'] = substr($compressiondata, 1); + + $ThisFileInfo['png'][$chunk['type_text']]['compression_method_text'] = PNGcompressionMethodLookup($ThisFileInfo['png'][$chunk['type_text']]['compression_method']); + break; + + + case 'tEXt': // Textual Data + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + list($keyword, $text) = explode(chr(0x00), $ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2); + $ThisFileInfo['png'][$chunk['type_text']]['keyword'] = $keyword; + $ThisFileInfo['png'][$chunk['type_text']]['text'] = $text; + + $ThisFileInfo['png']['comments'][$ThisFileInfo['png'][$chunk['type_text']]['keyword']][] = $ThisFileInfo['png'][$chunk['type_text']]['text']; + break; + + + case 'zTXt': // Compressed Textual Data + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + list($keyword, $otherdata) = explode(chr(0x00), $ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2); + $ThisFileInfo['png'][$chunk['type_text']]['keyword'] = $keyword; + $ThisFileInfo['png'][$chunk['type_text']]['compression_method'] = BigEndian2Int(substr($otherdata, 0, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['compressed_text'] = substr($otherdata, 1); + $ThisFileInfo['png'][$chunk['type_text']]['compression_method_text'] = PNGcompressionMethodLookup($ThisFileInfo['png'][$chunk['type_text']]['compression_method']); + switch ($ThisFileInfo['png'][$chunk['type_text']]['compression_method']) { + case 0: + $ThisFileInfo['png'][$chunk['type_text']]['text'] = gzuncompress($ThisFileInfo['png'][$chunk['type_text']]['compressed_text']); + break; + + default: + // unknown compression method + break; + } + + if (isset($ThisFileInfo['png'][$chunk['type_text']]['text'])) { + $ThisFileInfo['png']['comments'][$ThisFileInfo['png'][$chunk['type_text']]['keyword']][] = $ThisFileInfo['png'][$chunk['type_text']]['text']; + } + break; + + + case 'iTXt': // International Textual Data + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + list($keyword, $otherdata) = explode(chr(0x00), $ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2); + $ThisFileInfo['png'][$chunk['type_text']]['keyword'] = $keyword; + $ThisFileInfo['png'][$chunk['type_text']]['compression'] = (bool) BigEndian2Int(substr($otherdata, 0, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['compression_method'] = BigEndian2Int(substr($otherdata, 1, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['compression_method_text'] = PNGcompressionMethodLookup($ThisFileInfo['png'][$chunk['type_text']]['compression_method']); + list($languagetag, $translatedkeyword, $text) = explode(chr(0x00), substr($otherdata, 2), 3); + $ThisFileInfo['png'][$chunk['type_text']]['language_tag'] = $languagetag; + $ThisFileInfo['png'][$chunk['type_text']]['translated_keyword'] = utf8_decode($translatedkeyword); + + if ($ThisFileInfo['png'][$chunk['type_text']]['compression']) { + + switch ($ThisFileInfo['png'][$chunk['type_text']]['compression_method']) { + case 0: + $ThisFileInfo['png'][$chunk['type_text']]['text'] = utf8_decode(gzuncompress($text)); + break; + + default: + // unknown compression method + break; + } + + } else { + + $ThisFileInfo['png'][$chunk['type_text']]['text'] = utf8_decode($text); + + } + + if (isset($ThisFileInfo['png'][$chunk['type_text']]['text'])) { + $ThisFileInfo['png']['comments'][$ThisFileInfo['png'][$chunk['type_text']]['keyword']][] = $ThisFileInfo['png'][$chunk['type_text']]['text']; + } + break; + + + case 'bKGD': // Background Color + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + switch ($ThisFileInfo['png']['IHDR']['raw']['color_type']) { + case 0: + case 4: + $ThisFileInfo['png'][$chunk['type_text']]['background_gray'] = BigEndian2Int($ThisFileInfo['png'][$chunk['type_text']]['header']['data']); + break; + + case 2: + case 6: + $ThisFileInfo['png'][$chunk['type_text']]['background_red'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0 * $ThisFileInfo['png']['IHDR']['raw']['bit_depth'], $ThisFileInfo['png']['IHDR']['raw']['bit_depth'])); + $ThisFileInfo['png'][$chunk['type_text']]['background_green'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 1 * $ThisFileInfo['png']['IHDR']['raw']['bit_depth'], $ThisFileInfo['png']['IHDR']['raw']['bit_depth'])); + $ThisFileInfo['png'][$chunk['type_text']]['background_blue'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2 * $ThisFileInfo['png']['IHDR']['raw']['bit_depth'], $ThisFileInfo['png']['IHDR']['raw']['bit_depth'])); + break; + + case 3: + $ThisFileInfo['png'][$chunk['type_text']]['background_index'] = BigEndian2Int($ThisFileInfo['png'][$chunk['type_text']]['header']['data']); + break; + + default: + break; + } + break; + + + case 'pHYs': // Physical Pixel Dimensions + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $ThisFileInfo['png'][$chunk['type_text']]['pixels_per_unit_x'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 4)); + $ThisFileInfo['png'][$chunk['type_text']]['pixels_per_unit_y'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 4, 4)); + $ThisFileInfo['png'][$chunk['type_text']]['unit_specifier'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 8, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['unit'] = PNGpHYsUnitLookup($ThisFileInfo['png'][$chunk['type_text']]['unit_specifier']); + break; + + + case 'sBIT': // Significant Bits + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + switch ($ThisFileInfo['png']['IHDR']['raw']['color_type']) { + case 0: + $ThisFileInfo['png'][$chunk['type_text']]['significant_bits_gray'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 1)); + break; + + case 2: + case 3: + $ThisFileInfo['png'][$chunk['type_text']]['significant_bits_red'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['significant_bits_green'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 1, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['significant_bits_blue'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2, 1)); + break; + + case 4: + $ThisFileInfo['png'][$chunk['type_text']]['significant_bits_gray'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['significant_bits_alpha'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 1, 1)); + break; + + case 6: + $ThisFileInfo['png'][$chunk['type_text']]['significant_bits_red'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['significant_bits_green'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 1, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['significant_bits_blue'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['significant_bits_alpha'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 3, 1)); + break; + + default: + break; + } + break; + + + case 'sPLT': // Suggested Palette + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + list($palettename, $otherdata) = explode(chr(0x00), $ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2); + $ThisFileInfo['png'][$chunk['type_text']]['palette_name'] = $palettename; + $sPLToffset = 0; + $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bits'] = BigEndian2Int(substr($otherdata, $sPLToffset, 1)); + $sPLToffset += 1; + $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bytes'] = $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bits'] / 8; + $paletteCounter = 0; + while ($sPLToffset < strlen($otherdata)) { + $ThisFileInfo['png'][$chunk['type_text']]['red'][$paletteCounter] = BigEndian2Int(substr($otherdata, $sPLToffset, $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bytes'])); + $sPLToffset += $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bytes']; + $ThisFileInfo['png'][$chunk['type_text']]['green'][$paletteCounter] = BigEndian2Int(substr($otherdata, $sPLToffset, $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bytes'])); + $sPLToffset += $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bytes']; + $ThisFileInfo['png'][$chunk['type_text']]['blue'][$paletteCounter] = BigEndian2Int(substr($otherdata, $sPLToffset, $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bytes'])); + $sPLToffset += $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bytes']; + $ThisFileInfo['png'][$chunk['type_text']]['alpha'][$paletteCounter] = BigEndian2Int(substr($otherdata, $sPLToffset, $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bytes'])); + $sPLToffset += $ThisFileInfo['png'][$chunk['type_text']]['sample_depth_bytes']; + $ThisFileInfo['png'][$chunk['type_text']]['frequency'][$paletteCounter] = BigEndian2Int(substr($otherdata, $sPLToffset, 2)); + $sPLToffset += 2; + $paletteCounter++; + } + break; + + + case 'hIST': // Palette Histogram + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $hISTcounter = 0; + while ($hISTcounter < strlen($ThisFileInfo['png'][$chunk['type_text']]['header']['data'])) { + $ThisFileInfo['png'][$chunk['type_text']][$hISTcounter] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $hISTcounter / 2, 2)); + $hISTcounter += 2; + } + break; + + + case 'tIME': // Image Last-Modification Time + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $ThisFileInfo['png'][$chunk['type_text']]['year'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 2)); + $ThisFileInfo['png'][$chunk['type_text']]['month'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['day'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 3, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['hour'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 4, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['minute'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 5, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['second'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 6, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['unix'] = gmmktime($ThisFileInfo['png'][$chunk['type_text']]['hour'], $ThisFileInfo['png'][$chunk['type_text']]['minute'], $ThisFileInfo['png'][$chunk['type_text']]['second'], $ThisFileInfo['png'][$chunk['type_text']]['month'], $ThisFileInfo['png'][$chunk['type_text']]['day'], $ThisFileInfo['png'][$chunk['type_text']]['year']); + break; + + + case 'oFFs': // Image Offset + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $ThisFileInfo['png'][$chunk['type_text']]['position_x'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 4), false, true); + $ThisFileInfo['png'][$chunk['type_text']]['position_y'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 4, 4), false, true); + $ThisFileInfo['png'][$chunk['type_text']]['unit_specifier'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 8, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['unit'] = PNGoFFsUnitLookup($ThisFileInfo['png'][$chunk['type_text']]['unit_specifier']); + break; + + + case 'pCAL': // Calibration Of Pixel Values + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + list($calibrationname, $otherdata) = explode(chr(0x00), $ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2); + $ThisFileInfo['png'][$chunk['type_text']]['calibration_name'] = $calibrationname; + $pCALoffset = 0; + $ThisFileInfo['png'][$chunk['type_text']]['original_zero'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $pCALoffset, 4), false, true); + $pCALoffset += 4; + $ThisFileInfo['png'][$chunk['type_text']]['original_max'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $pCALoffset, 4), false, true); + $pCALoffset += 4; + $ThisFileInfo['png'][$chunk['type_text']]['equation_type'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $pCALoffset, 1)); + $pCALoffset += 1; + $ThisFileInfo['png'][$chunk['type_text']]['equation_type_text'] = PNGpCALequationTypeLookup($ThisFileInfo['png'][$chunk['type_text']]['equation_type']); + $ThisFileInfo['png'][$chunk['type_text']]['parameter_count'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $pCALoffset, 1)); + $pCALoffset += 1; + $ThisFileInfo['png'][$chunk['type_text']]['parameters'] = explode(chr(0x00), substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], $pCALoffset)); + break; + + + case 'sCAL': // Physical Scale Of Image Subject + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $ThisFileInfo['png'][$chunk['type_text']]['unit_specifier'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 1)); + $ThisFileInfo['png'][$chunk['type_text']]['unit'] = PNGsCALUnitLookup($ThisFileInfo['png'][$chunk['type_text']]['unit_specifier']); + list($pixelwidth, $pixelheight) = explode(chr(0x00), substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 1)); + $ThisFileInfo['png'][$chunk['type_text']]['pixel_width'] = $pixelwidth; + $ThisFileInfo['png'][$chunk['type_text']]['pixel_height'] = $pixelheight; + break; + + + case 'gIFg': // GIF Graphic Control Extension + $gIFgCounter = 0; + if (isset($ThisFileInfo['png'][$chunk['type_text']]) && is_array($ThisFileInfo['png'][$chunk['type_text']])) { + $gIFgCounter = count($ThisFileInfo['png'][$chunk['type_text']]); + } + $ThisFileInfo['png'][$chunk['type_text']][$gIFgCounter]['header'] = $chunk; + $ThisFileInfo['png'][$chunk['type_text']][$gIFgCounter]['disposal_method'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 1)); + $ThisFileInfo['png'][$chunk['type_text']][$gIFgCounter]['user_input_flag'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 1, 1)); + $ThisFileInfo['png'][$chunk['type_text']][$gIFgCounter]['delay_time'] = BigEndian2Int(substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 2, 2)); + break; + + + case 'gIFx': // GIF Application Extension + $gIFxCounter = 0; + if (isset($ThisFileInfo['png'][$chunk['type_text']]) && is_array($ThisFileInfo['png'][$chunk['type_text']])) { + $gIFxCounter = count($ThisFileInfo['png'][$chunk['type_text']]); + } + $ThisFileInfo['png'][$chunk['type_text']][$gIFxCounter]['header'] = $chunk; + $ThisFileInfo['png'][$chunk['type_text']][$gIFxCounter]['application_identifier'] = substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 0, 8); + $ThisFileInfo['png'][$chunk['type_text']][$gIFxCounter]['authentication_code'] = substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 8, 3); + $ThisFileInfo['png'][$chunk['type_text']][$gIFxCounter]['application_data'] = substr($ThisFileInfo['png'][$chunk['type_text']]['header']['data'], 11); + break; + + + case 'IDAT': // Image Data + $idatinformationfieldindex = 0; + if (isset($ThisFileInfo['png']['IDAT']) && is_array($ThisFileInfo['png']['IDAT'])) { + $idatinformationfieldindex = count($ThisFileInfo['png']['IDAT']); + } + unset($chunk['data']); + $ThisFileInfo['png'][$chunk['type_text']][$idatinformationfieldindex]['header'] = $chunk; + break; + + + case 'IEND': // Image Trailer + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + break; + + + default: + //unset($chunk['data']); + $ThisFileInfo['png'][$chunk['type_text']]['header'] = $chunk; + $ThisFileInfo['warning'] .= "\n".'Unhandled chunk type: '.$chunk['type_text']; + break; + } + } + + // PNG tags have highest priority + if (!empty($ThisFileInfo['png']['comments'])) { + CopyFormatCommentsToRootComments($ThisFileInfo['png']['comments'], $ThisFileInfo, true, true, true); + + // add tag to array of tags + $ThisFileInfo['tags'][] = 'png'; + } + + return true; +} + +function PNGsRGBintentLookup($sRGB) { + static $PNGsRGBintentLookup = array(); + if (empty($PNGsRGBintentLookup)) { + $PNGsRGBintentLookup[0] = 'Perceptual'; + $PNGsRGBintentLookup[1] = 'Relative colorimetric'; + $PNGsRGBintentLookup[2] = 'Saturation'; + $PNGsRGBintentLookup[3] = 'Absolute colorimetric'; + } + return (isset($PNGsRGBintentLookup[$sRGB]) ? $PNGsRGBintentLookup[$sRGB] : 'invalid'); +} + +function PNGcompressionMethodLookup($compressionmethod) { + static $PNGcompressionMethodLookup = array(); + if (empty($PNGcompressionMethodLookup)) { + $PNGcompressionMethodLookup[0] = 'deflate/inflate'; + } + return (isset($PNGcompressionMethodLookup[$compressionmethod]) ? $PNGcompressionMethodLookup[$compressionmethod] : 'invalid'); +} + +function PNGpHYsUnitLookup($unitid) { + static $PNGpHYsUnitLookup = array(); + if (empty($PNGpHYsUnitLookup)) { + $PNGpHYsUnitLookup[0] = 'unknown'; + $PNGpHYsUnitLookup[1] = 'meter'; + } + return (isset($PNGpHYsUnitLookup[$unitid]) ? $PNGpHYsUnitLookup[$unitid] : 'invalid'); +} + +function PNGoFFsUnitLookup($unitid) { + static $PNGoFFsUnitLookup = array(); + if (empty($PNGoFFsUnitLookup)) { + $PNGoFFsUnitLookup[0] = 'pixel'; + $PNGoFFsUnitLookup[1] = 'micrometer'; + } + return (isset($PNGoFFsUnitLookup[$unitid]) ? $PNGoFFsUnitLookup[$unitid] : 'invalid'); +} + +function PNGpCALequationTypeLookup($equationtype) { + static $PNGpCALequationTypeLookup = array(); + if (empty($PNGpCALequationTypeLookup)) { + $PNGpCALequationTypeLookup[0] = 'Linear mapping'; + $PNGpCALequationTypeLookup[1] = 'Base-e exponential mapping'; + $PNGpCALequationTypeLookup[2] = 'Arbitrary-base exponential mapping'; + $PNGpCALequationTypeLookup[3] = 'Hyperbolic mapping'; + } + return (isset($PNGpCALequationTypeLookup[$equationtype]) ? $PNGpCALequationTypeLookup[$equationtype] : 'invalid'); +} + +function PNGsCALUnitLookup($unitid) { + static $PNGsCALUnitLookup = array(); + if (empty($PNGsCALUnitLookup)) { + $PNGsCALUnitLookup[0] = 'meter'; + $PNGsCALUnitLookup[1] = 'radian'; + } + return (isset($PNGsCALUnitLookup[$unitid]) ? $PNGsCALUnitLookup[$unitid] : 'invalid'); +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.putid3.php b/livesupport/modules/getid3/var/getid3.putid3.php new file mode 100644 index 000000000..c4d6f4efd --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.putid3.php @@ -0,0 +1,1938 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.putid3.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function GenerateID3v2TagFlags($majorversion=4, $Unsynchronisation=false, $Compression=false, $ExtendedHeader=false, $Experimental=false, $Footer=false) { + if ($majorversion == 4) { + // %abcd0000 + $flag = Bool2IntString($Unsynchronisation); // a - Unsynchronisation + $flag .= Bool2IntString($ExtendedHeader); // b - Extended header + $flag .= Bool2IntString($Experimental); // c - Experimental indicator + $flag .= Bool2IntString($Footer); // d - Footer present + $flag .= '0000'; + } elseif ($majorversion == 3) { + // %abc00000 + $flag = Bool2IntString($Unsynchronisation); // a - Unsynchronisation + $flag .= Bool2IntString($ExtendedHeader); // b - Extended header + $flag .= Bool2IntString($Experimental); // c - Experimental indicator + $flag .= '00000'; + } elseif ($majorversion == 2) { + // %ab000000 + $flag = Bool2IntString($Unsynchronisation); // a - Unsynchronisation + $flag .= Bool2IntString($Compression); // b - Compression + $flag .= '000000'; + } else { + return false; + } + return chr(bindec($flag)); +} + + +function GenerateID3v2FrameFlags($majorversion=4, $TagAlter=false, $FileAlter=false, $ReadOnly=false, $Compression=false, $Encryption=false, $GroupingIdentity=false, $Unsynchronisation=false, $DataLengthIndicator=false) { + if ($majorversion == 4) { + // %0abc0000 %0h00kmnp + + $flag1 = '0'; + $flag1 .= Bool2IntString($TagAlter); // a - Tag alter preservation (true == discard) + $flag1 .= Bool2IntString($FileAlter); // b - File alter preservation (true == discard) + $flag1 .= Bool2IntString($ReadOnly); // c - Read only (true == read only) + $flag1 .= '0000'; + + $flag2 = '0'; + $flag2 .= Bool2IntString($GroupingIdentity); // h - Grouping identity (true == contains group information) + $flag2 .= '00'; + $flag2 .= Bool2IntString($Compression); // k - Compression (true == compressed) + $flag2 .= Bool2IntString($Encryption); // m - Encryption (true == encrypted) + $flag2 .= Bool2IntString($Unsynchronisation); // n - Unsynchronisation (true == unsynchronised) + $flag2 .= Bool2IntString($DataLengthIndicator); // p - Data length indicator (true == data length indicator added) + + } elseif ($majorversion == 3) { + // %abc00000 %ijk00000 + + $flag1 = Bool2IntString($TagAlter); // a - Tag alter preservation (true == discard) + $flag1 .= Bool2IntString($FileAlter); // b - File alter preservation (true == discard) + $flag1 .= Bool2IntString($ReadOnly); // c - Read only (true == read only) + $flag1 .= '00000'; + + $flag2 = Bool2IntString($Compression); // i - Compression (true == compressed) + $flag2 .= Bool2IntString($Encryption); // j - Encryption (true == encrypted) + $flag2 .= Bool2IntString($GroupingIdentity); // k - Grouping identity (true == contains group information) + $flag2 .= '00000'; + + } else { + return false; + } + return chr(bindec($flag1)).chr(bindec($flag2)); +} + +function GenerateID3v2FrameData($frame_name, $frame_data, $majorversion=4, $showerrors=false) { + if (!IsValidID3v2FrameName($frame_name, $majorversion)) { + return false; + } + $error = ''; + $framedata = ''; + require_once(GETID3_INCLUDEPATH.'getid3.frames.php'); + + if ($majorversion == 2) { + ksort($frame_data); + reset($frame_data); + switch ($frame_name) { + case 'TXX': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'WXX': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'IPL': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'MCI': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'ETC': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'MLL': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'STC': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'ULT': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'SLT': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'COM': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'RVA': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'EQU': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'REV': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'PIC': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'GEO': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'CNT': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'POP': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'BUF': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'CRM': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'CRA': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + case 'LNK': + $error .= $frame_name.' not yet supported in putid3.php
'; + break; + default: + if ($frame_name{0} == 'T') { + // T?? + $error .= $frame_name.' not yet supported in putid3.php
'; + } elseif ($frame_name{0} == 'W') { + // W?? + $error .= $frame_name.' not yet supported in putid3.php
'; + } else { + $error .= $frame_name.' not yet supported in putid3.php
'; + return false; + } + } + } else { // $majorversion > 2 + switch ($frame_name) { + case 'UFID': + // 4.1 UFID Unique file identifier + // Owner identifier $00 + // Identifier + if (strlen($frame_data['data']) > 64) { + $error .= 'Identifier not allowed to be longer than 64 bytes in '.$frame_name.' (supplied data was '.strlen($frame_data['data']).' bytes long)
'; + } else { + $framedata .= str_replace(chr(0), '', $frame_data['ownerid']).chr(0); + $framedata .= substr($frame_data['data'], 0, 64); // max 64 bytes - truncate anything longer + } + break; + case 'TXXX': + // 4.2.2 TXXX User defined text information frame + // Text encoding $xx + // Description $00 (00) + // Value + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].') for ID3v2.'.$majorversion.'
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= $frame_data['description'].TextEncodingLookup('terminator', $frame_data['encodingid']); + $framedata .= $frame_data['data']; + } + break; + case 'WXXX': + // 4.3.2 WXXX User defined URL link frame + // Text encoding $xx + // Description $00 (00) + // URL + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].') for ID3v2.'.$majorversion.'
'; + } elseif (!isset($frame_data['url']) || !IsValidURL($frame_data['url'], false, false)) { + $error .= 'Invalid URL in '.$frame_name.' ('.$frame_data['url'].')
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= $frame_data['description'].TextEncodingLookup('terminator', $frame_data['encodingid']); + $framedata .= $frame_data['url']; + } + break; + case 'IPLS': + // 4.4 IPLS Involved people list (ID3v2.3 only) + // Text encoding $xx + // People list strings + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].') for ID3v2.'.$majorversion.'
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= $frame_data['data']; + } + break; + case 'MCDI': + // 4.4 MCDI Music CD identifier + // CD TOC + $framedata .= $frame_data['data']; + break; + case 'ETCO': + // 4.5 ETCO Event timing codes + // Time stamp format $xx + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Followed by a list of key events in the following format: + // Type of event $xx + // Time stamp $xx (xx ...) + // The 'Time stamp' is set to zero if directly at the beginning of the sound + // or after the previous event. All events MUST be sorted in chronological order. + if (($frame_data['timestampformat'] > 2) || ($frame_data['timestampformat'] < 1)) { + $error .= 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$frame_data['timestampformat'].')
'; + } else { + $framedata .= chr($frame_data['timestampformat']); + foreach ($frame_data as $key => $val) { + if (!IsValidETCOevent($val['typeid'], $majorversion)) { + $error .= 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')
'; + } elseif (($key != 'timestampformat') && ($key != 'flags')) { + if (($val['timestamp'] > 0) && ($previousETCOtimestamp >= $val['timestamp'])) { + // The 'Time stamp' is set to zero if directly at the beginning of the sound + // or after the previous event. All events MUST be sorted in chronological order. + $error .= 'Out-of-order timestamp in '.$frame_name.' ('.$val['timestamp'].') for Event Type ('.$val['typeid'].')
'; + } else { + $framedata .= chr($val['typeid']); + $framedata .= BigEndian2String($val['timestamp'], 4, false); + } + } + } + } + break; + case 'MLLT': + // 4.6 MLLT MPEG location lookup table + // MPEG frames between reference $xx xx + // Bytes between reference $xx xx xx + // Milliseconds between reference $xx xx xx + // Bits for bytes deviation $xx + // Bits for milliseconds dev. $xx + // Then for every reference the following data is included; + // Deviation in bytes %xxx.... + // Deviation in milliseconds %xxx.... + if (($frame_data['framesbetweenreferences'] > 0) && ($frame_data['framesbetweenreferences'] <= 65535)) { + $framedata .= BigEndian2String($frame_data['framesbetweenreferences'], 2, false); + } else { + $error .= 'Invalid MPEG Frames Between References in '.$frame_name.' ('.$frame_data['framesbetweenreferences'].')
'; + } + if (($frame_data['bytesbetweenreferences'] > 0) && ($frame_data['bytesbetweenreferences'] <= 16777215)) { + $framedata .= BigEndian2String($frame_data['bytesbetweenreferences'], 3, false); + } else { + $error .= 'Invalid bytes Between References in '.$frame_name.' ('.$frame_data['bytesbetweenreferences'].')
'; + } + if (($frame_data['msbetweenreferences'] > 0) && ($frame_data['msbetweenreferences'] <= 16777215)) { + $framedata .= BigEndian2String($frame_data['msbetweenreferences'], 3, false); + } else { + $error .= 'Invalid Milliseconds Between References in '.$frame_name.' ('.$frame_data['msbetweenreferences'].')
'; + } + if (!IsWithinBitRange($frame_data['bitsforbytesdeviation'], 8, false)) { + if (($frame_data['bitsforbytesdeviation'] % 4) == 0) { + $framedata .= chr($frame_data['bitsforbytesdeviation']); + } else { + $error .= 'Bits For Bytes Deviation in '.$frame_name.' ('.$frame_data['bitsforbytesdeviation'].') must be a multiple of 4.
'; + } + } else { + $error .= 'Invalid Bits For Bytes Deviation in '.$frame_name.' ('.$frame_data['bitsforbytesdeviation'].')
'; + } + if (!IsWithinBitRange($frame_data['bitsformsdeviation'], 8, false)) { + if (($frame_data['bitsformsdeviation'] % 4) == 0) { + $framedata .= chr($frame_data['bitsformsdeviation']); + } else { + $error .= 'Bits For Milliseconds Deviation in '.$frame_name.' ('.$frame_data['bitsforbytesdeviation'].') must be a multiple of 4.
'; + } + } else { + $error .= 'Invalid Bits For Milliseconds Deviation in '.$frame_name.' ('.$frame_data['bitsformsdeviation'].')
'; + } + foreach ($frame_data as $key => $val) { + if (($key != 'framesbetweenreferences') && ($key != 'bytesbetweenreferences') && ($key != 'msbetweenreferences') && ($key != 'bitsforbytesdeviation') && ($key != 'bitsformsdeviation') && ($key != 'flags')) { + $unwrittenbitstream .= str_pad(Dec2Bin($val['bytedeviation']), $frame_data['bitsforbytesdeviation'], '0', STR_PAD_LEFT); + $unwrittenbitstream .= str_pad(Dec2Bin($val['msdeviation']), $frame_data['bitsformsdeviation'], '0', STR_PAD_LEFT); + } + } + for ($i=0;$i + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + if (($frame_data['timestampformat'] > 2) || ($frame_data['timestampformat'] < 1)) { + $error .= 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$frame_data['timestampformat'].')
'; + } else { + $framedata .= chr($frame_data['timestampformat']); + foreach ($frame_data as $key => $val) { + if (!IsValidETCOevent($val['typeid'], $majorversion)) { + $error .= 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')
'; + } elseif (($key != 'timestampformat') && ($key != 'flags')) { + if (($val['tempo'] < 0) || ($val['tempo'] > 510)) { + $error .= 'Invalid Tempo (max = 510) in '.$frame_name.' ('.$val['tempo'].') at timestamp ('.$val['timestamp'].')
'; + } else { + if ($val['tempo'] > 255) { + $framedata .= chr(255); + $val['tempo'] -= 255; + } + $framedata .= chr($val['tempo']); + $framedata .= BigEndian2String($val['timestamp'], 4, false); + } + } + } + } + break; + case 'USLT': + // 4.8 USLT Unsynchronised lyric/text transcription + // Text encoding $xx + // Language $xx xx xx + // Content descriptor $00 (00) + // Lyrics/text + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].') for ID3v2.'.$majorversion.'
'; + } elseif (LanguageLookup($frame_data['language'], true) == '') { + $error .= 'Invalid Language in '.$frame_name.' ('.$frame_data['language'].')
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= strtolower($frame_data['language']); + $framedata .= $frame_data['description'].TextEncodingLookup('terminator', $frame_data['encodingid']); + $framedata .= $frame_data['data']; + } + break; + case 'SYLT': + // 4.9 SYLT Synchronised lyric/text + // Text encoding $xx + // Language $xx xx xx + // Time stamp format $xx + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Content type $xx + // Content descriptor $00 (00) + // Terminated text to be synced (typically a syllable) + // Sync identifier (terminator to above string) $00 (00) + // Time stamp $xx (xx ...) + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].') for ID3v2.'.$majorversion.'
'; + } elseif (LanguageLookup($frame_data['language'], true) == '') { + $error .= 'Invalid Language in '.$frame_name.' ('.$frame_data['language'].')
'; + } elseif (($frame_data['timestampformat'] > 2) || ($frame_data['timestampformat'] < 1)) { + $error .= 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$frame_data['timestampformat'].')
'; + } elseif (!IsValidSYLTtype($frame_data['contenttypeid'], $majorversion)) { + $error .= 'Invalid Content Type byte in '.$frame_name.' ('.$frame_data['contenttypeid'].')
'; + } elseif (!is_array($frame_data['data'])) { + $error .= 'Invalid Lyric/Timestamp data in '.$frame_name.' (must be an array)
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= strtolower($frame_data['language']); + $framedata .= chr($frame_data['timestampformat']); + $framedata .= chr($frame_data['contenttypeid']); + $framedata .= $frame_data['description'].TextEncodingLookup('terminator', $frame_data['encodingid']); + ksort($frame_data['data']); + foreach ($frame_data['data'] as $key => $val) { + $framedata .= $val['data'].TextEncodingLookup('terminator', $frame_data['encodingid']); + $framedata .= BigEndian2String($val['timestamp'], 4, false); + } + } + break; + case 'COMM': + // 4.10 COMM Comments + // Text encoding $xx + // Language $xx xx xx + // Short content descrip. $00 (00) + // The actual text + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].') for ID3v2.'.$majorversion.'
'; + } elseif (LanguageLookup($frame_data['language'], true) == '') { + $error .= 'Invalid Language in '.$frame_name.' ('.$frame_data['language'].')
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= strtolower($frame_data['language']); + $framedata .= $frame_data['description'].TextEncodingLookup('terminator', $frame_data['encodingid']); + $framedata .= $frame_data['data']; + } + break; + case 'RVA2': + // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only) + // Identification $00 + // The 'identification' string is used to identify the situation and/or + // device where this adjustment should apply. The following is then + // repeated for every channel: + // Type of channel $xx + // Volume adjustment $xx xx + // Bits representing peak $xx + // Peak volume $xx (xx ...) + $framedata .= str_replace(chr(0), '', $frame_data['description']).chr(0); + foreach ($frame_data as $key => $val) { + if ($key != 'description') { + $framedata .= chr($val['channeltypeid']); + $framedata .= BigEndian2String($val['volumeadjust'], 2, false, true); // signed 16-bit + if (!IsWithinBitRange($frame_data['bitspeakvolume'], 8, false)) { + $framedata .= chr($val['bitspeakvolume']); + if ($val['bitspeakvolume'] > 0) { + $framedata .= BigEndian2String($val['peakvolume'], ceil($val['bitspeakvolume'] / 8), false, false); + } + } else { + $error .= 'Invalid Bits Representing Peak Volume in '.$frame_name.' ('.$val['bitspeakvolume'].') (range = 0 to 255)
'; + } + } + } + break; + case 'RVAD': + // 4.12 RVAD Relative volume adjustment (ID3v2.3 only) + // Increment/decrement %00fedcba + // Bits used for volume descr. $xx + // Relative volume change, right $xx xx (xx ...) // a + // Relative volume change, left $xx xx (xx ...) // b + // Peak volume right $xx xx (xx ...) + // Peak volume left $xx xx (xx ...) + // Relative volume change, right back $xx xx (xx ...) // c + // Relative volume change, left back $xx xx (xx ...) // d + // Peak volume right back $xx xx (xx ...) + // Peak volume left back $xx xx (xx ...) + // Relative volume change, center $xx xx (xx ...) // e + // Peak volume center $xx xx (xx ...) + // Relative volume change, bass $xx xx (xx ...) // f + // Peak volume bass $xx xx (xx ...) + if (!IsWithinBitRange($frame_data['bitsvolume'], 8, false)) { + $error .= 'Invalid Bits For Volume Description byte in '.$frame_name.' ('.$frame_data['bitsvolume'].') (range = 1 to 255)
'; + } else { + $incdecflag .= '00'; + $incdecflag .= Bool2IntString($frame_data['incdec']['right']); // a - Relative volume change, right + $incdecflag .= Bool2IntString($frame_data['incdec']['left']); // b - Relative volume change, left + $incdecflag .= Bool2IntString($frame_data['incdec']['rightrear']); // c - Relative volume change, right back + $incdecflag .= Bool2IntString($frame_data['incdec']['leftrear']); // d - Relative volume change, left back + $incdecflag .= Bool2IntString($frame_data['incdec']['center']); // e - Relative volume change, center + $incdecflag .= Bool2IntString($frame_data['incdec']['bass']); // f - Relative volume change, bass + $framedata .= chr(bindec($incdecflag)); + $framedata .= chr($frame_data['bitsvolume']); + $framedata .= BigEndian2String($frame_data['volumechange']['right'], ceil($frame_data['bitsvolume'] / 8), false); + $framedata .= BigEndian2String($frame_data['volumechange']['left'], ceil($frame_data['bitsvolume'] / 8), false); + $framedata .= BigEndian2String($frame_data['peakvolume']['right'], ceil($frame_data['bitsvolume'] / 8), false); + $framedata .= BigEndian2String($frame_data['peakvolume']['left'], ceil($frame_data['bitsvolume'] / 8), false); + if ($frame_data['volumechange']['rightrear'] || $frame_data['volumechange']['leftrear'] || + $frame_data['peakvolume']['rightrear'] || $frame_data['peakvolume']['leftrear'] || + $frame_data['volumechange']['center'] || $frame_data['peakvolume']['center'] || + $frame_data['volumechange']['bass'] || $frame_data['peakvolume']['bass']) { + $framedata .= BigEndian2String($frame_data['volumechange']['rightrear'], ceil($frame_data['bitsvolume']/8), false); + $framedata .= BigEndian2String($frame_data['volumechange']['leftrear'], ceil($frame_data['bitsvolume']/8), false); + $framedata .= BigEndian2String($frame_data['peakvolume']['rightrear'], ceil($frame_data['bitsvolume']/8), false); + $framedata .= BigEndian2String($frame_data['peakvolume']['leftrear'], ceil($frame_data['bitsvolume']/8), false); + } + if ($frame_data['volumechange']['center'] || $frame_data['peakvolume']['center'] || + $frame_data['volumechange']['bass'] || $frame_data['peakvolume']['bass']) { + $framedata .= BigEndian2String($frame_data['volumechange']['center'], ceil($frame_data['bitsvolume']/8), false); + $framedata .= BigEndian2String($frame_data['peakvolume']['center'], ceil($frame_data['bitsvolume']/8), false); + } + if ($frame_data['volumechange']['bass'] || $frame_data['peakvolume']['bass']) { + $framedata .= BigEndian2String($frame_data['volumechange']['bass'], ceil($frame_data['bitsvolume']/8), false); + $framedata .= BigEndian2String($frame_data['peakvolume']['bass'], ceil($frame_data['bitsvolume']/8), false); + } + } + break; + case 'EQU2': + // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only) + // Interpolation method $xx + // $00 Band + // $01 Linear + // Identification $00 + // The following is then repeated for every adjustment point + // Frequency $xx xx + // Volume adjustment $xx xx + if (($frame_data['interpolationmethod'] < 0) || ($frame_data['interpolationmethod'] > 1)) { + $error .= 'Invalid Interpolation Method byte in '.$frame_name.' ('.$frame_data['interpolationmethod'].') (valid = 0 or 1)
'; + } else { + $framedata .= chr($frame_data['interpolationmethod']); + $framedata .= str_replace(chr(0), '', $frame_data['description']).chr(0); + foreach ($frame_data['data'] as $key => $val) { + $framedata .= BigEndian2String(round($key * 2), 2, false); + $framedata .= BigEndian2String($val, 2, false, true); // signed 16-bit + } + } + break; + case 'EQUA': + // 4.12 EQUA Equalisation (ID3v2.3 only) + // Adjustment bits $xx + // This is followed by 2 bytes + ('adjustment bits' rounded up to the + // nearest byte) for every equalisation band in the following format, + // giving a frequency range of 0 - 32767Hz: + // Increment/decrement %x (MSB of the Frequency) + // Frequency (lower 15 bits) + // Adjustment $xx (xx ...) + if (!IsWithinBitRange($frame_data['bitsvolume'], 8, false)) { + $error .= 'Invalid Adjustment Bits byte in '.$frame_name.' ('.$frame_data['bitsvolume'].') (range = 1 to 255)
'; + } else { + $framedata .= chr($frame_data['adjustmentbits']); + foreach ($frame_data as $key => $val) { + if ($key != 'bitsvolume') { + if (($key > 32767) || ($key < 0)) { + $error .= 'Invalid Frequency in '.$frame_name.' ('.$key.') (range = 0 to 32767)
'; + } else { + if ($val >= 0) { + // put MSB of frequency to 1 if increment, 0 if decrement + $key |= 0x8000; + } + $framedata .= BigEndian2String($key, 2, false); + $framedata .= BigEndian2String($val, ceil($frame_data['adjustmentbits'] / 8), false); + } + } + } + } + break; + case 'RVRB': + // 4.13 RVRB Reverb + // Reverb left (ms) $xx xx + // Reverb right (ms) $xx xx + // Reverb bounces, left $xx + // Reverb bounces, right $xx + // Reverb feedback, left to left $xx + // Reverb feedback, left to right $xx + // Reverb feedback, right to right $xx + // Reverb feedback, right to left $xx + // Premix left to right $xx + // Premix right to left $xx + if (!IsWithinBitRange($frame_data['left'], 16, false)) { + $error .= 'Invalid Reverb Left in '.$frame_name.' ('.$frame_data['left'].') (range = 0 to 65535)
'; + } elseif (!IsWithinBitRange($frame_data['right'], 16, false)) { + $error .= 'Invalid Reverb Left in '.$frame_name.' ('.$frame_data['right'].') (range = 0 to 65535)
'; + } elseif (!IsWithinBitRange($frame_data['bouncesL'], 8, false)) { + $error .= 'Invalid Reverb Bounces, Left in '.$frame_name.' ('.$frame_data['bouncesL'].') (range = 0 to 255)
'; + } elseif (!IsWithinBitRange($frame_data['bouncesR'], 8, false)) { + $error .= 'Invalid Reverb Bounces, Right in '.$frame_name.' ('.$frame_data['bouncesR'].') (range = 0 to 255)
'; + } elseif (!IsWithinBitRange($frame_data['feedbackLL'], 8, false)) { + $error .= 'Invalid Reverb Feedback, Left-To-Left in '.$frame_name.' ('.$frame_data['feedbackLL'].') (range = 0 to 255)
'; + } elseif (!IsWithinBitRange($frame_data['feedbackLR'], 8, false)) { + $error .= 'Invalid Reverb Feedback, Left-To-Right in '.$frame_name.' ('.$frame_data['feedbackLR'].') (range = 0 to 255)
'; + } elseif (!IsWithinBitRange($frame_data['feedbackRR'], 8, false)) { + $error .= 'Invalid Reverb Feedback, Right-To-Right in '.$frame_name.' ('.$frame_data['feedbackRR'].') (range = 0 to 255)
'; + } elseif (!IsWithinBitRange($frame_data['feedbackRL'], 8, false)) { + $error .= 'Invalid Reverb Feedback, Right-To-Left in '.$frame_name.' ('.$frame_data['feedbackRL'].') (range = 0 to 255)
'; + } elseif (!IsWithinBitRange($frame_data['premixLR'], 8, false)) { + $error .= 'Invalid Premix, Left-To-Right in '.$frame_name.' ('.$frame_data['premixLR'].') (range = 0 to 255)
'; + } elseif (!IsWithinBitRange($frame_data['premixRL'], 8, false)) { + $error .= 'Invalid Premix, Right-To-Left in '.$frame_name.' ('.$frame_data['premixRL'].') (range = 0 to 255)
'; + } else { + $framedata .= BigEndian2String($frame_data['left'], 2, false); + $framedata .= BigEndian2String($frame_data['right'], 2, false); + $framedata .= chr($frame_data['bouncesL']); + $framedata .= chr($frame_data['bouncesR']); + $framedata .= chr($frame_data['feedbackLL']); + $framedata .= chr($frame_data['feedbackLR']); + $framedata .= chr($frame_data['feedbackRR']); + $framedata .= chr($frame_data['feedbackRL']); + $framedata .= chr($frame_data['premixLR']); + $framedata .= chr($frame_data['premixRL']); + } + break; + case 'APIC': + // 4.14 APIC Attached picture + // Text encoding $xx + // MIME type $00 + // Picture type $xx + // Description $00 (00) + // Picture data + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].') for ID3v2.'.$majorversion.'
'; + } elseif (!IsValidAPICpicturetype($frame_data['picturetypeid'], $majorversion)) { + $error .= 'Invalid Picture Type byte in '.$frame_name.' ('.$frame_data['picturetypeid'].') for ID3v2.'.$majorversion.'
'; + } elseif (($majorversion >= 3) && (!IsValidAPICimageformat($frame_data['mime'], $majorversion))) { + $error .= 'Invalid MIME Type in '.$frame_name.' ('.$frame_data['mime'].') for ID3v2.'.$majorversion.'
'; + } elseif (($frame_data['mime'] == '-->') && (!IsValidURL($frame_data['data'], false, false))) { + $error .= 'Invalid URL in '.$frame_name.' ('.$frame_data['data'].')
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= str_replace(chr(0), '', $frame_data['mime']).chr(0); + $framedata .= chr($frame_data['picturetypeid']); + $framedata .= $frame_data['description'].TextEncodingLookup('terminator', $frame_data['encodingid']); + $framedata .= $frame_data['data']; + } + break; + case 'GEOB': + // 4.15 GEOB General encapsulated object + // Text encoding $xx + // MIME type $00 + // Filename $00 (00) + // Content description $00 (00) + // Encapsulated object + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].') for ID3v2.'.$majorversion.'
'; + } elseif (!IsValidMIMEstring($frame_data['mime'])) { + $error .= 'Invalid MIME Type in '.$frame_name.' ('.$frame_data['mime'].')
'; + } elseif (!$frame_data['description']) { + $error .= 'Missing Description in '.$frame_name.'
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= str_replace(chr(0), '', $frame_data['mime']).chr(0); + $framedata .= $frame_data['filename'].TextEncodingLookup('terminator', $frame_data['encodingid']); + $framedata .= $frame_data['description'].TextEncodingLookup('terminator', $frame_data['encodingid']); + $framedata .= $frame_data['data']; + } + break; + case 'PCNT': + // 4.16 PCNT Play counter + // When the counter reaches all one's, one byte is inserted in + // front of the counter thus making the counter eight bits bigger + // Counter $xx xx xx xx (xx ...) + $framedata .= BigEndian2String($frame_data['data'], 4, false); + break; + case 'POPM': + // 4.17 POPM Popularimeter + // When the counter reaches all one's, one byte is inserted in + // front of the counter thus making the counter eight bits bigger + // Email to user $00 + // Rating $xx + // Counter $xx xx xx xx (xx ...) + if (!IsWithinBitRange($frame_data['rating'], 8, false)) { + $error .= 'Invalid Rating byte in '.$frame_name.' ('.$frame_data['rating'].') (range = 0 to 255)
'; + } elseif (!IsValidEmail($frame_data['email'])) { + $error .= 'Invalid Email in '.$frame_name.' ('.$frame_data['email'].')
'; + } else { + $framedata .= str_replace(chr(0), '', $frame_data['email']).chr(0); + $framedata .= chr($frame_data['rating']); + $framedata .= BigEndian2String($frame_data['data'], 4, false); + } + break; + case 'RBUF': + // 4.18 RBUF Recommended buffer size + // Buffer size $xx xx xx + // Embedded info flag %0000000x + // Offset to next tag $xx xx xx xx + if (!IsWithinBitRange($frame_data['buffersize'], 24, false)) { + $error .= 'Invalid Buffer Size in '.$frame_name.'
'; + } elseif (!IsWithinBitRange($frame_data['nexttagoffset'], 32, false)) { + $error .= 'Invalid Offset To Next Tag in '.$frame_name.'
'; + } else { + $framedata .= BigEndian2String($frame_data['buffersize'], 3, false); + $flag .= '0000000'; + $flag .= Bool2IntString($frame_data['flags']['embededinfo']); + $framedata .= chr(bindec($flag)); + $framedata .= BigEndian2String($frame_data['nexttagoffset'], 4, false); + } + break; + case 'AENC': + // 4.19 AENC Audio encryption + // Owner identifier $00 + // Preview start $xx xx + // Preview length $xx xx + // Encryption info + if (!IsWithinBitRange($frame_data['previewstart'], 16, false)) { + $error .= 'Invalid Preview Start in '.$frame_name.' ('.$frame_data['previewstart'].')
'; + } elseif (!IsWithinBitRange($frame_data['previewlength'], 16, false)) { + $error .= 'Invalid Preview Length in '.$frame_name.' ('.$frame_data['previewlength'].')
'; + } else { + $framedata .= str_replace(chr(0), '', $frame_data['ownerid']).chr(0); + $framedata .= BigEndian2String($frame_data['previewstart'], 2, false); + $framedata .= BigEndian2String($frame_data['previewlength'], 2, false); + $framedata .= $frame_data['encryptioninfo']; + } + break; + case 'LINK': + // 4.20 LINK Linked information + // Frame identifier $xx xx xx xx + // URL $00 + // ID and additional data + if (!IsValidID3v2FrameName($frame_data['frameid'], $majorversion)) { + $error .= 'Invalid Frame Identifier in '.$frame_name.' ('.$frame_data['frameid'].')
'; + } elseif (!IsValidURL($frame_data['url'], true, false)) { + $error .= 'Invalid URL in '.$frame_name.' ('.$frame_data['url'].')
'; + } elseif ((($frame_data['frameid'] == 'AENC') || ($frame_data['frameid'] == 'APIC') || ($frame_data['frameid'] == 'GEOB') || ($frame_data['frameid'] == 'TXXX')) && ($frame_data['additionaldata'] == '')) { + $error .= 'Content Descriptor must be specified as additional data for Frame Identifier of '.$frame_data['frameid'].' in '.$frame_name.'
'; + } elseif (($frame_data['frameid'] == 'USER') && (LanguageLookup($frame_data['additionaldata'], true) == '')) { + $error .= 'Language must be specified as additional data for Frame Identifier of '.$frame_data['frameid'].' in '.$frame_name.'
'; + } elseif (($frame_data['frameid'] == 'PRIV') && ($frame_data['additionaldata'] == '')) { + $error .= 'Owner Identifier must be specified as additional data for Frame Identifier of '.$frame_data['frameid'].' in '.$frame_name.'
'; + } elseif ((($frame_data['frameid'] == 'COMM') || ($frame_data['frameid'] == 'SYLT') || ($frame_data['frameid'] == 'USLT')) && ((LanguageLookup(substr($frame_data['additionaldata'], 0, 3), true) == '') || (substr($frame_data['additionaldata'], 3) == ''))) { + $error .= 'Language followed by Content Descriptor must be specified as additional data for Frame Identifier of '.$frame_data['frameid'].' in '.$frame_name.'
'; + } else { + $framedata .= $frame_data['frameid']; + $framedata .= str_replace(chr(0), '', $frame_data['url']).chr(0); + switch ($frame_data['frameid']) { + case 'COMM': + case 'SYLT': + case 'USLT': + case 'PRIV': + case 'USER': + case 'AENC': + case 'APIC': + case 'GEOB': + case 'TXXX': + $framedata .= $frame_data['additionaldata']; + break; + case 'ASPI': + case 'ETCO': + case 'EQU2': + case 'MCID': + case 'MLLT': + case 'OWNE': + case 'RVA2': + case 'RVRB': + case 'SYTC': + case 'IPLS': + case 'RVAD': + case 'EQUA': + // no additional data required + break; + case 'RBUF': + if ($majorversion == 3) { + // no additional data required + } else { + $error .= $frame_data['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$majorversion.')
'; + } + + default: + if ((substr($frame_data['frameid'], 0, 1) == 'T') || (substr($frame_data['frameid'], 0, 1) == 'W')) { + // no additional data required + } else { + $error .= $frame_data['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$majorversion.')
'; + } + break; + } + } + break; + case 'POSS': + // 4.21 POSS Position synchronisation frame (ID3v2.3+ only) + // Time stamp format $xx + // Position $xx (xx ...) + if (($frame_data['timestampformat'] < 1) || ($frame_data['timestampformat'] > 2)) { + $error .= 'Invalid Time Stamp Format in '.$frame_name.' ('.$frame_data['timestampformat'].') (valid = 1 or 2)
'; + } elseif (!IsWithinBitRange($frame_data['position'], 32, false)) { + $error .= 'Invalid Position in '.$frame_name.' ('.$frame_data['position'].') (range = 0 to 4294967295)
'; + } else { + $framedata .= chr($frame_data['timestampformat']); + $framedata .= BigEndian2String($frame_data['position'], 4, false); + } + break; + case 'USER': + // 4.22 USER Terms of use (ID3v2.3+ only) + // Text encoding $xx + // Language $xx xx xx + // The actual text + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].')
'; + } elseif (LanguageLookup($frame_data['language'], true) == '') { + $error .= 'Invalid Language in '.$frame_name.' ('.$frame_data['language'].')
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= strtolower($frame_data['language']); + $framedata .= $frame_data['data']; + } + break; + case 'OWNE': + // 4.23 OWNE Ownership frame (ID3v2.3+ only) + // Text encoding $xx + // Price paid $00 + // Date of purch. + // Seller + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].')
'; + } elseif (!IsANumber($frame_data['pricepaid']['value'], false)) { + $error .= 'Invalid Price Paid in '.$frame_name.' ('.$frame_data['pricepaid']['value'].')
'; + } elseif (!IsValidDateStampString($frame_data['purchasedate'])) { + $error .= 'Invalid Date Of Purchase in '.$frame_name.' ('.$frame_data['purchasedate'].') (format = YYYYMMDD)
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= str_replace(chr(0), '', $frame_data['pricepaid']['value']).chr(0); + $framedata .= $frame_data['purchasedate']; + $framedata .= $frame_data['seller']; + } + break; + case 'COMR': + // 4.24 COMR Commercial frame (ID3v2.3+ only) + // Text encoding $xx + // Price string $00 + // Valid until + // Contact URL $00 + // Received as $xx + // Name of seller $00 (00) + // Description $00 (00) + // Picture MIME type $00 + // Seller logo + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].')
'; + } elseif (!IsValidDateStampString($frame_data['pricevaliduntil'])) { + $error .= 'Invalid Valid Until date in '.$frame_name.' ('.$frame_data['pricevaliduntil'].') (format = YYYYMMDD)
'; + } elseif (!IsValidURL($frame_data['contacturl'], false, true)) { + $error .= 'Invalid Contact URL in '.$frame_name.' ('.$frame_data['contacturl'].') (allowed schemes: http, https, ftp, mailto)
'; + } elseif (!IsValidCOMRreceivedas($frame_data['receivedasid'], $majorversion)) { + $error .= 'Invalid Received As byte in '.$frame_name.' ('.$frame_data['contacturl'].') (range = 0 to 8)
'; + } elseif (!IsValidMIMEstring($frame_data['mime'])) { + $error .= 'Invalid MIME Type in '.$frame_name.' ('.$frame_data['mime'].')
'; + } else { + $framedata .= chr($frame_data['encodingid']); + unset($pricestring); + foreach ($frame_data['price'] as $key => $val) { + if (IsValidPriceString($key.$val['value'])) { + $pricestrings[] = $key.$val['value']; + } else { + $error .= 'Invalid Price String in '.$frame_name.' ('.$key.$val['value'].')
'; + } + } + $framedata .= implode('/', $pricestrings); + $framedata .= $frame_data['pricevaliduntil']; + $framedata .= str_replace(chr(0), '', $frame_data['contacturl']).chr(0); + $framedata .= chr($frame_data['receivedasid']); + $framedata .= $frame_data['sellername'].TextEncodingLookup('terminator', $frame_data['encodingid']); + $framedata .= $frame_data['description'].TextEncodingLookup('terminator', $frame_data['encodingid']); + $framedata .= $frame_data['mime'].chr(0); + $framedata .= $frame_data['logo']; + } + break; + case 'ENCR': + // 4.25 ENCR Encryption method registration (ID3v2.3+ only) + // Owner identifier $00 + // Method symbol $xx + // Encryption data + if (!IsWithinBitRange($frame_data['methodsymbol'], 8, false)) { + $error .= 'Invalid Group Symbol in '.$frame_name.' ('.$frame_data['methodsymbol'].') (range = 0 to 255)
'; + } else { + $framedata .= str_replace(chr(0), '', $frame_data['ownerid']).chr(0); + $framedata .= ord($frame_data['methodsymbol']); + $framedata .= $frame_data['data']; + } + break; + case 'GRID': + // 4.26 GRID Group identification registration (ID3v2.3+ only) + // Owner identifier $00 + // Group symbol $xx + // Group dependent data + if (!IsWithinBitRange($frame_data['groupsymbol'], 8, false)) { + $error .= 'Invalid Group Symbol in '.$frame_name.' ('.$frame_data['groupsymbol'].') (range = 0 to 255)
'; + } else { + $framedata .= str_replace(chr(0), '', $frame_data['ownerid']).chr(0); + $framedata .= ord($frame_data['groupsymbol']); + $framedata .= $frame_data['data']; + } + break; + case 'PRIV': + // 4.27 PRIV Private frame (ID3v2.3+ only) + // Owner identifier $00 + // The private data + $framedata .= str_replace(chr(0), '', $frame_data['ownerid']).chr(0); + $framedata .= $frame_data['data']; + break; + case 'SIGN': + // 4.28 SIGN Signature frame (ID3v2.4+ only) + // Group symbol $xx + // Signature + if (!IsWithinBitRange($frame_data['groupsymbol'], 8, false)) { + $error .= 'Invalid Group Symbol in '.$frame_name.' ('.$frame_data['groupsymbol'].') (range = 0 to 255)
'; + } else { + $framedata .= ord($frame_data['groupsymbol']); + $framedata .= $frame_data['data']; + } + break; + case 'SEEK': + // 4.29 SEEK Seek frame (ID3v2.4+ only) + // Minimum offset to next tag $xx xx xx xx + if (!IsWithinBitRange($frame_data['data'], 32, false)) { + $error .= 'Invalid Minimum Offset in '.$frame_name.' ('.$frame_data['data'].') (range = 0 to 4294967295)
'; + } else { + $framedata .= BigEndian2String($frame_data['data'], 4, false); + } + break; + case 'ASPI': + // 4.30 ASPI Audio seek point index (ID3v2.4+ only) + // Indexed data start (S) $xx xx xx xx + // Indexed data length (L) $xx xx xx xx + // Number of index points (N) $xx xx + // Bits per index point (b) $xx + // Then for every index point the following data is included: + // Fraction at index (Fi) $xx (xx) + if (!IsWithinBitRange($frame_data['datastart'], 32, false)) { + $error .= 'Invalid Indexed Data Start in '.$frame_name.' ('.$frame_data['datastart'].') (range = 0 to 4294967295)
'; + } elseif (!IsWithinBitRange($frame_data['datalength'], 32, false)) { + $error .= 'Invalid Indexed Data Length in '.$frame_name.' ('.$frame_data['datalength'].') (range = 0 to 4294967295)
'; + } elseif (!IsWithinBitRange($frame_data['indexpoints'], 16, false)) { + $error .= 'Invalid Number Of Index Points in '.$frame_name.' ('.$frame_data['indexpoints'].') (range = 0 to 65535)
'; + } elseif (!IsWithinBitRange($frame_data['bitsperpoint'], 8, false)) { + $error .= 'Invalid Bits Per Index Point in '.$frame_name.' ('.$frame_data['bitsperpoint'].') (range = 0 to 255)
'; + } elseif ($frame_data['indexpoints'] != count($frame_data['indexes'])) { + $error .= 'Number Of Index Points does not match actual supplied data in '.$frame_name.'
'; + } else { + $framedata .= BigEndian2String($frame_data['datastart'], 4, false); + $framedata .= BigEndian2String($frame_data['datalength'], 4, false); + $framedata .= BigEndian2String($frame_data['indexpoints'], 2, false); + $framedata .= BigEndian2String($frame_data['bitsperpoint'], 1, false); + foreach ($frame_data['indexes'] as $key => $val) { + $framedata .= BigEndian2String($val, ceil($frame_data['bitsperpoint'] / 8), false); + } + } + break; + case 'RGAD': + // RGAD Replay Gain Adjustment + // http://privatewww.essex.ac.uk/~djmrob/replaygain/ + // Peak Amplitude $xx $xx $xx $xx + // Radio Replay Gain Adjustment %aaabbbcd %dddddddd + // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd + // a - name code + // b - originator code + // c - sign bit + // d - replay gain adjustment + + if (($frame_data['radio_adjustment'] > 51) || ($frame_data['radio_adjustment'] < -51)) { + $error .= 'Invalid Radio Adjustment in '.$frame_name.' ('.$frame_data['radio_adjustment'].') (range = -51.0 to +51.0)
'; + } elseif (($frame_data['audiophile_adjustment'] > 51) || ($frame_data['audiophile_adjustment'] < -51)) { + $error .= 'Invalid Audiophile Adjustment in '.$frame_name.' ('.$frame_data['audiophile_adjustment'].') (range = -51.0 to +51.0)
'; + } elseif (!IsValidRGADname($frame_data['raw']['radio_name'], $majorversion)) { + $error .= 'Invalid Radio Name Code in '.$frame_name.' ('.$frame_data['raw']['radio_name'].') (range = 0 to 2)
'; + } elseif (!IsValidRGADname($frame_data['raw']['audiophile_name'], $majorversion)) { + $error .= 'Invalid Audiophile Name Code in '.$frame_name.' ('.$frame_data['raw']['audiophile_name'].') (range = 0 to 2)
'; + } elseif (!IsValidRGADoriginator($frame_data['raw']['radio_originator'], $majorversion)) { + $error .= 'Invalid Radio Originator Code in '.$frame_name.' ('.$frame_data['raw']['radio_originator'].') (range = 0 to 3)
'; + } elseif (!IsValidRGADoriginator($frame_data['raw']['audiophile_originator'], $majorversion)) { + $error .= 'Invalid Audiophile Originator Code in '.$frame_name.' ('.$frame_data['raw']['audiophile_originator'].') (range = 0 to 3)
'; + } else { + $framedata .= Float2String($frame_data['peakamplitude'], 32); + $framedata .= RGADgainString($frame_data['raw']['radio_name'], $frame_data['raw']['radio_originator'], $frame_data['radio_adjustment']); + $framedata .= RGADgainString($frame_data['raw']['audiophile_name'], $frame_data['raw']['audiophile_originator'], $frame_data['audiophile_adjustment']); + } + break; + default: + if ($frame_name{0} == 'T') { + // 4.2. T??? Text information frames + // Text encoding $xx + // Information + if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) { + $error .= 'Invalid Text Encoding in '.$frame_name.' ('.$frame_data['encodingid'].') for ID3v2.'.$majorversion.'
'; + } else { + $framedata .= chr($frame_data['encodingid']); + $framedata .= $frame_data['data']; + } + } elseif ($frame_name{0} == 'W') { + // 4.3. W??? URL link frames + // URL + if (!IsValidURL($frame_data['url'], false, false)) { + $error .= 'Invalid URL in '.$frame_name.' ('.$frame_data['url'].')
'; + } else { + $framedata .= $frame_data['url']; + } + } else { + $error .= $frame_name.' not yet supported in putid3.php
'; + } + break; + } + } + if ($error) { + if ($showerrors) { + echo $error; + } + return false; + } else { + return $framedata; + } +} + +function ID3v2FrameIsAllowed($frame_name, $frame_data, $majorversion, $showerrors=false) { + static $PreviousFrames = array(); + $error = ''; + + if ($frame_name === null) { + // if the writing functions are called multiple times, the static array needs to be + // cleared - this can be done by calling ID3v2FrameIsAllowed(null, '', '') + $PreviousFrames = array(); + return true; + } + + if ($majorversion == 4) { + switch ($frame_name) { + case 'UFID': + case 'AENC': + case 'ENCR': + case 'GRID': + if (!isset($frame_data['ownerid'])) { + $error .= '[ownerid] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['ownerid'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$frame_data['ownerid'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['ownerid']; + } + break; + case 'TXXX': + case 'WXXX': + case 'RVA2': + case 'EQU2': + case 'APIC': + case 'GEOB': + if (!isset($frame_data['description'])) { + $error .= '[description] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['description'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Description ('.$frame_data['description'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['description']; + } + break; + case 'USER': + if (!isset($frame_data['language'])) { + $error .= '[language] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['language'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Language ('.$frame_data['language'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['language']; + } + break; + case 'USLT': + case 'SYLT': + case 'COMM': + if (!isset($frame_data['language'])) { + $error .= '[language] not specified for '.$frame_name.'
'; + } elseif (!isset($frame_data['description'])) { + $error .= '[description] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['language'].$frame_data['description'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$frame_data['language'].' + '.$frame_data['description'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['language'].$frame_data['description']; + } + break; + case 'POPM': + if (!isset($frame_data['email'])) { + $error .= '[email] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['email'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Email ('.$frame_data['email'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['email']; + } + break; + case 'IPLS': + case 'MCDI': + case 'ETCO': + case 'MLLT': + case 'SYTC': + case 'RVRB': + case 'PCNT': + case 'RBUF': + case 'POSS': + case 'OWNE': + case 'SEEK': + case 'ASPI': + case 'RGAD': + if (in_array($frame_name, $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed
'; + } else { + $PreviousFrames[] = $frame_name; + } + break; + case 'LINK': + // this isn't implemented quite right (yet) - it should check the target frame data for compliance + // but right now it just allows one linked frame of each type, to be safe. + if (!isset($frame_data['frameid'])) { + $error .= '[frameid] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['frameid'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$frame_data['frameid'].')
'; + } elseif (in_array($frame_data['frameid'], $PreviousFrames)) { + // no links to singleton tags + $error .= 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$frame_data['frameid'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['frameid']; // only one linked tag of this type + $PreviousFrames[] = $frame_data['frameid']; // no non-linked singleton tags of this type + } + break; + case 'COMR': + // There may be more than one 'commercial frame' in a tag, but no two may be identical + // Checking isn't implemented at all (yet) - just assumes that it's OK. + break; + case 'PRIV': + case 'SIGN': + if (!isset($frame_data['ownerid'])) { + $error .= '[ownerid] not specified for '.$frame_name.'
'; + } elseif (!isset($frame_data['data'])) { + $error .= '[data] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['ownerid'].$frame_data['data'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same OwnerID + Data ('.$frame_data['ownerid'].' + '.$frame_data['data'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['ownerid'].$frame_data['data']; + } + break; + default: + if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { + $error .= 'Frame not allowed in ID3v2.'.$majorversion.': '.$frame_name.'
'; + } + break; + } + } elseif ($majorversion == 3) { + switch ($frame_name) { + case 'UFID': + case 'AENC': + case 'ENCR': + case 'GRID': + if (!isset($frame_data['ownerid'])) { + $error .= '[ownerid] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['ownerid'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$frame_data['ownerid'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['ownerid']; + } + break; + case 'TXXX': + case 'WXXX': + case 'APIC': + case 'GEOB': + if (!isset($frame_data['description'])) { + $error .= '[description] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['description'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Description ('.$frame_data['description'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['description']; + } + break; + case 'USER': + if (!isset($frame_data['language'])) { + $error .= '[language] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['language'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Language ('.$frame_data['language'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['language']; + } + break; + case 'USLT': + case 'SYLT': + case 'COMM': + if (!isset($frame_data['language'])) { + $error .= '[language] not specified for '.$frame_name.'
'; + } elseif (!isset($frame_data['description'])) { + $error .= '[description] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['language'].$frame_data['description'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$frame_data['language'].' + '.$frame_data['description'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['language'].$frame_data['description']; + } + break; + case 'POPM': + if (!isset($frame_data['email'])) { + $error .= '[email] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['email'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Email ('.$frame_data['email'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['email']; + } + break; + case 'IPLS': + case 'MCDI': + case 'ETCO': + case 'MLLT': + case 'SYTC': + case 'RVAD': + case 'EQUA': + case 'RVRB': + case 'PCNT': + case 'RBUF': + case 'POSS': + case 'OWNE': + case 'RGAD': + if (in_array($frame_name, $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed
'; + } else { + $PreviousFrames[] = $frame_name; + } + break; + case 'LINK': + // this isn't implemented quite right (yet) - it should check the target frame data for compliance + // but right now it just allows one linked frame of each type, to be safe. + if (!isset($frame_data['frameid'])) { + $error .= '[frameid] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['frameid'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$frame_data['frameid'].')
'; + } elseif (in_array($frame_data['frameid'], $PreviousFrames)) { + // no links to singleton tags + $error .= 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$frame_data['frameid'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['frameid']; // only one linked tag of this type + $PreviousFrames[] = $frame_data['frameid']; // no non-linked singleton tags of this type + } + break; + case 'COMR': + // There may be more than one 'commercial frame' in a tag, but no two may be identical + // Checking isn't implemented at all (yet) - just assumes that it's OK. + break; + case 'PRIV': + if (!isset($frame_data['ownerid'])) { + $error .= '[ownerid] not specified for '.$frame_name.'
'; + } elseif (!isset($frame_data['data'])) { + $error .= '[data] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['ownerid'].$frame_data['data'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same OwnerID + Data ('.$frame_data['ownerid'].' + '.$frame_data['data'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['ownerid'].$frame_data['data']; + } + break; + default: + if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { + $error .= 'Frame not allowed in ID3v2.'.$majorversion.': '.$frame_name.'
'; + } + break; + } + } elseif ($majorversion == 2) { + switch ($frame_name) { + case 'UFI': + case 'CRM': + case 'CRA': + if (!isset($frame_data['ownerid'])) { + $error .= '[ownerid] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['ownerid'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$frame_data['ownerid'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['ownerid']; + } + break; + case 'TXX': + case 'WXX': + case 'PIC': + case 'GEO': + if (!isset($frame_data['description'])) { + $error .= '[description] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['description'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Description ('.$frame_data['description'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['description']; + } + break; + case 'ULT': + case 'SLT': + case 'COM': + if (!isset($frame_data['language'])) { + $error .= '[language] not specified for '.$frame_name.'
'; + } elseif (!isset($frame_data['description'])) { + $error .= '[description] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['language'].$frame_data['description'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$frame_data['language'].' + '.$frame_data['description'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['language'].$frame_data['description']; + } + break; + case 'POP': + if (!isset($frame_data['email'])) { + $error .= '[email] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['email'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same Email ('.$frame_data['email'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['email']; + } + break; + case 'IPL': + case 'MCI': + case 'ETC': + case 'MLL': + case 'STC': + case 'RVA': + case 'EQU': + case 'REV': + case 'CNT': + case 'BUF': + if (in_array($frame_name, $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed
'; + } else { + $PreviousFrames[] = $frame_name; + } + break; + case 'LNK': + // this isn't implemented quite right (yet) - it should check the target frame data for compliance + // but right now it just allows one linked frame of each type, to be safe. + if (!isset($frame_data['frameid'])) { + $error .= '[frameid] not specified for '.$frame_name.'
'; + } elseif (in_array($frame_name.$frame_data['frameid'], $PreviousFrames)) { + $error .= 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$frame_data['frameid'].')
'; + } elseif (in_array($frame_data['frameid'], $PreviousFrames)) { + // no links to singleton tags + $error .= 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$frame_data['frameid'].')
'; + } else { + $PreviousFrames[] = $frame_name.$frame_data['frameid']; // only one linked tag of this type + $PreviousFrames[] = $frame_data['frameid']; // no non-linked singleton tags of this type + } + break; + default: + if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { + $error .= 'Frame not allowed in ID3v2.'.$majorversion.': '.$frame_name.'
'; + } + break; + } + } + + if ($error) { + if ($showerrors) { + echo $error; + } + return false; + } else { + return true; + } +} + +function GenerateID3v2Tag($data, $majorversion=4, $minorversion=0, $paddedlength=0, $extendedheader='', $footer=false, $showerrors=true, $noerrorsonly=true) { + ID3v2FrameIsAllowed(null, '', ''); // clear static array in case this isn't the first call to GenerateID3v2Tag() + + $tagstring = ''; + if (is_array($data)) { + if (is_array($extendedheader)) { + // not supported yet + } + foreach ($data as $frame_name => $frame_rawinputdata) { + if (!is_array($frame_rawinputdata) || !isset($frame_rawinputdata[0]) || !is_array($frame_rawinputdata[0])) { + // force everything to be arrayed so only one processing loop + $frame_rawinputdata = array($frame_rawinputdata); + } + foreach ($frame_rawinputdata as $irrelevantindex => $frame_inputdata) { + if (IsValidID3v2FrameName($frame_name, $majorversion)) { + unset($frame_length); + unset($frame_flags); + $frame_data = false; + if (ID3v2FrameIsAllowed($frame_name, $frame_inputdata, $majorversion, $showerrors)) { + if ($frame_data = GenerateID3v2FrameData($frame_name, $frame_inputdata, $majorversion, $showerrors)) { + $FrameUnsynchronisation = false; + if ($majorversion >= 4) { + // frame-level unsynchronization + $unsynchdata = Unsynchronise($frame_data); + if (strlen($unsynchdata) != strlen($frame_data)) { + // unsynchronization needed + $FrameUnsynchronisation = true; + $frame_data = $unsynchdata; + if (isset($TagUnsynchronisation) && $TagUnsynchronisation === false) { + // only set to true if ALL frames are unsynchronised + } else { + $TagUnsynchronisation = true; + } + } else { + if (isset($TagUnsynchronisation)) { + $TagUnsynchronisation = false; + } + } + unset($unsynchdata); + + $frame_length = BigEndian2String(strlen($frame_data), 4, true); + } else { + $frame_length = BigEndian2String(strlen($frame_data), 4, false); + } + $frame_flags = GenerateID3v2FrameFlags($majorversion, ID3v2FrameFlagsLookupTagAlter($frame_name, $majorversion), ID3v2FrameFlagsLookupFileAlter($frame_name, $majorversion), false, false, false, false, $FrameUnsynchronisation, false); + } + } else { + if ($showerrors) { + echo 'Frame "'.$frame_name.'" is NOT allowed
'; + } + } + if ($frame_data === false) { + if ($showerrors) { + echo 'GenerateID3v2FrameData() failed for "'.$frame_name.'"
'; + echo 'Error generated in getID3() v'.GETID3VERSION.'
'; + } + if ($noerrorsonly) { + return false; + } else { + unset($frame_name); + } + } + } else { + // ignore any invalid frame names, including 'title', 'header', etc + unset($frame_name); + unset($frame_length); + unset($frame_flags); + unset($frame_data); + } + if (isset($frame_name) && isset($frame_length) && isset($frame_flags) && isset($frame_data)) { + $tagstring .= $frame_name.$frame_length.$frame_flags.$frame_data; + } + } + } + if ($footer) { + if ($showerrors) { + echo 'Footer not supported (yet)
'; + } + return false; + } +//echo number_format(strlen($tagstring)); + if (!isset($TagUnsynchronisation)) { + $TagUnsynchronisation = true; + } + if ($majorversion <= 3) { + // tag-level unsynchronization + $unsynchdata = Unsynchronise($tagstring); + if (strlen($unsynchdata) != strlen($tagstring)) { + // unsynchronization needed + $TagUnsynchronisation = true; + $tagstring = $unsynchdata; + } + } +//echo ' - '.number_format(strlen($tagstring)).'
'; + if (!$footer && ($paddedlength > (strlen($tagstring) + ID3v2HeaderLength($majorversion)))) { + // pad up to $paddedlength bytes if unpadded tag is shorter than $paddedlength + // "Furthermore it MUST NOT have any padding when a tag footer is added to the tag." + $tagstring .= @str_repeat(chr(0), $paddedlength - strlen($tagstring)); + } + if (substr($tagstring, strlen($tagstring) - 1, 1) == chr(255)) { + // special unsynchronization case: + // if last byte == $FF then appended a $00 + $TagUnsynchronisation = true; + $tagstring .= chr(0); + } + + $tagheader = 'ID3'; + $tagheader .= chr($majorversion); + $tagheader .= chr($minorversion); + $tagheader .= GenerateID3v2TagFlags($majorversion, $TagUnsynchronisation, false, (bool) $extendedheader, false, $footer); + $tagheader .= BigEndian2String(strlen($tagstring), 4, true); + + return $tagheader.$tagstring; + } else { + return false; + } +} + +function WriteID3v2($filename, $data, $majorversion=4, $minorversion=0, $overwrite=false, $paddedlength=0, $showerrors=false) { + // File MUST be writeable - CHMOD(646) at least. It's best if the + // directory is also writeable, because that method is both faster and less susceptible to errors. + if (is_writeable($filename) || (!file_exists($filename) && is_writeable(dirname($filename)))) { + $error = ''; + $OldThisfileInfo = GetAllFileInfo($filename); + if ($overwrite) { + // ignore previous data + } else { + // merge with existing data + $data = array_join_merge($OldThisfileInfo, $data); + $paddedlength = max($OldThisfileInfo['id3v2']['headerlength'], $paddedlength); + } + if ($NewID3v2Tag = GenerateID3v2Tag($data['id3v2'], $majorversion, $minorversion, $paddedlength, '', false, $showerrors, true)) { + if ((!file_exists($filename) && is_writeable(dirname($filename))) || (is_writeable($filename) && isset($OldThisfileInfo['id3v2']['headerlength']) && ($OldThisfileInfo['id3v2']['headerlength'] == strlen($NewID3v2Tag)))) { + // best and fastest method - insert-overwrite existing tag (padded to length of old tag if neccesary) + if (file_exists($filename)) { + + ob_start(); + if ($fp = fopen($filename, 'r+b')) { + rewind($fp); + fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); + fclose($fp); + } else { + $error .= 'Could not open '.$filename.' mode "r+b" - '.strip_tags(ob_get_contents()).'
'; + } + ob_end_clean(); + + } else { + + ob_start(); + if ($fp = fopen($filename, 'wb')) { + rewind($fp); + fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); + fclose($fp); + } else { + $error .= 'Could not open '.$filename.' mode "wb" - '.strip_tags(ob_get_contents()).'
'; + } + ob_end_clean(); + + } + + } else { + + // new tag is longer than old tag - must rewrite entire file + if (is_writeable(dirname($filename))) { + // preferred alternate method - only one copying operation, minimal chance of corrupting + // original file if script is interrupted, but required directory to be writeable + ob_start(); + if ($fp_source = fopen($filename, 'rb')) { + + if ($OldThisfileInfo['audiobytes'] > 0) { + + rewind($fp_source); + if ($OldThisfileInfo['avdataoffset'] !== false) { + fseek($fp_source, $OldThisfileInfo['avdataoffset'], SEEK_SET); + } + ob_start(); + if ($fp_temp = fopen($filename.'getid3tmp', 'wb')) { + fwrite($fp_temp, $NewID3v2Tag, strlen($NewID3v2Tag)); + // while (($buffer = fread($fp_source, FREAD_BUFFER_SIZE)) !== false) { + while ($buffer = fread($fp_source, FREAD_BUFFER_SIZE)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_temp); + } else { + $error .= 'Could not open '.$filename.'getid3tmp mode "wb" - '.strip_tags(ob_get_contents()).'
'; + } + ob_end_clean(); + fclose($fp_source); + + } else { // no previous audiodata + + ob_start(); + if ($fp_temp = fopen($filename.'getid3tmp', 'wb')) { + fwrite($fp_temp, $NewID3v2Tag, strlen($NewID3v2Tag)); + fclose($fp_temp); + } else { + $error .= 'Could not open '.$filename.'getid3tmp mode "wb" - '.strip_tags(ob_get_contents()).'
'; + } + ob_end_clean(); + + } + + } else { + + $error .= 'Could not open '.$filename.' mode "rb" - '.strip_tags(ob_get_contents()).'
'; + + } + ob_end_clean(); + if (!$error) { + if (file_exists($filename)) { + unlink($filename); + } + rename($filename.'getid3tmp', $filename); + } + + } else { // !is_writeable(dirname($filename)) + + // less desirable alternate method - double-copies the file, overwrites original file + // and could corrupt source file if the script is interrupted or an error occurs. + ob_start(); + if ($fp_source = fopen($filename, 'rb')) { + + rewind($fp_source); + if ($OldThisfileInfo['avdataoffset'] !== false) { + fseek($fp_source, $OldThisfileInfo['avdataoffset'], SEEK_SET); + } + if ($fp_temp = tmpfile()) { + + fwrite($fp_temp, $NewID3v2Tag, strlen($NewID3v2Tag)); + // while (($buffer = fread($fp_source, FREAD_BUFFER_SIZE)) !== false) { + while ($buffer = fread($fp_source, FREAD_BUFFER_SIZE)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_source); + ob_start(); + if ($fp_source = @fopen($filename, 'wb')) { + + rewind($fp_temp); + // while (($buffer = fread($fp_temp, FREAD_BUFFER_SIZE)) !== false) { + while ($buffer = fread($fp_temp, FREAD_BUFFER_SIZE)) { + fwrite($fp_source, $buffer, strlen($buffer)); + } + fseek($fp_temp, -128, SEEK_END); + fclose($fp_source); + + } else { + + $error .= 'Could not open '.$filename.' mode "wb" - '.strip_tags(ob_get_contents()).'
'; + + } + ob_end_clean(); + fclose($fp_temp); + + } else { + + $error .= 'Could not create tmpfile()
'; + + } + + } else { + + $error .= 'Could not open '.$filename.' mode "rb" - '.strip_tags(ob_get_contents()).'
'; + + } + ob_end_clean(); + } + } + } else { + $error .= 'GenerateID3v2Tag() failed
'; + } + + if ($error) { + if ($showerrors) { + echo $error; + } + return false; + } + return true; + } + return false; +} + +function RemoveID3v2($filename, $showerrors=false) { + // File MUST be writeable - CHMOD(646) at least. It's best if the + // directory is also writeable, because that method is both faster and less susceptible to errors. + if (is_writeable(dirname($filename))) { + // preferred method - only one copying operation, minimal chance of corrupting + // original file if script is interrupted, but required directory to be writeable + if ($fp_source = @fopen($filename, 'rb')) { + $OldThisfileInfo = GetAllFileInfo($filename); + rewind($fp_source); + if ($OldThisfileInfo['avdataoffset'] !== false) { + fseek($fp_source, $OldThisfileInfo['avdataoffset'], SEEK_SET); + } + if ($fp_temp = @fopen($filename.'getid3tmp', 'w+b')) { + // while (($buffer = fread($fp_source, FREAD_BUFFER_SIZE)) !== false) { + while ($buffer = fread($fp_source, FREAD_BUFFER_SIZE)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_temp); + } else { + $error .= 'Could not open '.$filename.'getid3tmp mode "w+b"
'; + } + fclose($fp_source); + } else { + $error .= 'Could not open '.$filename.' mode "rb"
'; + } + if (file_exists($filename)) { + unlink($filename); + } + rename($filename.'getid3tmp', $filename); + } elseif (is_writable($filename)) { + // less desirable alternate method - double-copies the file, overwrites original file + // and could corrupt source file if the script is interrupted or an error occurs. + if ($fp_source = @fopen($filename, 'rb')) { + $OldThisfileInfo = GetAllFileInfo($filename); + rewind($fp_source); + if ($OldThisfileInfo['avdataoffset'] !== false) { + fseek($fp_source, $OldThisfileInfo['avdataoffset'], SEEK_SET); + } + if ($fp_temp = tmpfile()) { + // while (($buffer = fread($fp_source, FREAD_BUFFER_SIZE)) !== false) { + while ($buffer = fread($fp_source, FREAD_BUFFER_SIZE)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_source); + if ($fp_source = @fopen($filename, 'wb')) { + rewind($fp_temp); + // while (($buffer = fread($fp_temp, FREAD_BUFFER_SIZE)) !== false) { + while ($buffer = fread($fp_temp, FREAD_BUFFER_SIZE)) { + fwrite($fp_source, $buffer, strlen($buffer)); + } + fseek($fp_temp, -128, SEEK_END); + fclose($fp_source); + } else { + $error .= 'Could not open '.$filename.' mode "wb"
'; + } + fclose($fp_temp); + } else { + $error .= 'Could not create tmpfile()
'; + } + } else { + $error .= 'Could not open '.$filename.' mode "rb"
'; + } + } else { + $error .= 'Directory and file both not writeable
'; + } + if ($error) { + if ($showerrors) { + echo $error; + } + return false; + } else { + return true; + } +} + + +function GenerateID3v1Tag($title, $artist, $album, $year, $genre, $comment, $track) { + $ID3v1Tag = 'TAG'; + $ID3v1Tag .= str_pad(substr($title, 0, 30), 30, chr(0), STR_PAD_RIGHT); + $ID3v1Tag .= str_pad(substr($artist, 0, 30), 30, chr(0), STR_PAD_RIGHT); + $ID3v1Tag .= str_pad(substr($album, 0, 30), 30, chr(0), STR_PAD_RIGHT); + $ID3v1Tag .= str_pad(substr($year, 0, 4), 4, ' ', STR_PAD_LEFT); + if (isset($track) && ($track > 0) && ($track <= 255)) { + $ID3v1Tag .= str_pad(substr($comment, 0, 28), 28, chr(0), STR_PAD_RIGHT); + $ID3v1Tag .= chr(0); + if (gettype($track) == 'string') { + $track = (int) $track; + } + $ID3v1Tag .= chr($track); + } else { + $ID3v1Tag .= str_pad(substr($comment, 0, 30), 30, chr(0), STR_PAD_RIGHT); + } + if (($genre < 0) || ($genre > 147)) { + $genre = 255; // 'unknown' genre + } + if (gettype($genre) == 'string') { + $genrenumber = (int) $genre; + $ID3v1Tag .= chr($genrenumber); + } elseif (gettype($genre) == 'integer') { + $ID3v1Tag .= chr($genre); + } else { + $ID3v1Tag .= chr(255); // 'unknown' genre + } + + return $ID3v1Tag; +} + +function WriteID3v1($filename, $title='', $artist='', $album='', $year='', $comment='', $genre=255, $track='', $showerrors=false) { + // File MUST be writeable - CHMOD(646) at least + if (is_writeable($filename)) { + $error = ''; + if ($fp_source = @fopen($filename, 'r+b')) { + fseek($fp_source, -128, SEEK_END); + if (fread($fp_source, 3) == 'TAG') { + fseek($fp_source, -128, SEEK_END); // overwrite existing ID3v1 tag + } else { + fseek($fp_source, 0, SEEK_END); // append new ID3v1 tag + } + fwrite($fp_source, GenerateID3v1Tag($title, $artist, $album, $year, $genre, $comment, $track), 128); + fclose($fp_source); + } else { + if ($showerrors) { + echo 'Could not open '.$filename.' mode "r+b"
'; + } + return false; + } + return true; + } + if ($showerrors) { + echo '!is_writable('.$filename.')
'; + } + return false; +} + +function RemoveID3v1($filename, $showerrors=false) { + // File MUST be writeable - CHMOD(646) at least + if (is_writeable($filename)) { + if ($fp_source = @fopen($filename, 'r+b')) { + fseek($fp_source, -128, SEEK_END); + if (fread($fp_source, 3) == 'TAG') { + ftruncate($fp_source, filesize($filename) - 128); + } else { + // no ID3v1 tag to begin with - do nothing + } + fclose($fp_source); + } else { + $error .= 'Could not open '.$filename.' mode "r+b"
'; + } + if ($error) { + if ($showerrors) { + echo $error; + } + return false; + } else { + return true; + } + } else { + return false; + } +} + +function IsValidPriceString($pricestring) { + if (LanguageLookup(substr($pricestring, 0, 3), true) == '') { + return false; + } elseif (!IsANumber(substr($pricestring, 3), true)) { + return false; + } + return true; +} + +function ID3v2FrameFlagsLookupTagAlter($framename, $majorversion) { + // unfinished + switch ($framename) { + case 'RGAD': + $allow = true; + default: + $allow = false; + break; + } + return $allow; +} + +function ID3v2FrameFlagsLookupFileAlter($framename, $majorversion) { + // unfinished + switch ($framename) { + case 'RGAD': + return false; + break; + + default: + return false; + break; + } +} + +function IsValidETCOevent($eventid, $majorversion) { + if (($eventid < 0) || ($eventid > 0xFF)) { + // outside range of 1 byte + return false; + } elseif (($eventid >= 0xF0) && ($eventid <= 0xFC)) { + // reserved for future use + return false; + } elseif (($eventid >= 0x17) && ($eventid <= 0xDF)) { + // reserved for future use + return false; + } elseif (($eventid >= 0x0E) && ($eventid <= 0x16) && ($majorversion == 2)) { + // not defined in ID3v2.2 + return false; + } elseif (($eventid >= 0x15) && ($eventid <= 0x16) && ($majorversion == 3)) { + // not defined in ID3v2.3 + return false; + } + return true; +} + +function IsValidSYLTtype($contenttype, $majorversion) { + if (($contenttype >= 0) && ($contenttype <= 8) && ($majorversion == 4)) { + return true; + } elseif (($contenttype >= 0) && ($contenttype <= 6) && ($majorversion == 3)) { + return true; + } + return false; +} + +function IsValidRVA2channeltype($channeltype, $majorversion) { + if (($channeltype >= 0) && ($channeltype <= 8) && ($majorversion == 4)) { + return true; + } + return false; +} + +function IsValidAPICpicturetype($picturetype, $majorversion) { + if (($picturetype >= 0) && ($picturetype <= 0x14) && ($majorversion >= 2) && ($majorversion <= 4)) { + return true; + } + return false; +} + +function IsValidAPICimageformat($imageformat, $majorversion) { + if ($imageformat == '-->') { + return true; + } elseif ($majorversion == 2) { + if ((strlen($imageformat) == 3) && ($imageformat == strtoupper($imageformat))) { + return true; + } + } elseif (($majorversion == 3) || ($majorversion == 4)) { + if (IsValidMIMEstring($imageformat)) { + return true; + } + } + return false; +} + +function IsValidCOMRreceivedas($receivedas, $majorversion) { + if (($majorversion >= 3) && ($receivedas >= 0) && ($receivedas <= 8)) { + return true; + } + return false; +} + +function IsValidRGADname($RGADname, $majorversion) { + if (($RGADname >= 0) && ($RGADname <= 2)) { + return true; + } + return false; +} + +function IsValidRGADoriginator($RGADoriginator, $majorversion) { + if (($RGADoriginator >= 0) && ($RGADoriginator <= 3)) { + return true; + } + return false; +} + +function IsValidMIMEstring($mimestring) { + if ((strlen($mimestring) >= 3) && (strpos($mimestring, '/') > 0) && (strpos($mimestring, '/') < (strlen($mimestring) - 1))) { + return true; + } + return false; +} + +function IsWithinBitRange($number, $maxbits, $signed=false) { + if ($signed) { + if (($number > (0 - pow(2, $maxbits - 1))) && ($number <= pow(2, $maxbits - 1))) { + return true; + } + } else { + if (($number >= 0) && ($number <= pow(2, $maxbits))) { + return true; + } + } + return false; +} + +function IsValidTextEncoding($textencodingbyte, $majorversion) { + $textencodingintval = chr($textencodingbyte); + if (($textencodingintval >= 0) && ($textencodingintval <= 3) && ($majorversion == 4)) { + return true; + } elseif (($textencodingintval >= 0) && ($textencodingintval <= 1) && ($majorversion == 3)) { + return true; + } elseif (($textencodingintval >= 0) && ($textencodingintval <= 1) && ($majorversion == 2)) { + return true; + } + return false; +} + +function safe_parse_url($url) { + $parts = @parse_url($url); + $parts['scheme'] = (isset($parts['scheme']) ? $parts['scheme'] : ''); + $parts['host'] = (isset($parts['host']) ? $parts['host'] : ''); + $parts['user'] = (isset($parts['user']) ? $parts['user'] : ''); + $parts['pass'] = (isset($parts['pass']) ? $parts['pass'] : ''); + $parts['path'] = (isset($parts['path']) ? $parts['path'] : ''); + $parts['query'] = (isset($parts['query']) ? $parts['query'] : ''); + return $parts; +} + +function IsValidURL($url, $allowUserPass=false) { + if ($url == '') { + return false; + } + if ($allowUserPass !== true) { + if (strstr($url, '@')) { + // in the format http://user:pass@example.com or http://user@example.com + // but could easily be somebody incorrectly entering an email address in place of a URL + return false; + } + } + if ($parts = safe_parse_url($url)) { + if (($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') && ($parts['scheme'] != 'ftp') && ($parts['scheme'] != 'gopher')) { + return false; + } elseif (!eregi("^[[:alnum:]]([-.]?[0-9a-z])*\.[a-z]{2,3}$", $parts['host'], $regs) && !IsValidDottedIP($parts['host'])) { + return false; + } elseif (!eregi("^([[:alnum:]-]|[\_])*$", $parts['user'], $regs)) { + return false; + } elseif (!eregi("^([[:alnum:]-]|[\_])*$", $parts['pass'], $regs)) { + return false; + } elseif (!eregi("^[[:alnum:]/_\.@~-]*$", $parts['path'], $regs)) { + return false; + } elseif (!eregi("^[[:alnum:]?&=+:;_()%#/,\.-]*$", $parts['query'], $regs)) { + return false; + } else { + return true; + } + } else { + return false; + } +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.quicktime.php b/livesupport/modules/getid3/var/getid3.quicktime.php new file mode 100644 index 000000000..7962fe104 --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.quicktime.php @@ -0,0 +1,1037 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.quicktime.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function getQuicktimeHeaderFilepointer(&$fd, &$ThisFileInfo) { + + $ThisFileInfo['fileformat'] = 'quicktime'; + $ThisFileInfo['audio']['dataformat'] = 'quicktime'; + $ThisFileInfo['video']['dataformat'] = 'quicktime'; + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + + $offset = 0; + $atomcounter = 0; + + while ($offset < $ThisFileInfo['avdataend']) { + fseek($fd, $offset, SEEK_SET); + $AtomHeader = fread($fd, 8); + + $atomsize = BigEndian2Int(substr($AtomHeader, 0, 4)); + $atomname = substr($AtomHeader, 4, 4); + $ThisFileInfo['quicktime']["$atomname"]['name'] = $atomname; + $ThisFileInfo['quicktime']["$atomname"]['size'] = $atomsize; + $ThisFileInfo['quicktime']["$atomname"]['offset'] = $offset; + + if (($offset + $atomsize) > $ThisFileInfo['avdataend']) { + $ThisFileInfo['error'] .= "\n".'Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)'; + return false; + } + + switch ($atomname) { + case 'mdat': // Media DATa atom + // 'mdat' contains the actual data for the audio/video + if (!isset($ThisFileInfo['avdataend_tmp']) ||($ThisFileInfo['quicktime']["$atomname"]['size'] > ($ThisFileInfo['avdataend_tmp'] - $ThisFileInfo['avdataoffset']))) { + + $ThisFileInfo['avdataoffset'] = $ThisFileInfo['quicktime']["$atomname"]['offset'] + 8; + $OldAVDataEnd = $ThisFileInfo['avdataend']; + $ThisFileInfo['avdataend'] = $ThisFileInfo['quicktime']["$atomname"]['offset'] + $ThisFileInfo['quicktime']["$atomname"]['size']; + + require_once(GETID3_INCLUDEPATH.'getid3.mp3.php'); + if (MPEGaudioHeaderValid(MPEGaudioHeaderDecode(fread($fd, 4)))) { + getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $ThisFileInfo['avdataoffset'], false); + if (isset($ThisFileInfo['mpeg']['audio'])) { + $ThisFileInfo['audio']['dataformat'] = 'mp3'; + $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate']; + $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels']; + $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'] * 1000; + $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitratemode']); + $ThisFileInfo['bitrate'] = $ThisFileInfo['audio']['bitrate']; + } + } + $ThisFileInfo['avdataend'] = $OldAVDataEnd; + unset($OldAVDataEnd); + + } + break; + + case 'free': // FREE space atom + case 'skip': // SKIP atom + case 'wide': // 64-bit expansion placeholder atom + // 'free', 'skip' and 'wide' are just padding, contains no useful data at all + break; + + default: + $atomHierarchy = array(); + $ThisFileInfo['quicktime']["$atomname"] = QuicktimeParseAtom($atomname, $atomsize, fread($fd, $atomsize), $ThisFileInfo, $offset, $atomHierarchy); + break; + } + + $offset += $atomsize; + $atomcounter++; + } + + if (!empty($ThisFileInfo['avdataend_tmp'])) { + // this value is assigned to a temp value and then erased because + // otherwise any atoms beyond the 'mdat' atom would not get parsed + $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataend_tmp']; + unset($ThisFileInfo['avdataend_tmp']); + } + + // Quicktime tags have highest priority + if (isset($ThisFileInfo['quicktime']['comments'])) { + CopyFormatCommentsToRootComments($ThisFileInfo['quicktime']['comments'], $ThisFileInfo, true, true, true); + // add tag to array of tags + $ThisFileInfo['tags'][] = 'quicktime'; + } + + if (!isset($ThisFileInfo['bitrate']) && isset($ThisFileInfo['playtime_seconds'])) { + $ThisFileInfo['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds']; + } + if (isset($ThisFileInfo['bitrate']) && !isset($ThisFileInfo['audio']['bitrate']) && !isset($ThisFileInfo['quicktime']['video'])) { + $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['bitrate']; + } + + return true; +} + +function QuicktimeParseAtom($atomname, $atomsize, $atomdata, &$ThisFileInfo, $baseoffset, &$atomHierarchy) { + // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm + + array_push($atomHierarchy, $atomname); + $atomstructure['hierarchy'] = implode(' ', $atomHierarchy); + $atomstructure['name'] = $atomname; + $atomstructure['size'] = $atomsize; + $atomstructure['offset'] = $baseoffset; + switch ($atomname) { + case 'moov': // MOVie container atom + case 'trak': // TRAcK container atom + case 'clip': // CLIPping container atom + case 'matt': // track MATTe container atom + case 'edts': // EDiTS container atom + case 'tref': // Track REFerence container atom + case 'mdia': // MeDIA container atom + case 'minf': // Media INFormation container atom + case 'dinf': // Data INFormation container atom + case 'udta': // User DaTA container atom + case 'stbl': // Sample TaBLe container atom + case 'cmov': // Compressed MOVie container atom + case 'rmra': // Reference Movie Record Atom + case 'rmda': // Reference Movie Descriptor Atom + $atomstructure['subatoms'] = QuicktimeParseContainerAtom($atomdata, $ThisFileInfo, $baseoffset + 8, $atomHierarchy); + break; + + + case '©cpy': + case '©day': + case '©dir': + case '©ed1': + case '©ed2': + case '©ed3': + case '©ed4': + case '©ed5': + case '©ed6': + case '©ed7': + case '©ed8': + case '©ed9': + case '©fmt': + case '©inf': + case '©prd': + case '©prf': + case '©req': + case '©src': + case '©wrt': + case '©nam': + case '©cmt': + case '©wrn': + case '©hst': + case '©mak': + case '©mod': + case '©PRD': + case '©swr': + case '©aut': + case '©ART': + case '©trk': + case '©alb': + case '©com': + case '©gen': + case '©ope': + case '©url': + case '©enc': + $atomstructure['data_length'] = BigEndian2Int(substr($atomdata, 0, 2)); + $atomstructure['language_id'] = BigEndian2Int(substr($atomdata, 2, 2)); + $atomstructure['data'] = substr($atomdata, 4); + + $atomstructure['language'] = QuicktimeLanguageLookup($atomstructure['language_id']); + $handyatomtranslatorarray['©cpy'] = 'copyright'; + $handyatomtranslatorarray['©day'] = 'creation_date'; + $handyatomtranslatorarray['©dir'] = 'director'; + $handyatomtranslatorarray['©ed1'] = 'edit1'; + $handyatomtranslatorarray['©ed2'] = 'edit2'; + $handyatomtranslatorarray['©ed3'] = 'edit3'; + $handyatomtranslatorarray['©ed4'] = 'edit4'; + $handyatomtranslatorarray['©ed5'] = 'edit5'; + $handyatomtranslatorarray['©ed6'] = 'edit6'; + $handyatomtranslatorarray['©ed7'] = 'edit7'; + $handyatomtranslatorarray['©ed8'] = 'edit8'; + $handyatomtranslatorarray['©ed9'] = 'edit9'; + $handyatomtranslatorarray['©fmt'] = 'format'; + $handyatomtranslatorarray['©inf'] = 'information'; + $handyatomtranslatorarray['©prd'] = 'producer'; + $handyatomtranslatorarray['©prf'] = 'performers'; + $handyatomtranslatorarray['©req'] = 'system_requirements'; + $handyatomtranslatorarray['©src'] = 'source_credit'; + $handyatomtranslatorarray['©wrt'] = 'writer'; + + // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt + $handyatomtranslatorarray['©nam'] = 'title'; + $handyatomtranslatorarray['©cmt'] = 'comment'; + $handyatomtranslatorarray['©wrn'] = 'warning'; + $handyatomtranslatorarray['©hst'] = 'host_computer'; + $handyatomtranslatorarray['©mak'] = 'make'; + $handyatomtranslatorarray['©mod'] = 'model'; + $handyatomtranslatorarray['©PRD'] = 'product'; + $handyatomtranslatorarray['©swr'] = 'software'; + $handyatomtranslatorarray['©aut'] = 'author'; + $handyatomtranslatorarray['©ART'] = 'artist'; + $handyatomtranslatorarray['©trk'] = 'track'; + $handyatomtranslatorarray['©alb'] = 'album'; + $handyatomtranslatorarray['©com'] = 'comment'; + $handyatomtranslatorarray['©gen'] = 'genre'; + $handyatomtranslatorarray['©ope'] = 'composer'; + $handyatomtranslatorarray['©url'] = 'url'; + $handyatomtranslatorarray['©enc'] = 'encoder'; + if (isset($handyatomtranslatorarray["$atomname"])) { + $ThisFileInfo['quicktime']['comments'][$handyatomtranslatorarray["$atomname"]][] = $atomstructure['data']; + } + break; + + + case 'play': // auto-PLAY atom + $atomstructure['autoplay'] = (bool) BigEndian2Int(substr($atomdata, 0, 1)); + + $ThisFileInfo['quicktime']['autoplay'] = $atomstructure['autoplay']; + break; + + + case 'WLOC': // Window LOCation atom + $atomstructure['location_x'] = BigEndian2Int(substr($atomdata, 0, 2)); + $atomstructure['location_y'] = BigEndian2Int(substr($atomdata, 2, 2)); + break; + + + case 'LOOP': // LOOPing atom + case 'SelO': // play SELection Only atom + case 'AllF': // play ALL Frames atom + $atomstructure['data'] = BigEndian2Int($atomdata); + break; + + + case 'name': // + case 'MCPS': // Media Cleaner PRo + case '@PRM': // adobe PReMiere version + case '@PRQ': // adobe PRemiere Quicktime version + $atomstructure['data'] = $atomdata; + break; + + + case 'cmvd': // Compressed MooV Data atom + $ThisFileInfo['warning'] .= "\n".'Compressed Quicktime MOOV Data atoms ("cmvd") not supported'; + break; + + + case 'dcom': // Data COMpression atom + $atomstructure['compression_id'] = $atomdata; + $atomstructure['compression_text'] = QuicktimeDCOMLookup($atomdata); + break; + + + case 'rdrf': // Reference movie Data ReFerence atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); + $atomstructure['flags']['internal_data'] = (bool) ($atomstructure['flags_raw'] & 0x000001); + + $atomstructure['reference_type_name'] = substr($atomdata, 4, 4); + $atomstructure['reference_length'] = BigEndian2Int(substr($atomdata, 8, 4)); + switch ($atomstructure['reference_type_name']) { + case 'url ': + $atomstructure['url'] = NoNullString(substr($atomdata, 12)); + break; + + case 'alis': + $atomstructure['file_alias'] = substr($atomdata, 12); + break; + + case 'rsrc': + $atomstructure['resource_alias'] = substr($atomdata, 12); + break; + + default: + $atomstructure['data'] = substr($atomdata, 12); + break; + } + break; + + + case 'rmqu': // Reference Movie QUality atom + $atomstructure['movie_quality'] = BigEndian2Int($atomdata); + break; + + + case 'rmcs': // Reference Movie Cpu Speed atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['cpu_speed_rating'] = BigEndian2Int(substr($atomdata, 4, 2)); + break; + + + case 'rmvc': // Reference Movie Version Check atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['gestalt_selector'] = substr($atomdata, 4, 4); + $atomstructure['gestalt_value_mask'] = BigEndian2Int(substr($atomdata, 8, 4)); + $atomstructure['gestalt_value'] = BigEndian2Int(substr($atomdata, 12, 4)); + $atomstructure['gestalt_check_type'] = BigEndian2Int(substr($atomdata, 14, 2)); + break; + + + case 'rmcd': // Reference Movie Component check atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['component_type'] = substr($atomdata, 4, 4); + $atomstructure['component_subtype'] = substr($atomdata, 8, 4); + $atomstructure['component_manufacturer'] = substr($atomdata, 12, 4); + $atomstructure['component_flags_raw'] = BigEndian2Int(substr($atomdata, 16, 4)); + $atomstructure['component_flags_mask'] = BigEndian2Int(substr($atomdata, 20, 4)); + $atomstructure['component_min_version'] = BigEndian2Int(substr($atomdata, 24, 4)); + break; + + + case 'rmdr': // Reference Movie Data Rate atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['data_rate'] = BigEndian2Int(substr($atomdata, 4, 4)); + + $atomstructure['data_rate_bps'] = $atomstructure['data_rate'] * 10; + break; + + + case 'rmla': // Reference Movie Language Atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['language_id'] = BigEndian2Int(substr($atomdata, 4, 2)); + + $atomstructure['language'] = QuicktimeLanguageLookup($atomstructure['language_id']); + break; + + + case 'rmla': // Reference Movie Language Atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['track_id'] = BigEndian2Int(substr($atomdata, 4, 2)); + break; + + + case 'stsd': // Sample Table Sample Description atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4)); + $stsdEntriesDataOffset = 8; + for ($i = 0; $i < $atomstructure['number_entries']; $i++) { + $atomstructure['sample_description_table'][$i]['size'] = BigEndian2Int(substr($atomdata, $stsdEntriesDataOffset, 4)); + $stsdEntriesDataOffset += 4; + $atomstructure['sample_description_table'][$i]['data_format'] = substr($atomdata, $stsdEntriesDataOffset, 4); + $stsdEntriesDataOffset += 4; + $atomstructure['sample_description_table'][$i]['reserved'] = BigEndian2Int(substr($atomdata, $stsdEntriesDataOffset, 6)); + $stsdEntriesDataOffset += 6; + $atomstructure['sample_description_table'][$i]['reference_index'] = BigEndian2Int(substr($atomdata, $stsdEntriesDataOffset, 2)); + $stsdEntriesDataOffset += 2; + $atomstructure['sample_description_table'][$i]['data'] = substr($atomdata, $stsdEntriesDataOffset, ($atomstructure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2)); + $stsdEntriesDataOffset += ($atomstructure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2); + + $atomstructure['sample_description_table'][$i]['encoder_version'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 0, 2)); + $atomstructure['sample_description_table'][$i]['encoder_revision'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 2, 2)); + $atomstructure['sample_description_table'][$i]['encoder_vendor'] = substr($atomstructure['sample_description_table'][$i]['data'], 4, 4); + + if ($atomstructure['sample_description_table'][$i]['encoder_vendor'] == chr(0).chr(0).chr(0).chr(0)) { + + // audio atom + $atomstructure['sample_description_table'][$i]['audio_channels'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 8, 2)); + $atomstructure['sample_description_table'][$i]['audio_bit_depth'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 10, 2)); + $atomstructure['sample_description_table'][$i]['audio_compression_id'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 12, 2)); + $atomstructure['sample_description_table'][$i]['audio_packet_size'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 14, 2)); + $atomstructure['sample_description_table'][$i]['audio_sample_rate'] = FixedPoint16_16(substr($atomstructure['sample_description_table'][$i]['data'], 16, 4)); + + $ThisFileInfo['quicktime']['audio']['codec'] = QuicktimeAudioCodecLookup($atomstructure['sample_description_table'][$i]['data_format']); + $ThisFileInfo['quicktime']['audio']['sample_rate'] = $atomstructure['sample_description_table'][$i]['audio_sample_rate']; + $ThisFileInfo['quicktime']['audio']['channels'] = $atomstructure['sample_description_table'][$i]['audio_channels']; + $ThisFileInfo['quicktime']['audio']['bit_depth'] = $atomstructure['sample_description_table'][$i]['audio_bit_depth']; + $ThisFileInfo['audio']['codec'] = $ThisFileInfo['quicktime']['audio']['codec']; + $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['quicktime']['audio']['sample_rate']; + $ThisFileInfo['audio']['channels'] = $ThisFileInfo['quicktime']['audio']['channels']; + $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['quicktime']['audio']['bit_depth']; + + } else { + + // video atom + $atomstructure['sample_description_table'][$i]['video_temporal_quality'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 8, 4)); + $atomstructure['sample_description_table'][$i]['video_spatial_quality'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 12, 4)); + $atomstructure['sample_description_table'][$i]['video_frame_width'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 16, 2)); + $atomstructure['sample_description_table'][$i]['video_frame_height'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 18, 2)); + $atomstructure['sample_description_table'][$i]['video_resolution_x'] = FixedPoint16_16(substr($atomstructure['sample_description_table'][$i]['data'], 20, 4)); + $atomstructure['sample_description_table'][$i]['video_resolution_y'] = FixedPoint16_16(substr($atomstructure['sample_description_table'][$i]['data'], 24, 4)); + $atomstructure['sample_description_table'][$i]['video_data_size'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 28, 4)); + $atomstructure['sample_description_table'][$i]['video_frame_count'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 32, 2)); + $atomstructure['sample_description_table'][$i]['video_encoder_name_len'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 34, 1)); + $atomstructure['sample_description_table'][$i]['video_encoder_name'] = substr($atomstructure['sample_description_table'][$i]['data'], 35, $atomstructure['sample_description_table'][$i]['video_encoder_name_len']); + $atomstructure['sample_description_table'][$i]['video_pixel_color_depth'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 66, 2)); + $atomstructure['sample_description_table'][$i]['video_color_table_id'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 68, 2)); + + $atomstructure['sample_description_table'][$i]['video_pixel_color_type'] = (($atomstructure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color'); + $atomstructure['sample_description_table'][$i]['video_pixel_color_name'] = QuicktimeColorNameLookup($atomstructure['sample_description_table'][$i]['video_pixel_color_depth']); + + if ($atomstructure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') { + //$ThisFileInfo['quicktime']['video']['codec'] = QuicktimeVideoCodecLookup($atomstructure['sample_description_table'][$i]['data_format']); + $ThisFileInfo['quicktime']['video']['codec'] = $atomstructure['sample_description_table'][$i]['video_encoder_name']; + $ThisFileInfo['quicktime']['video']['color_depth'] = $atomstructure['sample_description_table'][$i]['video_pixel_color_depth']; + $ThisFileInfo['quicktime']['video']['color_depth_name'] = $atomstructure['sample_description_table'][$i]['video_pixel_color_name']; + + $ThisFileInfo['video']['codec'] = $ThisFileInfo['quicktime']['video']['codec']; + } + + } + switch ($atomstructure['sample_description_table'][$i]['data_format']) { + case 'mp4a': + $ThisFileInfo['fileformat'] = 'mp4'; + $ThisFileInfo['mime_type'] = 'audio/mp4'; + unset($ThisFileInfo['video']['dataformat']); + break; + + default: + // do nothing + break; + } + unset($atomstructure['sample_description_table'][$i]['data']); + } + break; + + + case 'stts': // Sample Table Time-to-Sample atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4)); + $sttsEntriesDataOffset = 8; + for ($i = 0; $i < $atomstructure['number_entries']; $i++) { + $atomstructure['time_to_sample_table'][$i]['sample_count'] = BigEndian2Int(substr($atomdata, $sttsEntriesDataOffset, 4)); + $sttsEntriesDataOffset += 4; + $atomstructure['time_to_sample_table'][$i]['sample_duration'] = BigEndian2Int(substr($atomdata, $sttsEntriesDataOffset, 4)); + $sttsEntriesDataOffset += 4; + } + break; + + + case 'stss': // Sample Table Sync Sample (key frames) atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4)); + $stssEntriesDataOffset = 8; + for ($i = 0; $i < $atomstructure['number_entries']; $i++) { + $atomstructure['time_to_sample_table'][$i] = BigEndian2Int(substr($atomdata, $stssEntriesDataOffset, 4)); + $stssEntriesDataOffset += 4; + } + break; + + + case 'stsc': // Sample Table Sample-to-Chunk atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4)); + $stscEntriesDataOffset = 8; + for ($i = 0; $i < $atomstructure['number_entries']; $i++) { + $atomstructure['sample_to_chunk_table'][$i]['first_chunk'] = BigEndian2Int(substr($atomdata, $stscEntriesDataOffset, 4)); + $stscEntriesDataOffset += 4; + $atomstructure['sample_to_chunk_table'][$i]['samples_per_chunk'] = BigEndian2Int(substr($atomdata, $stscEntriesDataOffset, 4)); + $stscEntriesDataOffset += 4; + $atomstructure['sample_to_chunk_table'][$i]['sample_description'] = BigEndian2Int(substr($atomdata, $stscEntriesDataOffset, 4)); + $stscEntriesDataOffset += 4; + } + break; + + + case 'stsz': // Sample Table SiZe atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['sample_size'] = BigEndian2Int(substr($atomdata, 4, 4)); + $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 8, 4)); + $stszEntriesDataOffset = 12; + if ($atomstructure['sample_size'] == 0) { + for ($i = 0; $i < $atomstructure['number_entries']; $i++) { + $atomstructure['sample_size_table'][$i] = BigEndian2Int(substr($atomdata, $stszEntriesDataOffset, 4)); + $stszEntriesDataOffset += 4; + } + } + break; + + + case 'stco': // Sample Table Chunk Offset atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4)); + $stcoEntriesDataOffset = 8; + for ($i = 0; $i < $atomstructure['number_entries']; $i++) { + $atomstructure['chunk_offset_table'][$i] = BigEndian2Int(substr($atomdata, $stcoEntriesDataOffset, 4)); + $stcoEntriesDataOffset += 4; + } + break; + + + case 'dref': // Data REFerence atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4)); + $drefDataOffset = 8; + for ($i = 0; $i < $atomstructure['number_entries']; $i++) { + $atomstructure['data_references'][$i]['size'] = BigEndian2Int(substr($atomdata, $drefDataOffset, 4)); + $drefDataOffset += 4; + $atomstructure['data_references'][$i]['type'] = substr($atomdata, $drefDataOffset, 4); + $drefDataOffset += 4; + $atomstructure['data_references'][$i]['version'] = BigEndian2Int(substr($atomdata, $drefDataOffset, 1)); + $drefDataOffset += 1; + $atomstructure['data_references'][$i]['flags_raw'] = BigEndian2Int(substr($atomdata, $drefDataOffset, 3)); // hardcoded: 0x000 + $drefDataOffset += 3; + $atomstructure['data_references'][$i]['data'] = substr($atomdata, $drefDataOffset, ($atomstructure['data_references'][$i]['size'] - 4 - 4 - 1 - 3)); + $drefDataOffset += ($atomstructure['data_references'][$i]['size'] - 4 - 4 - 1 - 3); + + $atomstructure['data_references'][$i]['flags']['self_reference'] = (bool) ($atomstructure['data_references'][$i]['flags_raw'] & 0x001); + } + break; + + + case 'gmin': // base Media INformation atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['graphics_mode'] = BigEndian2Int(substr($atomdata, 4, 2)); + $atomstructure['opcolor_red'] = BigEndian2Int(substr($atomdata, 6, 2)); + $atomstructure['opcolor_green'] = BigEndian2Int(substr($atomdata, 8, 2)); + $atomstructure['opcolor_blue'] = BigEndian2Int(substr($atomdata, 10, 2)); + $atomstructure['balance'] = BigEndian2Int(substr($atomdata, 12, 2)); + $atomstructure['reserved'] = BigEndian2Int(substr($atomdata, 14, 2)); + break; + + + case 'smhd': // Sound Media information HeaDer atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['balance'] = BigEndian2Int(substr($atomdata, 4, 2)); + $atomstructure['reserved'] = BigEndian2Int(substr($atomdata, 6, 2)); + break; + + + case 'vmhd': // Video Media information HeaDer atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); + $atomstructure['graphics_mode'] = BigEndian2Int(substr($atomdata, 4, 2)); + $atomstructure['opcolor_red'] = BigEndian2Int(substr($atomdata, 6, 2)); + $atomstructure['opcolor_green'] = BigEndian2Int(substr($atomdata, 8, 2)); + $atomstructure['opcolor_blue'] = BigEndian2Int(substr($atomdata, 10, 2)); + + $atomstructure['flags']['no_lean_ahead'] = (bool) ($atomstructure['flags_raw'] & 0x001); + break; + + + case 'hdlr': // HanDLeR reference atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['component_type'] = substr($atomdata, 4, 4); + $atomstructure['component_subtype'] = substr($atomdata, 8, 4); + $atomstructure['component_manufacturer'] = substr($atomdata, 12, 4); + $atomstructure['component_flags_raw'] = BigEndian2Int(substr($atomdata, 16, 4)); + $atomstructure['component_flags_mask'] = BigEndian2Int(substr($atomdata, 20, 4)); + $atomstructure['component_name'] = Pascal2String(substr($atomdata, 24)); + break; + + + case 'mdhd': // MeDia HeaDer atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['creation_time'] = BigEndian2Int(substr($atomdata, 4, 4)); + $atomstructure['modify_time'] = BigEndian2Int(substr($atomdata, 8, 4)); + $atomstructure['time_scale'] = BigEndian2Int(substr($atomdata, 12, 4)); + $atomstructure['duration'] = BigEndian2Int(substr($atomdata, 16, 4)); + $atomstructure['language_id'] = BigEndian2Int(substr($atomdata, 20, 2)); + $atomstructure['quality'] = BigEndian2Int(substr($atomdata, 22, 2)); + + if ($atomstructure['time_scale'] == 0) { + $ThisFileInfo['error'] .= "\n".'Corrupt Quicktime file: mdhd.time_scale == zero'; + return false; + } + $atomstructure['creation_time_unix'] = DateMac2Unix($atomstructure['creation_time']); + $atomstructure['modify_time_unix'] = DateMac2Unix($atomstructure['modify_time']); + $atomstructure['playtime_seconds'] = $atomstructure['duration'] / $atomstructure['time_scale']; + $atomstructure['language'] = QuicktimeLanguageLookup($atomstructure['language_id']); + break; + + + case 'pnot': // Preview atom + $atomstructure['modification_date'] = BigEndian2Int(substr($atomdata, 0, 4)); // "standard Macintosh format" + $atomstructure['version_number'] = BigEndian2Int(substr($atomdata, 4, 2)); // hardcoded: 0x00 + $atomstructure['atom_type'] = substr($atomdata, 6, 4); // usually: 'PICT' + $atomstructure['atom_index'] = BigEndian2Int(substr($atomdata, 10, 2)); // usually: 0x01 + + $atomstructure['modification_date_unix'] = DateMac2Unix($atomstructure['modification_date']); + break; + + + case 'crgn': // Clipping ReGioN atom + $atomstructure['region_size'] = BigEndian2Int(substr($atomdata, 0, 2)); // The Region size, Region boundary box, + $atomstructure['boundary_box'] = BigEndian2Int(substr($atomdata, 2, 8)); // and Clipping region data fields + $atomstructure['clipping_data'] = substr($atomdata, 10); // constitute a QuickDraw region. + break; + + + case 'load': // track LOAD settings atom + $atomstructure['preload_start_time'] = BigEndian2Int(substr($atomdata, 0, 4)); + $atomstructure['preload_duration'] = BigEndian2Int(substr($atomdata, 4, 4)); + $atomstructure['preload_flags_raw'] = BigEndian2Int(substr($atomdata, 8, 4)); + $atomstructure['default_hints_raw'] = BigEndian2Int(substr($atomdata, 12, 4)); + + $atomstructure['default_hints']['double_buffer'] = (bool) ($atomstructure['default_hints_raw'] & 0x0020); + $atomstructure['default_hints']['high_quality'] = (bool) ($atomstructure['default_hints_raw'] & 0x0100); + break; + + + case 'tmcd': // TiMe CoDe atom + case 'chap': // CHAPter list atom + case 'sync': // SYNChronization atom + case 'scpt': // tranSCriPT atom + case 'ssrc': // non-primary SouRCe atom + for ($i = 0; $i < (strlen($atomdata) % 4); $i++) { + $atomstructure['track_id'][$i] = BigEndian2Int(substr($atomdata, $i * 4, 4)); + } + break; + + + case 'elst': // Edit LiST atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4)); + for ($i = 0; $i < $atomstructure['number_entries']; $i++ ) { + $atomstructure['edit_list'][$i]['track_duration'] = BigEndian2Int(substr($atomdata, 8 + ($i * 12) + 0, 4)); + $atomstructure['edit_list'][$i]['media_time'] = BigEndian2Int(substr($atomdata, 8 + ($i * 12) + 4, 4)); + $atomstructure['edit_list'][$i]['media_rate'] = BigEndian2Int(substr($atomdata, 8 + ($i * 12) + 8, 4)); + } + break; + + + case 'kmat': // compressed MATte atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); // hardcoded: 0x000 + $atomstructure['matte_data_raw'] = substr($atomdata, 4); + break; + + + case 'ctab': // Color TABle atom + $atomstructure['color_table_seed'] = BigEndian2Int(substr($atomdata, 0, 4)); // hardcoded: 0x00000000 + $atomstructure['color_table_flags'] = BigEndian2Int(substr($atomdata, 4, 2)); // hardcoded: 0x8000 + $atomstructure['color_table_size'] = BigEndian2Int(substr($atomdata, 6, 2)) + 1; + for ($colortableentry = 0; $colortableentry < $atomstructure['color_table_size']; $colortableentry++) { + $atomstructure['color_table'][$colortableentry]['alpha'] = BigEndian2Int(substr($atomdata, 8 + ($colortableentry * 8) + 0, 2)); + $atomstructure['color_table'][$colortableentry]['red'] = BigEndian2Int(substr($atomdata, 8 + ($colortableentry * 8) + 2, 2)); + $atomstructure['color_table'][$colortableentry]['green'] = BigEndian2Int(substr($atomdata, 8 + ($colortableentry * 8) + 4, 2)); + $atomstructure['color_table'][$colortableentry]['blue'] = BigEndian2Int(substr($atomdata, 8 + ($colortableentry * 8) + 6, 2)); + } + break; + + + case 'mvhd': // MoVie HeaDer atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); + $atomstructure['creation_time'] = BigEndian2Int(substr($atomdata, 4, 4)); + $atomstructure['modify_time'] = BigEndian2Int(substr($atomdata, 8, 4)); + $atomstructure['time_scale'] = BigEndian2Int(substr($atomdata, 12, 4)); + $atomstructure['duration'] = BigEndian2Int(substr($atomdata, 16, 4)); + $atomstructure['preferred_rate'] = FixedPoint16_16(substr($atomdata, 20, 4)); + $atomstructure['preferred_volume'] = FixedPoint8_8(substr($atomdata, 24, 2)); + $atomstructure['reserved'] = substr($atomdata, 26, 10); + $atomstructure['matrix_a'] = FixedPoint16_16(substr($atomdata, 36, 4)); + $atomstructure['matrix_b'] = FixedPoint16_16(substr($atomdata, 40, 4)); + $atomstructure['matrix_u'] = FixedPoint16_16(substr($atomdata, 44, 4)); + $atomstructure['matrix_c'] = FixedPoint16_16(substr($atomdata, 48, 4)); + $atomstructure['matrix_v'] = FixedPoint16_16(substr($atomdata, 52, 4)); + $atomstructure['matrix_d'] = FixedPoint16_16(substr($atomdata, 56, 4)); + $atomstructure['matrix_x'] = FixedPoint2_30(substr($atomdata, 60, 4)); + $atomstructure['matrix_y'] = FixedPoint2_30(substr($atomdata, 64, 4)); + $atomstructure['matrix_w'] = FixedPoint2_30(substr($atomdata, 68, 4)); + $atomstructure['preview_time'] = BigEndian2Int(substr($atomdata, 72, 4)); + $atomstructure['preview_duration'] = BigEndian2Int(substr($atomdata, 76, 4)); + $atomstructure['poster_time'] = BigEndian2Int(substr($atomdata, 80, 4)); + $atomstructure['selection_time'] = BigEndian2Int(substr($atomdata, 84, 4)); + $atomstructure['selection_duration'] = BigEndian2Int(substr($atomdata, 88, 4)); + $atomstructure['current_time'] = BigEndian2Int(substr($atomdata, 92, 4)); + $atomstructure['next_track_id'] = BigEndian2Int(substr($atomdata, 96, 4)); + + if ($atomstructure['time_scale'] == 0) { + $ThisFileInfo['error'] .= "\n".'Corrupt Quicktime file: mvhd.time_scale == zero'; + return false; + } + $atomstructure['creation_time_unix'] = DateMac2Unix($atomstructure['creation_time']); + $atomstructure['modify_time_unix'] = DateMac2Unix($atomstructure['modify_time']); + $ThisFileInfo['quicktime']['time_scale'] = $atomstructure['time_scale']; + $ThisFileInfo['playtime_seconds'] = $atomstructure['duration'] / $atomstructure['time_scale']; + break; + + + case 'tkhd': // TracK HeaDer atom + $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1)); + $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3)); + $atomstructure['creation_time'] = BigEndian2Int(substr($atomdata, 4, 4)); + $atomstructure['modify_time'] = BigEndian2Int(substr($atomdata, 8, 4)); + $atomstructure['trackid'] = BigEndian2Int(substr($atomdata, 12, 4)); + $atomstructure['reserved1'] = BigEndian2Int(substr($atomdata, 16, 4)); + $atomstructure['duration'] = BigEndian2Int(substr($atomdata, 20, 4)); + $atomstructure['reserved2'] = BigEndian2Int(substr($atomdata, 24, 8)); + $atomstructure['layer'] = BigEndian2Int(substr($atomdata, 32, 2)); + $atomstructure['alternate_group'] = BigEndian2Int(substr($atomdata, 34, 2)); + $atomstructure['volume'] = FixedPoint8_8(substr($atomdata, 36, 2)); + $atomstructure['reserved3'] = BigEndian2Int(substr($atomdata, 38, 2)); + $atomstructure['matrix_a'] = FixedPoint16_16(substr($atomdata, 40, 4)); + $atomstructure['matrix_b'] = FixedPoint16_16(substr($atomdata, 44, 4)); + $atomstructure['matrix_u'] = FixedPoint16_16(substr($atomdata, 48, 4)); + $atomstructure['matrix_c'] = FixedPoint16_16(substr($atomdata, 52, 4)); + $atomstructure['matrix_v'] = FixedPoint16_16(substr($atomdata, 56, 4)); + $atomstructure['matrix_d'] = FixedPoint16_16(substr($atomdata, 60, 4)); + $atomstructure['matrix_x'] = FixedPoint2_30(substr($atomdata, 64, 4)); + $atomstructure['matrix_y'] = FixedPoint2_30(substr($atomdata, 68, 4)); + $atomstructure['matrix_w'] = FixedPoint2_30(substr($atomdata, 72, 4)); + $atomstructure['width'] = FixedPoint16_16(substr($atomdata, 76, 4)); + $atomstructure['height'] = FixedPoint16_16(substr($atomdata, 80, 4)); + + $atomstructure['flags']['enabled'] = (bool) ($atomstructure['flags_raw'] & 0x0001); + $atomstructure['flags']['in_movie'] = (bool) ($atomstructure['flags_raw'] & 0x0002); + $atomstructure['flags']['in_preview'] = (bool) ($atomstructure['flags_raw'] & 0x0004); + $atomstructure['flags']['in_poster'] = (bool) ($atomstructure['flags_raw'] & 0x0008); + $atomstructure['creation_time_unix'] = DateMac2Unix($atomstructure['creation_time']); + $atomstructure['modify_time_unix'] = DateMac2Unix($atomstructure['modify_time']); + + if (!isset($ThisFileInfo['video']['resolution_x']) || !isset($ThisFileInfo['video']['resolution_y'])) { + $ThisFileInfo['video']['resolution_x'] = $atomstructure['width']; + $ThisFileInfo['video']['resolution_y'] = $atomstructure['height']; + } + $ThisFileInfo['video']['resolution_x'] = max($ThisFileInfo['video']['resolution_x'], $atomstructure['width']); + $ThisFileInfo['video']['resolution_y'] = max($ThisFileInfo['video']['resolution_y'], $atomstructure['height']); + if (!empty($ThisFileInfo['video']['resolution_x']) && !empty($ThisFileInfo['video']['resolution_y'])) { + $ThisFileInfo['quicktime']['video']['resolution_x'] = $ThisFileInfo['video']['resolution_x']; + $ThisFileInfo['quicktime']['video']['resolution_y'] = $ThisFileInfo['video']['resolution_y']; + } else { + unset($ThisFileInfo['video']['resolution_x']); + unset($ThisFileInfo['video']['resolution_y']); + unset($ThisFileInfo['quicktime']['video']); + } + break; + + + case 'mdat': // Media DATa atom + case 'free': // FREE space atom + case 'skip': // SKIP atom + case 'wide': // 64-bit expansion placeholder atom + // 'mdat' data is too big to deal with, contains no useful metadata + // 'free', 'skip' and 'wide' are just padding, contains no useful data at all + + // When writing QuickTime files, it is sometimes necessary to update an atom's size. + // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom + // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime + // puts an 8-byte placeholder atom before any atoms it may have to update the size of. + // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the + // placeholder atom can be overwritten to obtain the necessary 8 extra bytes. + // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ). + break; + + + default: + $ThisFileInfo['warning'] .= "\n".'Unknown QuickTime atom type: "'.$atomname.'" at offset '.$baseoffset; + $atomstructure['data'] = $atomdata; + break; + } + array_pop($atomHierarchy); + return $atomstructure; +} + +function QuicktimeParseContainerAtom($atomdata, &$ThisFileInfo, $baseoffset, &$atomHierarchy) { + $atomstructure = false; + $subatomoffset = 0; + $subatomcounter = 0; + if ((strlen($atomdata) == 4) && (BigEndian2Int($atomdata) == 0x00000000)) { + return false; + } + while ($subatomoffset < strlen($atomdata)) { + $subatomsize = BigEndian2Int(substr($atomdata, $subatomoffset + 0, 4)); + $subatomname = substr($atomdata, $subatomoffset + 4, 4); + $subatomdata = substr($atomdata, $subatomoffset + 8, $subatomsize - 8); + if ($subatomsize == 0) { + // Furthermore, for historical reasons the list of atoms is optionally + // terminated by a 32-bit integer set to 0. If you are writing a program + // to read user data atoms, you should allow for the terminating 0. + return $atomstructure; + } + + $atomstructure[$subatomcounter] = QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $ThisFileInfo, $baseoffset + $subatomoffset, $atomHierarchy); + + $subatomoffset += $subatomsize; + $subatomcounter++; + } + return $atomstructure; +} + + +function QuicktimeLanguageLookup($languageid) { + static $QuicktimeLanguageLookup = array(); + if (empty($QuicktimeLanguageLookup)) { + $QuicktimeLanguageLookup[0] = 'English'; + $QuicktimeLanguageLookup[1] = 'French'; + $QuicktimeLanguageLookup[2] = 'German'; + $QuicktimeLanguageLookup[3] = 'Italian'; + $QuicktimeLanguageLookup[4] = 'Dutch'; + $QuicktimeLanguageLookup[5] = 'Swedish'; + $QuicktimeLanguageLookup[6] = 'Spanish'; + $QuicktimeLanguageLookup[7] = 'Danish'; + $QuicktimeLanguageLookup[8] = 'Portuguese'; + $QuicktimeLanguageLookup[9] = 'Norwegian'; + $QuicktimeLanguageLookup[10] = 'Hebrew'; + $QuicktimeLanguageLookup[11] = 'Japanese'; + $QuicktimeLanguageLookup[12] = 'Arabic'; + $QuicktimeLanguageLookup[13] = 'Finnish'; + $QuicktimeLanguageLookup[14] = 'Greek'; + $QuicktimeLanguageLookup[15] = 'Icelandic'; + $QuicktimeLanguageLookup[16] = 'Maltese'; + $QuicktimeLanguageLookup[17] = 'Turkish'; + $QuicktimeLanguageLookup[18] = 'Croatian'; + $QuicktimeLanguageLookup[19] = 'Chinese (Traditional)'; + $QuicktimeLanguageLookup[20] = 'Urdu'; + $QuicktimeLanguageLookup[21] = 'Hindi'; + $QuicktimeLanguageLookup[22] = 'Thai'; + $QuicktimeLanguageLookup[23] = 'Korean'; + $QuicktimeLanguageLookup[24] = 'Lithuanian'; + $QuicktimeLanguageLookup[25] = 'Polish'; + $QuicktimeLanguageLookup[26] = 'Hungarian'; + $QuicktimeLanguageLookup[27] = 'Estonian'; + $QuicktimeLanguageLookup[28] = 'Lettish'; + $QuicktimeLanguageLookup[28] = 'Latvian'; + $QuicktimeLanguageLookup[29] = 'Saamisk'; + $QuicktimeLanguageLookup[29] = 'Lappish'; + $QuicktimeLanguageLookup[30] = 'Faeroese'; + $QuicktimeLanguageLookup[31] = 'Farsi'; + $QuicktimeLanguageLookup[31] = 'Persian'; + $QuicktimeLanguageLookup[32] = 'Russian'; + $QuicktimeLanguageLookup[33] = 'Chinese (Simplified)'; + $QuicktimeLanguageLookup[34] = 'Flemish'; + $QuicktimeLanguageLookup[35] = 'Irish'; + $QuicktimeLanguageLookup[36] = 'Albanian'; + $QuicktimeLanguageLookup[37] = 'Romanian'; + $QuicktimeLanguageLookup[38] = 'Czech'; + $QuicktimeLanguageLookup[39] = 'Slovak'; + $QuicktimeLanguageLookup[40] = 'Slovenian'; + $QuicktimeLanguageLookup[41] = 'Yiddish'; + $QuicktimeLanguageLookup[42] = 'Serbian'; + $QuicktimeLanguageLookup[43] = 'Macedonian'; + $QuicktimeLanguageLookup[44] = 'Bulgarian'; + $QuicktimeLanguageLookup[45] = 'Ukrainian'; + $QuicktimeLanguageLookup[46] = 'Byelorussian'; + $QuicktimeLanguageLookup[47] = 'Uzbek'; + $QuicktimeLanguageLookup[48] = 'Kazakh'; + $QuicktimeLanguageLookup[49] = 'Azerbaijani'; + $QuicktimeLanguageLookup[50] = 'AzerbaijanAr'; + $QuicktimeLanguageLookup[51] = 'Armenian'; + $QuicktimeLanguageLookup[52] = 'Georgian'; + $QuicktimeLanguageLookup[53] = 'Moldavian'; + $QuicktimeLanguageLookup[54] = 'Kirghiz'; + $QuicktimeLanguageLookup[55] = 'Tajiki'; + $QuicktimeLanguageLookup[56] = 'Turkmen'; + $QuicktimeLanguageLookup[57] = 'Mongolian'; + $QuicktimeLanguageLookup[58] = 'MongolianCyr'; + $QuicktimeLanguageLookup[59] = 'Pashto'; + $QuicktimeLanguageLookup[60] = 'Kurdish'; + $QuicktimeLanguageLookup[61] = 'Kashmiri'; + $QuicktimeLanguageLookup[62] = 'Sindhi'; + $QuicktimeLanguageLookup[63] = 'Tibetan'; + $QuicktimeLanguageLookup[64] = 'Nepali'; + $QuicktimeLanguageLookup[65] = 'Sanskrit'; + $QuicktimeLanguageLookup[66] = 'Marathi'; + $QuicktimeLanguageLookup[67] = 'Bengali'; + $QuicktimeLanguageLookup[68] = 'Assamese'; + $QuicktimeLanguageLookup[69] = 'Gujarati'; + $QuicktimeLanguageLookup[70] = 'Punjabi'; + $QuicktimeLanguageLookup[71] = 'Oriya'; + $QuicktimeLanguageLookup[72] = 'Malayalam'; + $QuicktimeLanguageLookup[73] = 'Kannada'; + $QuicktimeLanguageLookup[74] = 'Tamil'; + $QuicktimeLanguageLookup[75] = 'Telugu'; + $QuicktimeLanguageLookup[76] = 'Sinhalese'; + $QuicktimeLanguageLookup[77] = 'Burmese'; + $QuicktimeLanguageLookup[78] = 'Khmer'; + $QuicktimeLanguageLookup[79] = 'Lao'; + $QuicktimeLanguageLookup[80] = 'Vietnamese'; + $QuicktimeLanguageLookup[81] = 'Indonesian'; + $QuicktimeLanguageLookup[82] = 'Tagalog'; + $QuicktimeLanguageLookup[83] = 'MalayRoman'; + $QuicktimeLanguageLookup[84] = 'MalayArabic'; + $QuicktimeLanguageLookup[85] = 'Amharic'; + $QuicktimeLanguageLookup[86] = 'Tigrinya'; + $QuicktimeLanguageLookup[87] = 'Galla'; + $QuicktimeLanguageLookup[87] = 'Oromo'; + $QuicktimeLanguageLookup[88] = 'Somali'; + $QuicktimeLanguageLookup[89] = 'Swahili'; + $QuicktimeLanguageLookup[90] = 'Ruanda'; + $QuicktimeLanguageLookup[91] = 'Rundi'; + $QuicktimeLanguageLookup[92] = 'Chewa'; + $QuicktimeLanguageLookup[93] = 'Malagasy'; + $QuicktimeLanguageLookup[94] = 'Esperanto'; + $QuicktimeLanguageLookup[128] = 'Welsh'; + $QuicktimeLanguageLookup[129] = 'Basque'; + $QuicktimeLanguageLookup[130] = 'Catalan'; + $QuicktimeLanguageLookup[131] = 'Latin'; + $QuicktimeLanguageLookup[132] = 'Quechua'; + $QuicktimeLanguageLookup[133] = 'Guarani'; + $QuicktimeLanguageLookup[134] = 'Aymara'; + $QuicktimeLanguageLookup[135] = 'Tatar'; + $QuicktimeLanguageLookup[136] = 'Uighur'; + $QuicktimeLanguageLookup[137] = 'Dzongkha'; + $QuicktimeLanguageLookup[138] = 'JavaneseRom'; + } + return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid'); +} + +function QuicktimeVideoCodecLookup($codecid) { + static $QuicktimeVideoCodecLookup = array(); + if (empty($QuicktimeVideoCodecLookup)) { + $QuicktimeVideoCodecLookup['rle '] = 'RLE-Animation'; + $QuicktimeVideoCodecLookup['avr '] = 'AVR-JPEG'; + $QuicktimeVideoCodecLookup['base'] = 'Base'; + $QuicktimeVideoCodecLookup['WRLE'] = 'BMP'; + $QuicktimeVideoCodecLookup['cvid'] = 'Cinepak'; + $QuicktimeVideoCodecLookup['clou'] = 'Cloud'; + $QuicktimeVideoCodecLookup['cmyk'] = 'CMYK'; + $QuicktimeVideoCodecLookup['yuv2'] = 'ComponentVideo'; + $QuicktimeVideoCodecLookup['yuvu'] = 'ComponentVideoSigned'; + $QuicktimeVideoCodecLookup['yuvs'] = 'ComponentVideoUnsigned'; + $QuicktimeVideoCodecLookup['dvc '] = 'DVC-NTSC'; + $QuicktimeVideoCodecLookup['dvcp'] = 'DVC-PAL'; + $QuicktimeVideoCodecLookup['dvpn'] = 'DVCPro-NTSC'; + $QuicktimeVideoCodecLookup['dvpp'] = 'DVCPro-PAL'; + $QuicktimeVideoCodecLookup['fire'] = 'Fire'; + $QuicktimeVideoCodecLookup['flic'] = 'FLC'; + $QuicktimeVideoCodecLookup['b48r'] = '48RGB'; + $QuicktimeVideoCodecLookup['gif '] = 'GIF'; + $QuicktimeVideoCodecLookup['smc '] = 'Graphics'; + $QuicktimeVideoCodecLookup['h261'] = 'H261'; + $QuicktimeVideoCodecLookup['h263'] = 'H263'; + $QuicktimeVideoCodecLookup['IV41'] = 'Indeo4'; + $QuicktimeVideoCodecLookup['jpeg'] = 'JPEG'; + $QuicktimeVideoCodecLookup['PNTG'] = 'MacPaint'; + $QuicktimeVideoCodecLookup['msvc'] = 'Microsoft Video1'; + $QuicktimeVideoCodecLookup['mjpa'] = 'Motion JPEG-A'; + $QuicktimeVideoCodecLookup['mjpb'] = 'Motion JPEG-B'; + $QuicktimeVideoCodecLookup['myuv'] = 'MPEG YUV420'; + $QuicktimeVideoCodecLookup['dmb1'] = 'OpenDML JPEG'; + $QuicktimeVideoCodecLookup['kpcd'] = 'PhotoCD'; + $QuicktimeVideoCodecLookup['8BPS'] = 'Planar RGB'; + $QuicktimeVideoCodecLookup['png '] = 'PNG'; + $QuicktimeVideoCodecLookup['qdrw'] = 'QuickDraw'; + $QuicktimeVideoCodecLookup['qdgx'] = 'QuickDrawGX'; + $QuicktimeVideoCodecLookup['raw '] = 'RAW'; + $QuicktimeVideoCodecLookup['.SGI'] = 'SGI'; + $QuicktimeVideoCodecLookup['b16g'] = '16Gray'; + $QuicktimeVideoCodecLookup['b64a'] = '64ARGB'; + $QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 1'; + $QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 3'; + $QuicktimeVideoCodecLookup['syv9'] = 'Sorenson YUV9'; + $QuicktimeVideoCodecLookup['tga '] = 'Targa'; + $QuicktimeVideoCodecLookup['b32a'] = '32AlphaGray'; + $QuicktimeVideoCodecLookup['tiff'] = 'TIFF'; + $QuicktimeVideoCodecLookup['path'] = 'Vector'; + $QuicktimeVideoCodecLookup['rpza'] = 'Video'; + $QuicktimeVideoCodecLookup['ripl'] = 'WaterRipple'; + $QuicktimeVideoCodecLookup['WRAW'] = 'Windows RAW'; + $QuicktimeVideoCodecLookup['y420'] = 'YUV420'; + } + return (isset($QuicktimeVideoCodecLookup["$codecid"]) ? $QuicktimeVideoCodecLookup["$codecid"] : ''); +} + +function QuicktimeAudioCodecLookup($codecid) { + static $QuicktimeAudioCodecLookup = array(); + if (empty($QuicktimeAudioCodecLookup)) { + $QuicktimeAudioCodecLookup['.mp3'] = 'Fraunhofer MPEG Layer-III alias'; + $QuicktimeAudioCodecLookup['aac '] = 'ISO/IEC 14496-3 AAC'; + $QuicktimeAudioCodecLookup['agsm'] = 'Apple GSM 10:1'; + $QuicktimeAudioCodecLookup['alaw'] = 'A-law 2:1'; + $QuicktimeAudioCodecLookup['conv'] = 'Sample Format'; + $QuicktimeAudioCodecLookup['dvca'] = 'DV'; + $QuicktimeAudioCodecLookup['dvi '] = 'DV 4:1'; + $QuicktimeAudioCodecLookup['eqal'] = 'Frequency Equalizer'; + $QuicktimeAudioCodecLookup['fl32'] = '32-bit Floating Point'; + $QuicktimeAudioCodecLookup['fl64'] = '64-bit Floating Point'; + $QuicktimeAudioCodecLookup['ima4'] = 'Interactive Multimedia Association 4:1'; + $QuicktimeAudioCodecLookup['in24'] = '24-bit Integer'; + $QuicktimeAudioCodecLookup['in32'] = '32-bit Integer'; + $QuicktimeAudioCodecLookup['lpc '] = 'LPC 23:1'; + $QuicktimeAudioCodecLookup['MAC3'] = 'Macintosh Audio Compression/Expansion (MACE) 3:1'; + $QuicktimeAudioCodecLookup['MAC6'] = 'Macintosh Audio Compression/Expansion (MACE) 6:1'; + $QuicktimeAudioCodecLookup['mixb'] = '8-bit Mixer'; + $QuicktimeAudioCodecLookup['mixw'] = '16-bit Mixer'; + $QuicktimeAudioCodecLookup['mp4a'] = 'ISO/IEC 14496-3 AAC'; + $QuicktimeAudioCodecLookup['MS'.chr(0x00).chr(0x02)] = 'Microsoft ADPCM'; + $QuicktimeAudioCodecLookup['MS'.chr(0x00).chr(0x11)] = 'DV IMA'; + $QuicktimeAudioCodecLookup['MS'.chr(0x00).chr(0x55)] = 'Fraunhofer MPEG Layer III'; + $QuicktimeAudioCodecLookup['NONE'] = 'No Encoding'; + $QuicktimeAudioCodecLookup['Qclp'] = 'Qualcomm PureVoice'; + $QuicktimeAudioCodecLookup['QDM2'] = 'QDesign Music 2'; + $QuicktimeAudioCodecLookup['QDMC'] = 'QDesign Music 1'; + $QuicktimeAudioCodecLookup['ratb'] = '8-bit Rate'; + $QuicktimeAudioCodecLookup['ratw'] = '16-bit Rate'; + $QuicktimeAudioCodecLookup['raw '] = 'raw PCM'; + $QuicktimeAudioCodecLookup['sour'] = 'Sound Source'; + $QuicktimeAudioCodecLookup['sowt'] = 'signed/two\'s complement (Little Endian)'; + $QuicktimeAudioCodecLookup['str1'] = 'Iomega MPEG layer II'; + $QuicktimeAudioCodecLookup['str2'] = 'Iomega MPEG *layer II'; + $QuicktimeAudioCodecLookup['str3'] = 'Iomega MPEG **layer II'; + $QuicktimeAudioCodecLookup['str4'] = 'Iomega MPEG ***layer II'; + $QuicktimeAudioCodecLookup['twos'] = 'signed/two\'s complement (Big Endian)'; + $QuicktimeAudioCodecLookup['ulaw'] = 'mu-law 2:1'; + } + return (isset($QuicktimeAudioCodecLookup["$codecid"]) ? $QuicktimeAudioCodecLookup["$codecid"] : ''); +} + +function QuicktimeDCOMLookup($compressionid) { + static $QuicktimeDCOMLookup = array(); + if (empty($QuicktimeDCOMLookup)) { + $QuicktimeDCOMLookup['zlib'] = 'ZLib Deflate'; + $QuicktimeDCOMLookup['adec'] = 'Apple Compression'; + } + return (isset($QuicktimeDCOMLookup["$compressionid"]) ? $QuicktimeDCOMLookup["$compressionid"] : ''); +} + +function QuicktimeColorNameLookup($colordepthid) { + static $QuicktimeColorNameLookup = array(); + if (empty($QuicktimeColorNameLookup)) { + $QuicktimeColorNameLookup[1] = '2-color (monochrome)'; + $QuicktimeColorNameLookup[2] = '4-color'; + $QuicktimeColorNameLookup[4] = '16-color'; + $QuicktimeColorNameLookup[8] = '256-color'; + $QuicktimeColorNameLookup[16] = 'thousands (16-bit color)'; + $QuicktimeColorNameLookup[24] = 'millions (24-bit color)'; + $QuicktimeColorNameLookup[32] = 'millions+ (32-bit color)'; + $QuicktimeColorNameLookup[33] = 'black & white'; + $QuicktimeColorNameLookup[34] = '4-gray'; + $QuicktimeColorNameLookup[36] = '16-gray'; + $QuicktimeColorNameLookup[40] = '256-gray'; + } + return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid'); +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.rar.php b/livesupport/modules/getid3/var/getid3.rar.php new file mode 100644 index 000000000..7c92e9d36 --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.rar.php @@ -0,0 +1,21 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.rar.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function getRARHeaderFilepointer(&$fd, &$ThisFileInfo) { + + $ThisFileInfo['fileformat'] = 'rar'; + + $ThisFileInfo['error'] .= "\n".'RAR parsing not enabled in this version of getID3()'; + return false; + +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.rgad.php b/livesupport/modules/getid3/var/getid3.rgad.php new file mode 100644 index 000000000..07efbfb0e --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.rgad.php @@ -0,0 +1,58 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.rgad.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function RGADnameLookup($namecode) { + static $RGADname = array(); + if (empty($RGADname)) { + $RGADname[0] = 'not set'; + $RGADname[1] = 'Radio Gain Adjustment'; + $RGADname[2] = 'Audiophile Gain Adjustment'; + } + + return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : ''); +} + +function RGADoriginatorLookup($originatorcode) { + static $RGADoriginator = array(); + if (empty($RGADoriginator)) { + $RGADoriginator[0] = 'unspecified'; + $RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer'; + $RGADoriginator[2] = 'set by user'; + $RGADoriginator[3] = 'determined automatically'; + } + + return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : ''); +} + +function RGADadjustmentLookup($rawadjustment, $signbit) { + $adjustment = $rawadjustment / 10; + if ($signbit == 1) { + $adjustment *= -1; + } + return (float) $adjustment; +} + +function RGADgainString($namecode, $originatorcode, $replaygain) { + if ($replaygain < 0) { + $signbit = '1'; + } else { + $signbit = '0'; + } + $storedreplaygain = round($replaygain * 10); + $gainstring = str_pad(decbin($namecode), 3, '0', STR_PAD_LEFT); + $gainstring .= str_pad(decbin($originatorcode), 3, '0', STR_PAD_LEFT); + $gainstring .= $signbit; + $gainstring .= str_pad(decbin(round($replaygain * 10)), 9, '0', STR_PAD_LEFT); + + return $gainstring; +} + +?> \ No newline at end of file diff --git a/livesupport/modules/getid3/var/getid3.vqf.php b/livesupport/modules/getid3/var/getid3.vqf.php new file mode 100644 index 000000000..245e3384b --- /dev/null +++ b/livesupport/modules/getid3/var/getid3.vqf.php @@ -0,0 +1,144 @@ + // +// available at http://getid3.sourceforge.net /// +///////////////////////////////////////////////////////////////// +// // +// getid3.vqf.php - part of getID3() // +// See getid3.readme.txt for more details // +// // +///////////////////////////////////////////////////////////////// + +function getVQFHeaderFilepointer(&$fd, &$ThisFileInfo) { + // based loosely on code from TTwinVQ by Jurgen Faul + // jfaul@gmx.de http://jfaul.de/atl + + $ThisFileInfo['fileformat'] = 'vqf'; + $ThisFileInfo['audio']['dataformat'] = 'vqf'; + $ThisFileInfo['audio']['bitrate_mode'] = 'cbr'; + $HasVQFTags = false; + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + $VQFheaderData = fread($fd, 16); + + $offset = 0; + $ThisFileInfo['vqf']['raw']['header_tag'] = substr($VQFheaderData, $offset, 4); + $offset += 4; + $ThisFileInfo['vqf']['raw']['version'] = substr($VQFheaderData, $offset, 8); + $offset += 8; + $ThisFileInfo['vqf']['raw']['size'] = BigEndian2Int(substr($VQFheaderData, $offset, 4)); + $offset += 4; + + while (ftell($fd) < $ThisFileInfo['avdataend']) { + + $ChunkBaseOffset = ftell($fd); + $chunkoffset = 0; + $ChunkData = fread($fd, 8); + $ChunkName = substr($ChunkData, $chunkoffset, 4); + if ($ChunkName == 'DATA') { + $ThisFileInfo['avdataoffset'] = $ChunkBaseOffset; + break; + } + $chunkoffset += 4; + $ChunkSize = BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); + $chunkoffset += 4; + if ($ChunkSize > ($ThisFileInfo['avdataend'] - ftell($fd))) { + $ThisFileInfo['error'] .= "\n".'Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset; + break; + } + $ChunkData .= fread($fd, $ChunkSize); + + switch ($ChunkName) { + case 'COMM': + $ThisFileInfo['vqf']["$ChunkName"]['channel_mode'] = BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); + $chunkoffset += 4; + $ThisFileInfo['vqf']["$ChunkName"]['bitrate'] = BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); + $chunkoffset += 4; + $ThisFileInfo['vqf']["$ChunkName"]['sample_rate'] = BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); + $chunkoffset += 4; + $ThisFileInfo['vqf']["$ChunkName"]['security_level'] = BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); + $chunkoffset += 4; + + $ThisFileInfo['audio']['channels'] = $ThisFileInfo['vqf']["$ChunkName"]['channel_mode'] + 1; + $ThisFileInfo['audio']['sample_rate'] = VQFchannelFrequencyLookup($ThisFileInfo['vqf']["$ChunkName"]['sample_rate']); + $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['vqf']["$ChunkName"]['bitrate'] * 1000; + + if ($ThisFileInfo['audio']['bitrate'] == 0) { + $ThisFileInfo['error'] .= 'Corrupt VQF file: bitrate_audio == zero'; + return false; + } + break; + + case 'NAME': + case 'AUTH': + case '(c) ': + case 'FILE': + case 'COMT': + case 'ALBM': + $HasVQFTags = true; + $ThisFileInfo['vqf']['comments'][VQFcommentNiceNameLookup($ChunkName)][] = trim(substr($ChunkData, 8)); + break; + + case 'DSIZ': + $ThisFileInfo['vqf']['DSIZ'] = BigEndian2Int(substr($ChunkData, 8, 4)); + break; + + default: + $ThisFileInfo['warning'] .= "\n".'Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset; + break; + } + } + + $ThisFileInfo['playtime_seconds'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['audio']['bitrate']; + + if (isset($ThisFileInfo['vqf']['DSIZ']) && (($ThisFileInfo['vqf']['DSIZ'] != ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] - strlen('DATA'))))) { + switch ($ThisFileInfo['vqf']['DSIZ']) { + case 0: + case 1: + $ThisFileInfo['warning'] .= "\n".'Invalid DSIZ value "'.$ThisFileInfo['vqf']['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($ThisFileInfo['vqf']['DSIZ'] + 1).'.0'; + $ThisFileInfo['audio']['encoder'] = 'Ahead Nero'; + break; + + default: + $ThisFileInfo['warning'] .= "\n".'Probable corrupted file - should be '.$ThisFileInfo['vqf']['DSIZ'].' bytes, actually '.($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] - strlen('DATA')); + break; + } + } + + // Any VQF tags present? + if ($HasVQFTags) { + + // add tag to array of tags + $ThisFileInfo['tags'][] = 'vqf'; + + // Yank other comments - VQF highest preference + CopyFormatCommentsToRootComments($ThisFileInfo['vqf']['comments'], $ThisFileInfo, true, true, true); + } + + return true; +} + +function VQFchannelFrequencyLookup($frequencyid) { + static $VQFchannelFrequencyLookup = array(); + if (empty($VQFchannelFrequencyLookup)) { + $VQFchannelFrequencyLookup[11] = 11025; + $VQFchannelFrequencyLookup[22] = 22050; + $VQFchannelFrequencyLookup[44] = 44100; + } + return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000); +} + +function VQFcommentNiceNameLookup($shortname) { + static $VQFcommentNiceNameLookup = array(); + if (empty($VQFcommentNiceNameLookup)) { + $VQFcommentNiceNameLookup['NAME'] = 'title'; + $VQFcommentNiceNameLookup['AUTH'] = 'artist'; + $VQFcommentNiceNameLookup['(c) '] = 'copyright'; + $VQFcommentNiceNameLookup['FILE'] = 'filename'; + $VQFcommentNiceNameLookup['COMT'] = 'comment'; + $VQFcommentNiceNameLookup['ALBM'] = 'album'; + } + return (isset($VQFcommentNiceNameLookup["$shortname"]) ? $VQFcommentNiceNameLookup["$shortname"] : $shortname); +} + +?> \ No newline at end of file